> ## 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 Network Design

> Purpose, design, and implementation of the Livepeer Network: the off-chain execution layer that turns the protocol's rules into delivered video and AI compute.

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>;
};

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 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 StyledStep = ({title, icon, titleSize = 'h3', iconColor = null, titleColor = null, children, className = '', style = {}, ...rest}) => {
  const styledTitle = titleColor ? <span style={{
    color: titleColor
  }}>{title}</span> : title;
  return <Step title={styledTitle} icon={icon} iconColor={iconColor || undefined} titleSize={titleSize} className={className} style={style} {...rest}>
      {children}
    </Step>;
};

export const StyledSteps = ({children, iconColor, titleColor, lineColor, iconSize = '24px', className = '', style = {}, ...rest}) => {
  const resolvedIconColor = iconColor || 'var(--accent-dark, #18794E)';
  const resolvedTitleColor = titleColor || 'var(--lp-color-accent)';
  const resolvedLineColor = lineColor || 'var(--lp-color-accent)';
  return <div className={['docs-styled-steps', className].filter(Boolean).join(' ')} style={style} {...rest}>
      <style>{`
        .docs-styled-steps .steps > div > div.absolute > div {
          background-color: ${resolvedIconColor};
        }
        .docs-styled-steps .steps > div > div.w-full > p {
          color: ${resolvedTitleColor};
        }
        .docs-styled-steps .steps > div > div.absolute.w-px {
          background-color: ${resolvedLineColor};
        }
        .docs-styled-steps .steps > div:last-child > div.absolute.w-px::after {
          content: '';
          position: absolute;
          bottom: 0;
          left: 50%;
          transform: translateX(-50%);
          width: 6px;
          height: 6px;
          background-color: ${resolvedLineColor};
          transform: translateX(-50%) rotate(45deg);
        }
      `}</style>
      <div>
        <Steps>{children}</Steps>
      </div>
    </div>;
};

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 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 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 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 Subtitle = ({style = {}, text, children, variant = 'default', fontSize = '', fontWeight = '', fontStyle = '', marginTop = '', marginBottom = '', color = '', className = '', ...rest}) => {
  const renderInlineCode = (value, keyPrefix) => {
    return value.split(/(`[^`]+`)/g).map((segment, index) => {
      if (segment.startsWith('`') && segment.endsWith('`')) {
        return <code key={`${keyPrefix}-code-${index}`}>{segment.slice(1, -1)}</code>;
      }
      return segment;
    });
  };
  const renderInlineMarkup = (value, keyPrefix = 'subtitle') => {
    if (typeof value !== 'string') {
      return value;
    }
    return value.split(/(\*\*[\s\S]+?\*\*)/g).map((segment, index) => {
      if (segment.startsWith('**') && segment.endsWith('**')) {
        const inner = segment.slice(2, -2);
        return <strong key={`${keyPrefix}-strong-${index}`}>
            {renderInlineCode(inner, `${keyPrefix}-strong-${index}`)}
          </strong>;
      }
      return renderInlineCode(segment, `${keyPrefix}-${index}`);
    });
  };
  const renderContent = (value, keyPrefix) => {
    if (Array.isArray(value)) {
      return value.map((item, index) => renderContent(item, `${keyPrefix}-${index}`));
    }
    return renderInlineMarkup(value, keyPrefix);
  };
  const variants = {
    default: {
      fontSize: '1rem',
      fontStyle: 'italic',
      color: 'var(--lp-color-accent)',
      marginBottom: 0
    },
    changelog: {
      fontSize: '0.8rem',
      fontStyle: 'normal',
      fontWeight: 700,
      color: 'var(--lp-color-text-primary)',
      marginBottom: 0
    }
  };
  const base = variants[variant] || variants.default;
  return <span className={className} style={{
    ...base,
    ...fontSize ? {
      fontSize
    } : {},
    ...fontWeight ? {
      fontWeight
    } : {},
    ...fontStyle ? {
      fontStyle
    } : {},
    ...marginTop ? {
      marginTop
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...color ? {
      color
    } : {},
    ...style
  }} {...rest}>
      {renderContent(text, 'text')}
      {renderContent(children, 'children')}
    </span>;
};

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 CardTitleTextWithArrow = ({children, className = '', style = {}, ...cardProps}) => {
  return <div className={className} style={{
    display: 'flex',
    width: 'fit-content',
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: '-1rem',
    ...style
  }}>
      <Card arrow={false} title={<span style={{
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center'
  }}>
            {' '}
            {children}{' '}
            <span style={{
    margin: '0 -1rem 0.2rem 0.75rem'
  }}>
              <Icon icon="arrow-up-right" size={16} color="var(--lp-color-text-secondary)" />
            </span>
          </span>} {...cardProps} />
    </div>;
};

<Quote>
  The Network is the **off-chain execution layer** responsible for *running the work*, *routing jobs to the right operators*, and *settling payment* at production volume. The Protocol enforces the rules; the Network does the work.
</Quote>

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

## Network Role

The Network was designed to deliver real-time video and AI compute at production volume on a permissionless, open marketplace.

The Network provides the **off-chain** execution layer for Livepeer with GPU operators accepting jobs, Gateways routing demand, and payments settling continuously off-chain.

The **Livepeer Network** is implemented by nodes running [`go-livepeer`](https://github.com/livepeer/go-livepeer) that accept jobs, perform compute, transcoding and AI inference, exchange off-chain payments, and then settle on-chain.

<Card title={<CustomCardTitle icon="cubes" title="Network Implementation, Actors & Node Mechanisms" />} arrow href="/v2/about/network/actors" />

## Network Design Principles

The 2017 whitepaper specified core design principles for the Livepeer video broadcasting network:

<StyledSteps iconColor="var(--accent)" titleColor="var(--accent)">
  <StyledStep title="Protocol Boundary" icon="scale-balanced">
    The chain enforces; the Network executes. The Protocol records stake, settles winning tickets, distributes inflation. The Network handles every job that does not touch the chain. The split is what lets execution change quickly while the rules stay slow.
  </StyledStep>

  <StyledStep title="Permissionless Participation" icon="door-open">
    Anyone with compatible hardware can register an Orchestrator and start receiving jobs. Anyone can run a Gateway and route demand. No application process, no vendor relationship, no gatekeeper. Capacity grows whenever a new operator joins.
  </StyledStep>

  <StyledStep title="Off-Chain Settlement" icon="bolt">
    Jobs are paid through probabilistic micropayment tickets exchanged off-chain. Only winning tickets touch the chain. This is what makes per-pixel and per-token pricing economical at production volume; on-chain settlement per job would cost more than the work itself.
  </StyledStep>

  <StyledStep title="Workload-Agnostic Runtime" icon="cubes">
    The same `go-livepeer` binary runs video transcoding, batch AI inference, and real-time live video-to-video. New capabilities ship as new pipelines, not as forks or hard upgrades. The Network expands by capability, not by replacement.
  </StyledStep>

  <StyledStep title="Open Coordination" icon="signal-stream">
    Discovery, capability advertisement, and price are all public. Gateways query Orchestrators directly; Orchestrators publish what they can do and what they charge. Price competition is visible. The marketplace is a marketplace, not a queue.
  </StyledStep>

  <StyledStep title="Stake-Anchored Trust" icon="shield-halved">
    Orchestrators bond LPT to participate. Their stake is the economic exposure that backs their work; misbehaviour or downtime costs them. The Network is trustworthy without a central operator because stake makes it costly to behave otherwise.
  </StyledStep>

  <StyledStep title="Anchor in the Protocol" icon="link">
    Every off-chain interaction resolves against on-chain truth: stake on `BondingManager`, deposits on `TicketBroker`, capabilities advertised through `ServiceRegistry`. The off-chain layer scales freely; the on-chain layer settles authoritatively.
  </StyledStep>
</StyledSteps>

## Design Decisions

The Network's design reflects deliberate choices made to preserve the seven properties at scale.

* **Single binary, multiple modes**: `go-livepeer` runs as Gateway, Orchestrator, or worker. One codebase, one upgrade path. A new operator does not pick between products; they pick a mode.
* **Probabilistic Micropayments off-chain**: Tickets accumulate off-chain; only winning tickets are submitted to the on-chain `TicketBroker`. Per-pixel video and per-token AI become economical because on-chain settlement per job would exceed the price of the work.
* **Posted prices, not auctions**: Orchestrators publish a price-per-unit; Gateways accept or reject. No bidding round. The market runs continuously; price competition is visible; Gateways route work without per-job coordination.
* **Stake gates the Active Set**: Bonded LPT determines which Orchestrators are eligible for video work each round. The reliability of the Network is anchored in the economic exposure of its operators.
* **Pipelines, not protocol upgrades**: New AI capabilities ship as new pipelines an Orchestrator chooses to run. Adding capacity for a new workload does not require a hard fork or a governance vote.

<Tip>
  Slashing exists in the Protocol but is currently dormant: the on-chain Verifier role is set to `0x0`. Honest work is enforced today through stake exposure, fast verification, and marketplace selection, not active on-chain slashing.
</Tip>

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

## Network Evolution

<FrameQuote author="Livepeer Whitepaper (2017)" href="/v2/about/resources/knowledge-hub/livepeer-whitepaper">
  The Livepeer Protocol described an **open, decentralised network** for live video transmission, where **transcoding capacity is provided by node operators in exchange for fees**, and where the system can scale to meet demand without requiring permission from any central authority.
</FrameQuote>

The design principles and mechanisms outlined in the whitepaper have been preserved and expanded upon in the real-world implementation of the Livepeer Network, which has evolved to meet the demands of production workloads while adhering to the core tenets of decentralisation, permissionless participation, and economic security.

The Network's design continues to reflect the original vision of an open, decentralised marketplace for video and AI compute, while incorporating new features and optimisations that have emerged through real-world usage and community feedback over time.

<ScrollableDiagram title="Livepeer Network Evolution" maxHeight="600px">
  ```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
  %%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1a1a1a', 'primaryTextColor': '#E0E4E0', 'primaryBorderColor': '#2b9a66', 'lineColor': '#2b9a66', 'secondaryColor': '#0d0d0d', 'tertiaryColor': '#1a1a1a', 'background': '#0d0d0d', 'fontFamily': "Inter, 'Inter Fallback', -apple-system, system-ui" }}}%%
  flowchart LR
      classDef old fill:#1a1a1a,color:#E0E4E0,stroke:#71717a,stroke-width:2px
      classDef new fill:#1a1a1a,color:#E0E4E0,stroke:#2b9a66,stroke-width:2px

      subgraph Designed["Whitepaper (2017)"]
          D1["Single Transcoder actor<br/>(25-node cap)"]:::old
          D2["Per-segment on-chain escrow"]:::old
          D3["Truebit-style verification"]:::old
          D4["Swarm/PPSPP relay distribution"]:::old
          D5["Ethereum mainnet"]:::old
          D6["Off-chain LIP polls<br/>(non-binding)"]:::old
          D7["Video transcoding only"]:::old
          D8["Implicit pricing<br/>(no marketplace spec)"]:::old
      end

      subgraph Running["2026 Network"]
          R1["Orchestrator + Transcoder<br/>(100-node active set)"]:::new
          R2["Probabilistic micropayment tickets<br/>(off-chain, on-chain redemption)"]:::new
          R3["Fast verification<br/>(MPEG-7 perceptual hash)<br/>Verifier role 0x0 - dormant"]:::new
          R4["Direct HTTP, trickle, external CDNs"]:::new
          R5["Arbitrum One"]:::new
          R6["On-chain Governor + Treasury<br/>(inflation-funded public goods)"]:::new
          R7["Video + AI Worker<br/>(transcoding, inference, real-time AI)"]:::new
          R8["Posted-price marketplace<br/>ServiceRegistry capability ads<br/>performance-based selection"]:::new
      end

      D1 -.->|Streamflow LIP-30 - 2020| R1
      D2 -.->|Streamflow PM tickets - 2020| R2
      D3 -.->|fast-verify - slashing dormant| R3
      D4 -.->|simplified| R4
      D5 -.->|Confluence LIP-80 - 2022| R5
      D6 -.->|Delta LIP-91 - 2023| R6
      D7 -.->|Cascade LIP-100 - 2025| R7
      D8 -.->|emergent| R8
  ```
</ScrollableDiagram>

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

## Network Participants

<DynamicTableV2
  headerList={['Actor', 'What they run', 'What they take on', 'What they earn']}
  itemsList={[
{
  Actor: <Subtitle variant="changelog">**Orchestrator**</Subtitle>,
  'What they run': '`go-livepeer` in Orchestrator mode plus attached transcoders and AI workers',
  'What they take on': 'GPU hardware, bonded LPT, operational uptime',
  'What they earn': 'ETH fees from jobs, LPT inflation rewards each round',
},
{
  Actor: <Subtitle variant="changelog">**Gateway**</Subtitle>,
  'What they run': '`go-livepeer` in Gateway mode, optionally with redeemer and remote signer',
  'What they take on': 'ETH deposit and reserve, routing infrastructure, client-facing service',
  'What they earn': 'Margin between price paid to Orchestrators and price charged to clients',
},
{
  Actor: <Subtitle variant="changelog">**Delegator**</Subtitle>,
  'What they run': 'No node. Bonds LPT to one Orchestrator through the Explorer',
  'What they take on': "Capital exposure to LPT and to the chosen Orchestrator's performance",
  'What they earn': "Share of the Orchestrator's ETH fees and LPT inflation, by stake share",
},
{
  Actor: <Subtitle variant="changelog">**Client**</Subtitle>,
  'What they run': 'An application that calls a Gateway API or SDK',
  'What they take on': 'No network role. Pays for jobs through a Gateway.',
  'What they earn': 'The transcoded video or AI output the job produced',
},
]}
/>

## Related Pages

<Columns cols={2}>
  <Card title={<CustomCardTitle icon="cube" title="Protocol Design" />} href="/v2/about/protocol/design" horizontal arrow>
    The on-chain layer that anchors the Network.
  </Card>

  <Card title={<CustomCardTitle icon="diagram-project" title="Infrastructure Stack" />} href="/v2/about/concepts/livepeer-stack" horizontal arrow>
    The four-layer Livepeer stack.
  </Card>

  <Card title={<CustomCardTitle icon="users" title="Actors and Capabilities" />} href="/v2/about/concepts/actors-and-capabilities" horizontal arrow>
    Who participates and why.
  </Card>

  <Card title={<CustomCardTitle icon="people-group" title="Participation and SPEs" />} href="/v2/about/network/participation" horizontal arrow>
    How to extend the Network beyond running a node.
  </Card>
</Columns>
