> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Livepeer: Open AI-Infrastructure for Real-Time Interactive Media

> Livepeer is a full-stack permissionless infrastructure substrate and decentralised marketplace for real-time media & AI pipelines. The network is defined by the off-chain actors that perform the compute work for video & AI jobs and the protocol that coordinates and governs them.

export const ScrollableDiagram = ({children, title = '', maxHeight = '500px', minWidth = '100%', showControls = false, className = '', style = {}, ...rest}) => {
  const buildDiagramKey = (currentTitle = '', currentClassName = '') => {
    const source = `${currentTitle}|${currentClassName}|scrollable-diagram`;
    let hash = 0;
    for (let index = 0; index < source.length; index += 1) {
      hash = hash * 31 + source.charCodeAt(index) >>> 0;
    }
    return `docs-diagram-${hash.toString(36)}`;
  };
  const diagramKey = buildDiagramKey(title, className);
  const zoomName = `${diagramKey}-zoom`;
  const zoomLevels = [{
    label: '75%',
    value: 0.75
  }, {
    label: '100%',
    value: 1
  }, {
    label: '125%',
    value: 1.25
  }, {
    label: '150%',
    value: 1.5
  }];
  const containerStyle = {
    overflow: 'auto',
    maxHeight,
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    background: 'var(--lp-color-bg-card)',
    position: 'relative'
  };
  return <div className={className} style={{
    position: 'relative',
    marginBottom: "var(--lp-spacing-4)",
    ...style
  }} {...rest}>
      {title && <p style={{
    textAlign: 'center',
    fontStyle: 'italic',
    color: 'var(--lp-color-text-secondary)',
    marginBottom: "var(--lp-spacing-2)",
    fontSize: '0.875rem'
  }}>
          {title}
        </p>}

      {showControls ? <style>{`
          [data-docs-diagram-key="${diagramKey}"] [data-docs-diagram-content] {
            transform: scale(1);
            transform-origin: top left;
            width: max-content;
          }
          ${zoomLevels.map(zoomLevel => `
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-shell] [data-docs-diagram-content] {
            transform: scale(${zoomLevel.value});
          }
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-controls] label[for="${diagramKey}-${zoomLevel.label.replace('%', '')}"] {
            background: var(--lp-color-accent);
            color: var(--lp-color-on-accent);
            border-color: var(--lp-color-accent);
          }`).join('\n')}
        `}</style> : null}

      {showControls ? zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <input key={inputId} id={inputId} type="radio" name={zoomName} defaultChecked={zoomLevel.value === 1} style={{
      position: 'absolute',
      opacity: 0,
      pointerEvents: 'none'
    }} />;
  }) : null}

      <div data-docs-diagram-key={diagramKey} data-docs-diagram-shell style={containerStyle}>
        <div data-docs-diagram-content style={{
    minWidth,
    transformOrigin: 'top left',
    width: 'max-content'
  }}>
          {children}
        </div>
      </div>

      {showControls ? <div data-docs-diagram-controls style={{
    display: 'flex',
    justifyContent: 'flex-end',
    alignItems: 'center',
    gap: "var(--lp-spacing-2)",
    marginTop: "var(--lp-spacing-2)",
    flexWrap: 'wrap'
  }}>
          <span style={{
    fontSize: "0.75rem",
    color: 'var(--lp-color-text-muted)',
    marginRight: 'auto'
  }}>
            Scroll to pan
          </span>
          {zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <label key={inputId} htmlFor={inputId} style={{
      background: 'transparent',
      color: 'var(--lp-color-text-secondary)',
      border: '1px solid var(--lp-color-border-default)',
      borderRadius: "4px",
      padding: '4px 10px',
      cursor: 'pointer',
      fontSize: "0.75rem",
      fontWeight: '600'
    }}>
                {zoomLevel.label}
              </label>;
  })}
        </div> : null}
    </div>;
};

export const Image = ({src, alt = "", caption, icon, hint, fullwidth = true, className = "", style = {}, ...rest}) => {
  icon = icon ? icon : "arrow-turn-down-right";
  return <Frame caption={caption} hint={hint} className={className} style={style} {...rest}>
      <img src={src} alt={alt} style={{
    width: fullwidth ? "100%" : undefined
  }} />
    </Frame>;
};

export const FrameQuote = ({children, author, source, href, frame = true, align = 'right', borderColor, img, spacing = true, className = "", style = {}, ...props}) => {
  const alignmentMap = {
    left: 'flex-start',
    center: 'center',
    right: 'flex-end'
  };
  const content = <blockquote style={{
    display: 'flex',
    flexDirection: 'column',
    padding: '0.75rem 1rem 0.25rem 1rem',
    gap: "var(--lp-spacing-1)",
    margin: 0
  }}>
      <div style={{
    borderLeft: `4px solid var(--lp-color-accent)`,
    paddingLeft: "var(--lp-spacing-4)",
    fontStyle: 'italic'
  }}>
        {children}
      </div>
      {(author || source) && <div style={{
    display: 'flex',
    justifyContent: alignmentMap[align] || 'flex-end',
    marginLeft: align === 'left' ? "var(--lp-spacing-6)" : 0
  }}>
          <div style={{
    textAlign: align === 'center' ? 'center' : 'left'
  }}>
            {author && <div>
                {spacing && <br />}
                <Icon icon="microphone" />{' '}
                <strong>
                  <em>{author}</em>
                </strong>
              </div>}
            {source && (href ? <a href={href} target="_blank" rel="noopener noreferrer">
                  <span style={{
    opacity: 0.7,
    fontStyle: 'italic',
    borderBottom: '1px solid var(--lp-color-accent)',
    fontSize: "1rem"
  }}>
                    {source}
                  </span>{' '}
                  <Icon icon="arrow-up-right" size={12} color="var(--lp-color-accent)" />
                </a> : <span style={{
    opacity: 0.7,
    fontStyle: 'italic',
    fontSize: "1rem"
  }}>
                  {source}
                </span>)}
          </div>
        </div>}
    </blockquote>;
  return frame ? <div className={className} style={{
    border: borderColor ? `1px solid ${borderColor}` : 'none',
    borderRadius: "8px",
    overflow: 'hidden',
    ...style
  }} {...props}>
      <Frame style={{
    border: 'none'
  }}>
        {img && <img src={img.src} alt={img.alt} />}
        {content}
      </Frame>
    </div> : content;
};

export const Quote = ({children, className = "", style = {}, ...rest}) => {
  const quoteStyle = {
    fontSize: "1rem",
    textAlign: 'center',
    opacity: 1,
    fontStyle: 'italic',
    color: 'var(--lp-color-accent)',
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    margin: '1rem 0',
    ...style
  };
  return <blockquote className={className} style={quoteStyle} {...rest}>{children}</blockquote>;
};

export const YouTubeVideo = ({embedUrl, url, title = "", author = "", hint = "", caption, className = "", style = {}, ...rest}) => {
  const toEmbedUrl = value => {
    if (!value || typeof value !== "string") return "";
    const source = value.trim();
    if (!source) return "";
    try {
      const parsed = new URL(source);
      const host = parsed.hostname.replace(/^www\./, "");
      if (host === "youtube.com" || host === "youtube-nocookie.com") {
        if (parsed.pathname.startsWith("/embed/")) return source;
        const videoId = parsed.pathname.startsWith("/shorts/") ? parsed.pathname.split("/").filter(Boolean)[1] : parsed.searchParams.get("v");
        if (!videoId) return "";
        const params = new URLSearchParams(parsed.search);
        params.delete("v");
        const query = params.toString();
        return `https://www.youtube.com/embed/${videoId}${query ? `?${query}` : ""}`;
      }
      if (host === "youtu.be") {
        const videoId = parsed.pathname.split("/").filter(Boolean)[0];
        if (!videoId) return "";
        const query = parsed.searchParams.toString();
        return `https://www.youtube.com/embed/${videoId}${query ? `?${query}` : ""}`;
      }
    } catch (_err) {
      return "";
    }
    return "";
  };
  const resolvedEmbedUrl = toEmbedUrl(embedUrl || url);
  if (!resolvedEmbedUrl) {
    return null;
  }
  const isValidYouTubeUrl = resolvedEmbedUrl.includes("youtube.com/embed/");
  if (!isValidYouTubeUrl) {
    console.warn("Invalid YouTube embed URL:", embedUrl || url);
    return null;
  }
  const buildCaption = () => {
    if (caption) return caption;
    if (!author && !title) return null;
    return <span style={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      textAlign: "center",
      lineHeight: 1.2
    }}>
        <span>
          {author && <>
              <Icon icon="microphone" size={16} /> <strong>{author}</strong>
            </>}
          {author && title ? `${" "} • ${title}` : title}
        </span>
      </span>;
  };
  const captionContent = buildCaption();
  return <Frame className={className} style={style} {...hint ? {
    hint
  } : {}} {...captionContent ? {
    caption: captionContent
  } : {}} {...rest}>
      <iframe className="w-full aspect-video rounded-xl" src={resolvedEmbedUrl} title={title || author || "YouTube Video"} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />
    </Frame>;
};

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const BorderedBox = ({children, variant = "default", padding = "var(--lp-spacing-4)", borderRadius = "var(--lp-spacing-px-8)", margin = "", accentBar = "", style = {}, className = "", ...rest}) => {
  const variants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    accent: {
      border: "1px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    muted: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "transparent"
    }
  };
  const accentBarColors = {
    accent: "var(--lp-color-accent)",
    positive: "var(--green-9)"
  };
  return <div data-docs-bordered-box="" data-accent-bar={accentBarColors[accentBar] ? "" : undefined} className={className} style={{
    ...variants[variant],
    padding: padding,
    borderRadius: borderRadius,
    ...margin ? {
      margin
    } : {},
    ...accentBarColors[accentBar] ? {
      position: "relative",
      '--accent-bar-color': accentBarColors[accentBar]
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const CustomCardTitle = ({icon, title, variant = "card", iconSize, style = {}, className = "", ...rest}) => {
  const variants = {
    card: {
      display: 'flex',
      alignItems: 'center',
      gap: "var(--lp-spacing-2)",
      marginBottom: "var(--lp-spacing-3)",
      color: 'var(--lp-color-text-primary)',
      fontSize: '1rem',
      fontWeight: 600
    },
    accordion: {
      display: 'inline-flex',
      alignItems: 'center',
      gap: "var(--lp-spacing-2)"
    },
    tab: {
      display: 'inline-flex',
      alignItems: 'center',
      gap: '0.4rem',
      fontSize: '0.875rem'
    }
  };
  const sizes = {
    card: 20,
    accordion: 18,
    tab: 14
  };
  const size = iconSize || sizes[variant] || 20;
  const baseStyle = variants[variant] || variants.card;
  return variant === 'card' ? <div className={className} style={{
    ...baseStyle,
    ...style
  }} {...rest}>
      {typeof icon === 'string' ? <Icon icon={icon} size={size} color="var(--lp-color-accent)" /> : icon}
      {title}
    </div> : <span className={className} style={{
    ...baseStyle,
    ...style
  }} {...rest}>
      {typeof icon === 'string' ? <Icon icon={icon} size={size} color="var(--lp-color-accent)" /> : icon}
      {title}
    </span>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

export const DynamicTableV2 = ({tableTitle = null, headerList = [], itemsList = [], monospaceColumns = [], columnWidths = {}, columnConfig = {}, showSeparators = false, margin, className = '', style = {}, ...rest}) => {
  if (!headerList.length) {
    return <div>No headers provided</div>;
  }
  const tableRef = useRef(null);
  const [measuredColumnWidths, setMeasuredColumnWidths] = useState({});
  const measureFitColumns = () => {
    const tableElement = tableRef.current;
    if (!tableElement) {
      return;
    }
    const nextWidths = headerList.reduce((accumulator, header, index) => {
      const config = columnConfig?.[header] || ({});
      if (!config.fitContent) {
        return accumulator;
      }
      const contentNodes = tableElement.querySelectorAll(`[data-docs-column-key="${index}"] [data-docs-fit-content]`);
      let maxContentWidth = 0;
      contentNodes.forEach(node => {
        const width = Math.ceil(node.getBoundingClientRect().width);
        if (width > maxContentWidth) {
          maxContentWidth = width;
        }
      });
      if (maxContentWidth > 0) {
        accumulator[header] = `${maxContentWidth + 16}px`;
      }
      return accumulator;
    }, {});
    setMeasuredColumnWidths(currentWidths => {
      const currentEntries = Object.entries(currentWidths);
      const nextEntries = Object.entries(nextWidths);
      if (currentEntries.length === nextEntries.length && nextEntries.every(([header, width]) => currentWidths[header] === width)) {
        return currentWidths;
      }
      return nextWidths;
    });
  };
  useLayoutEffect(() => {
    measureFitColumns();
  }, [headerList, itemsList, columnConfig]);
  useEffect(() => {
    const tableElement = tableRef.current;
    if (!tableElement || typeof ResizeObserver === 'undefined') {
      return undefined;
    }
    const resizeObserver = new ResizeObserver(() => {
      measureFitColumns();
    });
    resizeObserver.observe(tableElement);
    if (tableElement.parentElement) {
      resizeObserver.observe(tableElement.parentElement);
    }
    return () => {
      resizeObserver.disconnect();
    };
  }, [headerList, itemsList, columnConfig]);
  const fitHeaders = headerList.filter(header => columnConfig?.[header]?.fitContent);
  const hasMeasuredFitColumns = fitHeaders.length === 0 || fitHeaders.every(header => Boolean(measuredColumnWidths[header]));
  const getColumnStyle = (header, isMonospace = false) => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const nowrap = Boolean(config.nowrap) || fitContent || isMonospace;
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    return {
      ...fitContent && measuredWidth ? {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      } : {},
      ...!fitContent && !fluid && preferredWidth ? {
        minWidth: preferredWidth
      } : {},
      ...nowrap ? {
        whiteSpace: 'nowrap'
      } : {
        wordWrap: 'break-word',
        overflowWrap: 'break-word'
      }
    };
  };
  const getColumnTrackStyle = header => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    if (fitContent && measuredWidth) {
      return {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      };
    }
    if (fluid) {
      return {};
    }
    if (preferredWidth) {
      return {
        width: preferredWidth
      };
    }
    return {};
  };
  const renderCellContent = (header, content) => {
    const config = columnConfig?.[header] || ({});
    if (!config.fitContent) {
      return content;
    }
    return <div data-docs-fit-content style={{
      display: 'inline-flex',
      alignItems: 'center',
      whiteSpace: 'nowrap',
      width: 'max-content',
      maxWidth: 'none'
    }}>
        {content}
      </div>;
  };
  return <div className={className} style={style} {...rest}>
      {tableTitle && <div style={{
    fontStyle: 'italic',
    margin: 0
  }}>
          <strong>{tableTitle}</strong>
        </div>}
      <div style={{
    overflowX: 'auto',
    ...margin != null && ({
      margin
    })
  }} role="region" tabIndex={0} aria-label={tableTitle ? `Scrollable table: ${tableTitle}` : 'Scrollable table'}>
        <table ref={tableRef} data-docs-dynamic-table-v2 style={{
    width: '100%',
    tableLayout: hasMeasuredFitColumns ? 'fixed' : 'auto',
    borderCollapse: 'collapse',
    fontSize: '0.9rem',
    marginTop: 0
  }}>
          <colgroup>
            {headerList.map((header, index) => <col key={index} style={getColumnTrackStyle(header)} />)}
          </colgroup>
          <thead>
            <tr style={{
    backgroundColor: 'var(--lp-color-accent)',
    color: 'var(--lp-color-on-accent)',
    borderBottom: '1px solid var(--lp-color-border-default)'
  }}>
              {headerList.map((header, index) => <th key={index} data-docs-column-key={index} style={{
    padding: '10px 8px',
    textAlign: 'left',
    fontWeight: '600',
    color: 'var(--lp-color-on-accent)',
    verticalAlign: 'top',
    ...getColumnStyle(header)
  }}>
                  {renderCellContent(header, header)}
                </th>)}
            </tr>
          </thead>
          <tbody>
            {itemsList.filter(item => showSeparators || !item?.__separator).map((item, rowIndex) => item?.__separator ? <tr key={rowIndex} style={{
    backgroundColor: 'var(--lp-color-accent)',
    color: 'var(--lp-color-on-accent)',
    borderBottom: '1px solid var(--lp-color-accent)'
  }}>
                    <td colSpan={headerList.length} style={{
    padding: '6px 8px',
    fontWeight: '700',
    color: 'var(--lp-color-on-accent)',
    letterSpacing: '0.01em'
  }}>
                      {(item[headerList[0]] ?? item.Category) ?? 'Category'}
                    </td>
                  </tr> : <tr key={rowIndex} style={{
    borderBottom: '1px solid var(--lp-color-border-default)'
  }}>
                    {headerList.map((header, colIndex) => {
    const value = (item[header] ?? item[header.toLowerCase()]) ?? '-';
    const isMonospace = monospaceColumns.includes(colIndex);
    return <td key={colIndex} data-docs-column-key={colIndex} style={{
      padding: '8px 8px',
      fontFamily: isMonospace ? 'monospace' : 'inherit',
      verticalAlign: 'top',
      ...getColumnStyle(header, isMonospace)
    }}>
                          {renderCellContent(header, isMonospace ? <code>{value}</code> : value)}
                        </td>;
  })}
                  </tr>)}
          </tbody>
        </table>
      </div>
    </div>;
};

export const QuadGrid = ({children, icon = "arrows-spin", iconSize = 50, iconColor = "var(--lp-color-accent)", iconBackgroundColor = "transparent", gap, spinDuration = "10s", className = "", style = {}, ...rest}) => {
  if (children == null) {
    console.warn("[QuadGrid] Missing children");
    return null;
  }
  return <div className={className} style={{
    position: "relative",
    ...style
  }} {...rest}>
      <style>{`
        @keyframes quadGridSpin {
          from { transform: rotate(0deg); }
          to { transform: rotate(360deg); }
        }
        .lp-quad-grid-layout {
          display: grid;
          grid-template-columns: repeat(2, minmax(0, 1fr));
          grid-auto-rows: 1fr;
          gap: var(--lp-quad-grid-gap, 0);
        }
        @media (max-width: 768px) {
          .lp-quad-grid-layout {
            grid-template-columns: 1fr;
          }
        }
        @media (prefers-reduced-motion: reduce) {
          .lp-quad-grid-icon {
            animation: none !important;
          }
        }
      `}</style>
      <div className="lp-quad-grid-layout" style={{
    "--lp-quad-grid-gap": gap
  }}>
        {children}
      </div>
      <div style={{
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 10
  }}>
        <div className="lp-quad-grid-icon" style={{
    backgroundColor: iconBackgroundColor,
    borderRadius: "50%",
    padding: "var(--lp-spacing-2)",
    animation: `quadGridSpin ${spinDuration} linear infinite`
  }}>
          <Icon icon={icon} size={iconSize} color={iconColor} />
        </div>
      </div>
    </div>;
};

<YouTubeVideo url="https://www.youtube.com/watch?v=U6YRg7hHorM" caption="Tom Trowbridge talks to Doug Petkanics, CEO and Founder at Livepeer" />

<Accordion title="Summary: Decentralizing Video Streaming for the Future of AI" icon="video">
  **Key themes**

  * **DePIN overview:** Blockchain networks coordinate idle physical resources for open global access.
  * **Livepeer focus:** Livepeer offers video infrastructure at 10x lower cost than centralised providers.
  * **Market stats:** Video streaming is a \$250 billion market; Livepeer handles 3 million+ video minutes weekly.
  * **Token model:** Staking yields about 40% annual returns; inflationary rewards foster competition.
  * **AI expansion:** Plans to add generative AI workloads could increase usage 10x to 100x.
  * **Market efficiency:** Millions of idle GPUs enable efficient decentralised resource use.

  **DePIN definition and market context** *(00:00)*

  DePIN networks coordinate idle physical resources globally using blockchain incentives, enabling open infrastructure.

  They combine advanced hardware, software, and token economics for crowdsourced capacity monetisation.

  **Livepeer product strategy and market differentiation** *(04:22)*

  Livepeer aims to be the leading open video infrastructure, backed by nearly eight years of development.

  * Offers up to 10x cost savings and better scalability than centralised clouds.
  * Targets the \$250 billion video market through decentralised networks and developer-friendly SaaS APIs.
  * Processes over 3 million unique video minutes weekly, gaining industry credibility.

  **Token economics and network incentives** *(15:35)*

  Livepeer's work token model incentivizes GPU operators to stake and earn fees plus inflationary rewards.

  * Stakers earn about 40% annual returns; the protocol targets 50% token staking to maintain network health.
  * Inflation adjusts dynamically to encourage optimal staking levels.
  * Inflationary rewards enable lower prices than traditional clouds, fostering competition.

  **AI and generative video expansion** *(22:33)*

  Livepeer plans to support generative AI video workloads, which are highly compute-intensive.

  * AI integration could increase network usage 10x to 100x.
  * NVIDIA's rapid data centre growth highlights huge compute demand and chip shortages.

  **Supply-side dynamics and market efficiency** *(28:18)*

  Livepeer benefits from millions of idle video encoding GPUs, offering near-infinite supply.

  * Large cloud providers' reserved capacity often sits idle and can be monetised through DePIN networks.
  * Crypto-settled, open access payments enable efficient, global resource monetisation.

  **Founding insights and industry vision** *(31:30 onward)*

  Key lessons: work with great people and maintain a motivating mission to endure market cycles.

  * Mission focus helps navigate pivots and maintain relevance amid trends like generative AI.
  * DePIN can enable open, decentralised AI infrastructure to counter big tech and regulatory dominance.
  * Decentralised AI models promote trust and transparency versus opaque corporate AI systems.
</Accordion>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## About Livepeer

Projects like Livepeer are also known as <LinkArrow label="DePIN" href="https://review.stanfordblockchain.xyz/p/32-depin-decentralized-physical-infrastructure" newline={false} />  (Decentralised Physical Infrastructure Network) projects - blockchain networks that coordinate idle physical resources for open global access. They combine advanced hardware, software, and token economics to enable crowdsourced capacity monetisation.

<Tip>
  Livepeer was one of the earliest [DePIN](https://review.stanfordblockchain.xyz/p/32-depin-decentralized-physical-infrastructure) (Decentralised Physical Infrastructure Network) projects in the blockchain space - recognising the clear business and technical advantages of decentralised networks for resilience, scalability, and cost efficiency as well as for incentivising innovation, participation and network growth.
</Tip>

Open-participation, distributed infrastructure systems like Livepeer aren’t just software systems - they’re multi-layered digital ecosystems that require careful design of economic incentives, governance structures, and technical architecture and that provide unique value propositions that centrally operated systems cannot match, such as censorship resistance, economic security, and trustless coordination.

<Accordion title="The Case for Decentralisation" icon="network-wired">
  <p>Livepeer has both a decentralised network architecture and a decentralised governance model.</p>
  <p>The network is designed to be open and permissionless, allowing anyone to participate as a node operator or token holder.</p>

  The protocol is governed by token holders through on-chain voting, ensuring that the community has a say in the direction of the project.

  Technical Decentralisation Benefits:

  * **Resilience**: A distributed network of nodes is more resistant to failures, attacks, and censorship than a centralised system.
  * **Global Access**: By enabling anyone to participate as a node operator, Livepeer can tap into underutilized resources worldwide, increasing capacity and reducing costs.
  * **Open Innovation**: An open, decentralised ecosystem encourages innovation from a diverse set of contributors, leading to more robust and feature-rich infrastructure.
  * **Economic Alignment**: Cryptoeconomic incentives can align the interests of various stakeholders (operators

  A worldwide network of incentivised stakeholders provides critical benefits for achieving Livepeer's mission:

  For Developers:

  * Competitive improvements driven by self-interest rather than corporate roadmap
  * No gatekeeping on contributions and innovations
  * Freedom to fork and experiment

  For Infrastructure Operators:

  * Level playing field without platform risk from central authority
  * Economic confidence that rules won't arbitrarily change
  * Empowerment to participate in building the network

  For Token Participants:

  * Transparent incentive mechanisms
  * Clear process for proposing and voting on protocol updates
  * Predictable economics and future direction
</Accordion>

<Accordion icon="rocket" title="Crypto-Primitive Advantages">
  Decentralisation and cryptoeconomic design add specific properties that a centrally operated cloud cannot provide:

  * **Dynamic scaling and resilience** -- no single point of failure; capacity is contributed by independent operators globally
  * **Global payment rails** -- accessible by AI agents and automated systems without bank accounts or API contracts
  * **Permissionless participation** -- anyone with compatible hardware can join the network; innovation is not gated by a vendor relationship
  * **Fairer creator economics** -- transparent, auditable revenue streams with no hidden intermediary margin
  * **Lower latency via data locality** -- data stays closer to the user when operators are geographically distributed
  * **Lower costs without lock-in** -- no vendor margin on compute; switching is possible at the protocol level
  * **Self-sustaining incentives** -- inflation-based rewards and fee capture provide a runway to self-sustaining infrastructure without requiring venture capital to subsidise operations
  * **Network effects** -- as more operators join, capacity, resilience, and geographic coverage increase for all participants
</Accordion>

## Protocol Evolution

Livepeer’s [original whitepaper](https://github.com/livepeer/wiki/blob/master/WHITEPAPER.md) (2017) outlined an ambitious system design **protocol** for the fully decentralised live video streaming **network** - aiming to provide ***“the world’s open video infrastructure”***

It defined how the multiple actors in a live streaming ecosystem participate in a secure and economically rational way, including the economic incentives for encouraging participation in the network.

<CenteredContainer>
  <Card title={<div className="lp-title-accent-tight"><Icon icon="scroll" size={22} color="var(--accent)" /> {" "}Livepeer Whitepaper</div>} href="/v2/about/resources/knowledge-hub/livepeer-whitepaper" arrow cta="Read the full Livepeer Whitepaper" />
</CenteredContainer>

While ***the Livepeer Protocol and Network have evolved significantly since the original whitepaper***, the core design principles and economic incentives outlined in that document remain foundational to how the system operates today.

<ScrollableDiagram title="Livepeer Protocol Evolution" maxHeight="700px" maxWidth="100%" showControls={true}>
  ```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
  %%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#18794E', 'primaryTextColor': '#fff', 'primaryBorderColor': '#3CB540', 'lineColor': '#3CB540', 'mainBkg': '#18794E', 'nodeBorder': '#3CB540', 'clusterBkg': 'transparent', 'clusterBorder': '#3CB540', 'titleColor': '#3CB540', 'edgeLabelBackground': 'transparent', 'textColor': '#3CB540', 'nodeTextColor': '#fff'}}}%%
  flowchart TB
  subgraph v4["V4 Characteristics"]
      v4a["AI Inference<br/>Workloads"]
      v4b["Real-time Video<br/>Pipelines"]
      v4c["AI-aware<br/>Gateways"]
  end

  subgraph v3["V3 Characteristics"]
      v3a["Arbitrum One<br/>Deployment"]
      v3b["L1-L2 Bridge<br/>Contracts"]
      v3c["Reduced Gas<br/>Costs"]
  end

  subgraph v2["V2 Characteristics"]
      v2a["Off-chain Job<br/>Negotiation"]
      v2b["Probabilistic<br/>Micropayments"]
      v2c["Fault-based<br/>Verification"]
      v2d["Orchestrator/<br/>Transcoder Split"]
  end

  subgraph v1["V1 Characteristics"]
      v1a["On-chain Job<br/>Assignment"]
      v1b["On-chain Payments<br/>Per Job"]
      v1c["Routine Truebit<br/>Verification"]
      v1d["Unified Transcoder<br/>Role"]
  end

  v1Start["V1: Whitepaper<br/>April 2017"]
  v2Start["V2: Streamflow<br/>December 2018"]
  v3Start["V3: Confluence<br/>2022"]
  v4Start["V4: Cascade<br/>2024"]

  v1Start -->|"scalability upgrades"| v2Start
  v2Start -->|"L2 migration"| v3Start
  v3Start -->|"AI workload expansion"| v4Start

  v1Start -.-> v1a
  v1Start -.-> v1b
  v1Start -.-> v1c
  v1Start -.-> v1d

  v2Start -.-> v2a
  v2Start -.-> v2b
  v2Start -.-> v2c
  v2Start -.-> v2d

  v3Start -.-> v3a
  v3Start -.-> v3b
  v3Start -.-> v3c

  v4Start -.-> v4a
  v4Start -.-> v4b
  v4Start -.-> v4c

  classDef version fill:#18794E,stroke:#3CB540,color:#ffffff,stroke-width:2px
  classDef characteristic fill:#ffffff,stroke:#3CB540,color:#18794E,stroke-width:1px
  classDef group fill:#0B1F17,stroke:#3CB540,color:#3CB540,stroke-width:1px

  class v1Start,v2Start,v3Start,v4Start version
  class v1a,v1b,v1c,v1d,v2a,v2b,v2c,v2d,v3a,v3b,v3c,v4a,v4b,v4c characteristic
  class v1,v2,v3,v4 group
  ```
</ScrollableDiagram>

<Accordion title="Protocol Principles" icon="cubes">
  ## Protocol Principles

  The protocol aims to deliver **open AI and video infrastructure** at efficient pricing and infinite scale by harnessing:

  1. **Open source software** - Development contributed by global community
  2. **Open market for resources** - Underutilized compute and bandwidth from worldwide operators
  3. **Cryptoeconomic incentives** - Token-based participation rewards distributed to many parties

  <ScrollableDiagram title="Livepeer Mission, Stakeholders, and Outcomes" maxHeight="650px" maxWidth="100%" showControls={true}>
    ```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    %%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#18794E', 'primaryTextColor': '#fff', 'primaryBorderColor': '#3CB540', 'lineColor': '#3CB540', 'mainBkg': '#18794E', 'nodeBorder': '#3CB540', 'clusterBkg': 'transparent', 'clusterBorder': '#3CB540', 'titleColor': '#3CB540', 'edgeLabelBackground': 'transparent', 'textColor': '#3CB540', 'nodeTextColor': '#fff'}}}%%
    flowchart TB
    mission["Mission:<br/>Build World's Open<br/>Video Infrastructure"]

    subgraph enabling["Enabling Factors"]
        oss["Open Source Software<br/>Global developer<br/>contributions"]
        market["Open Resource Market<br/>Compute + Bandwidth"]
        incentives["Cryptoeconomic Incentives<br/>LPT token economics"]
    end

    subgraph stakeholders["Stakeholder Groups"]
        developers["Developers<br/>Protocol & Application"]
        operators["Infrastructure Operators<br/>Orchestrators/Transcoders"]
        participants["Network Participants<br/>Delegators/Token Holders"]
    end

    subgraph outcomes["Outcomes"]
        pricing["Efficient Pricing"]
        scale["Infinite Scale"]
        publicGood["Public Good<br/>Base Layer Protocol"]
    end

    mission --> oss
    mission --> market
    mission --> incentives

    oss --> developers
    market --> operators
    incentives --> participants

    developers --> pricing
    operators --> scale
    participants --> publicGood

    pricing --> mission
    scale --> mission
    publicGood --> mission
    market --> scale
    incentives --> publicGood

    classDef mission fill:#18794E,stroke:#3CB540,color:#ffffff,stroke-width:2px
    classDef node fill:#ffffff,stroke:#3CB540,color:#18794E,stroke-width:1px
    classDef group fill:#0B1F17,stroke:#3CB540,color:#3CB540,stroke-width:1px

    class mission mission
    class oss,market,incentives,developers,operators,participants,pricing,scale,publicGood node
    class enabling,stakeholders,outcomes group
    ```
  </ScrollableDiagram>
</Accordion>

<Accordion title="Protocol Evolution: From Whitepaper to Cascade" icon="arrows-spin">
  The whitepaper provides a detailed technical blueprint for the protocol's architecture, token economics, and security model, which continue to guide development and inform the community's understanding of the network's mechanics.

  <Image src="https://raw.githubusercontent.com/livepeer/docs/docs-v2-assets/snippets/assets/domain/00_HOME/evolution.png" alt="Evolution of Livepeer" caption="Evolution of the Livepeer Network" href="/v2/home/about/roadmap" arrow />

  <Update label="Whitepaper" description="April 2017" tags={["V1", "Original Design"]}>
    * Original design with on-chain job assignment, routine verification, and a unified transcoder role.
    * Gas constraints capped the Active Set at roughly 10-15 transcoders.
  </Update>

  <Update label="Streamflow" description="December 2018" tags={["V2", "Scalability & Micropayments"]}>
    * Off-chain job negotiation and Probabilistic Micropayments cut transaction overhead by orders of magnitude.
    * The Orchestrator and transcoder roles split, allowing one Orchestrator to coordinate many transcoder workers.
  </Update>

  <Update label="Confluence" description="2022" tags={["V3", "Arbitrum L2"]}>
    * Core protocol contracts migrated from Ethereum mainnet to Arbitrum One.
    * The migration reduced gas costs roughly 100x while inheriting Ethereum security through the rollup.
  </Update>

  <Update label="Cascade" description="2024" tags={["V4", "AI Workloads"]}>
    * The network expanded beyond video transcoding to real-time AI video pipelines.
    * Gateways became AI-aware, routing inference jobs and coordinating multi-step pipelines alongside existing transcoding workloads.
    * The protocol's stake, payment, and verification primitives stayed the same; the workload surface changed.
  </Update>

  <QuadGrid icon="arrows-spin" iconSize={50}>
    <DisplayCard title="Real-time Performance" icon="bolt">
      Industry-standard low latency optimised for real-time video AI and media, enabling sub-second inference and proven scalability.
    </DisplayCard>

    <DisplayCard title="Cost Efficiency" icon="piggy-bank">
      Access to GPU compute at 5–10x lower cost through an open marketplace with transparent on-chain economics and a pay-per-use model.
    </DisplayCard>

    <DisplayCard title="Automagic Scalability" icon="arrows-maximize">
      Scale capacity up or down dynamically in real-time via an elastic network supply, smart routing, and incentivised idle GPU utilisation.
    </DisplayCard>

    <DisplayCard title="Openness & Community" icon="people-group">
      Permissionless, open-source, community-driven infrastructure that provides global access, on-chain verifiable compute, and rewards all participants.
    </DisplayCard>
  </QuadGrid>

  ## Key Changes by Version

  <DynamicTableV2
    headerList={['Aspect', 'V1: Whitepaper', 'V2: Streamflow', 'V3: Confluence', 'V4: Cascade']}
    itemsList={[
    {
    Aspect: 'Workloads',
    'V1: Whitepaper': 'Video transcoding',
    'V2: Streamflow': 'Video transcoding',
    'V3: Confluence': 'Video transcoding',
    'V4: Cascade': 'Transcoding + real-time AI',
    },
    {
    Aspect: 'Job Assignment',
    'V1: Whitepaper': 'On-chain stake-based',
    'V2: Streamflow': 'Off-chain negotiation',
    'V3: Confluence': 'Off-chain negotiation',
    'V4: Cascade': 'Off-chain, AI-aware routing',
    },
    {
    Aspect: 'Payments',
    'V1: Whitepaper': 'On-chain per job',
    'V2: Streamflow': 'Probabilistic micropayments',
    'V3: Confluence': 'Probabilistic micropayments',
    'V4: Cascade': 'Probabilistic micropayments',
    },
    {
    Aspect: 'Verification',
    'V1: Whitepaper': 'Routine (1/1000 segments)',
    'V2: Streamflow': 'Fault-based challenges',
    'V3: Confluence': 'Fault-based challenges',
    'V4: Cascade': 'Fault-based challenges',
    },
    {
    Aspect: 'Node Roles',
    'V1: Whitepaper': 'Unified Transcoder',
    'V2: Streamflow': 'Orchestrator + Transcoder',
    'V3: Confluence': 'Orchestrator + Transcoder',
    'V4: Cascade': 'Orchestrator + Transcoder + AI worker',
    },
    {
    Aspect: 'Active Nodes',
    'V1: Whitepaper': '10-15 transcoders',
    'V2: Streamflow': 'Hundreds of orchestrators',
    'V3: Confluence': 'Hundreds of orchestrators',
    'V4: Cascade': 'Hundreds of orchestrators',
    },
    {
    Aspect: 'Blockchain',
    'V1: Whitepaper': 'Ethereum mainnet',
    'V2: Streamflow': 'Ethereum mainnet',
    'V3: Confluence': 'Arbitrum One',
    'V4: Cascade': 'Arbitrum One',
    },
    {
    Aspect: 'Transaction Cost',
    'V1: Whitepaper': 'High',
    'V2: Streamflow': 'Medium',
    'V3: Confluence': 'Low',
    'V4: Cascade': 'Low',
    },
]}
  />
</Accordion>

## Livepeer Protocol and Network

<Tip> The **Livepeer Protocol** and **Livepeer Network** are distinct but complementary components of the Livepeer ecosystem. </Tip>

The on-chain **Livepeer Protocol** governs the off-chain **Livepeer Network** participants who perform the work.

<CenteredContainer>
  <DynamicTableV2
    headerList={['Layer', 'Description', 'Technicals']}
    itemsList={[
    {
    Layer: <strong>Livepeer Protocol</strong>,
    Description: 'On-chain crypto-economic incentives & coordination; staking; payments.',
    Technicals : 'Smart contracts on Arbitrum (originally Ethereum mainnet) handling staking, delegation, the Active Set, round transitions, reward minting, ticket redemption, and slashing.',
    },
    {
    Layer: <strong>Livepeer Network</strong>,
    Description: 'Off-chain nodes performing real-time work (transcoding, inference, routing).',
    Technicals : 'Orchestrators running GPU nodes that perform transcoding and AI inference work, and Gateways that route jobs to Orchestrators and handle payments.',
    }
]}
  />
</CenteredContainer>

### Livepeer Protocol

<Quote>
  The Livepeer Protocol is the **on-chain coordination, security and economic layer** responsible for *governing the network*, *securing the system*, and *incentivising desired behaviour* from participants.
</Quote>

The **Livepeer Protocol** consists of a set of smart contracts encoded in [Solidity](https://soliditylang.org/) and deployed on the [Arbitrum One](https://arbitrum.io/) blockchain (with the token deployed on Ethereum mainnet), which enforce the rules of the network, coordinate participant behaviour, and provide economic incentives to secure the system and align it with desired outcomes.

<Accordion icon="cubes" title="Protocol Functions">
  The Livepeer Protocol contracts govern:

  * LivepeerToken (LPT) ownership and delegation
  * Staking and selection of active transcoder operators (Orchestrators)
  * Distribution of inflationary rewards and fees to participants
  * Time-based progression of the protocol through rounds
  * Payment processing through a probabilistic micropayment system

  Protocol services include:

  * staking
  * delegation
  * inflation & rewards
  * Orchestrator selection
  * slashing
  * probabilistic payments
  * verification rules

  This makes up the economic and coordination layer that incentivises and enforces desired behaviour.
</Accordion>

**Protocol Pages**

<Columns cols={2} gap="2rem" className="lp-columns-spaced">
  <Card href="/v2/about/protocol/design" title={<CustomCardTitle icon="cubes" title="Protocol Design" />} horizontal arrow> A deep dive on the design of the Livepeer Protocol and its mechanisms </Card>
  <Card href="/v2/about/protocol/blockchain-contracts" title={<CustomCardTitle icon="code" title="Blockchain Contracts" />} horizontal arrow> A detailed breakdown of the protocol's smart contract architecture. </Card>
</Columns>

<CustomDivider style={{ margin: "-1rem 0 -2rem 0" }} />

### Livepeer Network

<Quote>
  The Livepeer Network is the **off-chain execution layer** of the Livepeer ecosystem - the mesh of hardware and software nodes performing work.
</Quote>

The **Livepeer Network** consists of Orchestrators running GPU nodes that perform transcoding and AI inference work, and Gateways that route jobs to Orchestrators and handle payments and which operates according to the rules defined by the protocol.

The Livepeer Network is implemented by <LinkArrow label="go-livepeer" href="https://github.com/livepeer/go-livepeer" newline={false} />

<Accordion icon="network-wired" title="Network Services">
  Network services include:

  * Job routing
  * Verification
  * Payment
  * AI inference
  * Video Transcoding
  * Real-time AI Video Streaming
</Accordion>

**Network Pages**

<Columns cols={2} gap="2rem" className="lp-columns-spaced">
  <Card href="/v2/about/network/actors" title={<CustomCardTitle icon="circle-nodes" title="Network Actors" />} horizontal arrow> A detailed overview of the core actors and participants enabling the Livepeer Network. </Card>
  <Card href="/v2/about/network/marketplace" title={<CustomCardTitle icon="play" title="Livepeer Marketplace" />} horizontal arrow> How the Livepeer Network functions as a service marketplace to facilitates the exchange of compute resources. </Card>
</Columns>
