Satori

repository·main·Indexed 12 days ago

https://github.com/vercel/satori

A library to convert HTML and CSS into SVG using JSX syntax, commonly used for generating dynamic social cards and Open Graph images. It utilizes the Yoga layout engine (Flexbox) and supports a subset of HTML elements and CSS properties, including CSS variables and transforms. Satori handles layout calculation, font management, and typography automatically, supporting TTF, OTF, and WOFF formats.

Tokens
9.5K
Snippets
30
Records
35
Agent score
95%

What's inside Satori

  1. Overview of Satori

    main
    Satori is a library designed to convert HTML and CSS into SVG. It uses JSX syntax to define the layout and styles, making it straightforward to generate SVGs that match browser-based HTML/CSS rendering. It handles complex tasks like layout calculation, font management, and typography automatically.
  2. Supported HTML Elements and Images

    main

    Satori supports a limited subset of HTML elements. It does not support <input>, <style> tags, or external resources via <link> or <script>.

    Images

    You can use <img> to embed images. It is highly recommended to provide width and height attributes.

    For better performance when rendering to other image formats (like PNG), use base64 encoded data, an ArrayBuffer, or a Buffer for the src prop to avoid extra I/O during Satori's execution.

    await satori(
      <img src="https://picsum.photos/200/300" width={200} height={300} />,
      options
    )
    
    // Using base64 for better performance:
    await satori(
      <img src="data:image/png;base64,..." width={200} height={300} />,
      options
    )
  3. Setup Satori Standalone Build

    main

    In environments with limited WASM loading (like Cloudflare Workers), use the satori/standalone build. You must manually load the yoga.wasm binary and initialize Satori using init() before calling satori().

    import satori, { init } from 'satori/standalone'
    
    const res = await fetch('https://unpkg.com/satori/yoga.wasm')
    const yogaWasm = await res.arrayBuffer()
    
    await init(yogaWasm)
    
    // Now you can use satori as usual
    const svg = await satori(...)
  4. Convert JSX to SVG with satori()

    main

    To generate an SVG, import satori and call it with a JSX element and an options object. The options object must include width, height, and a fonts array.

    Each font object in the fonts array requires:

    • name: The font name.
    • data: The font data as a Buffer or ArrayBuffer (retrieved via fs in Node.js or fetch in other environments).
    • weight: The font weight (e.g., 400).
    • style: The font style (e.g., 'normal').

    The function returns an SVG string.

    import satori from 'satori'
    
    const svg = await satori(
      <div style={{ color: 'black' }}>hello, world</div
      ,
      {
        width: 600,
        height: 400,
        fonts: [
          {
            name: 'Roboto',
            // Use `fs` (Node.js only) or `fetch` to read the font as Buffer/ArrayBuffer and provide `data` here.
            data: robotoArrayBuffer,
            weight: 400,
            style: 'normal',
          },
        ],
      },
    )
  5. Use JSX with Satori

    main

    Satori accepts JSX elements that are pure and stateless. Note that React APIs like useState, useEffect, and dangerouslySetInnerHTML are not supported.

    Experimental: Built-in JSX support

    You can use Satori's experimental JSX runtime without installing React by using @jsxImportSource pragmas. This allows you to use Satori's own JSX implementation.

    Use without JSX

    If you do not have a JSX transpiler, you can pass React-element-like objects directly. These objects must include type, props.children, and props.style.

    /** @jsxRuntime automatic */
    /** @jsxImportSource satori/jsx */
    
    import satori from 'satori';
    import { FC, JSXNode } from 'satori/jsx';
    
    const MyComponent: FC<{ children: JSXNode }> = ({ children }) => (
      <div style={{ color: 'black' }}>{children}</div>
    )
    
    const svg = await satori(
      <MyComponent>hello, world</MyComponent>,
      options,
    )
    
    // OR without JSX:
    await satori(
      {
        type: 'div',
        props: {
          children: 'hello, world',
          style: { color: 'black' },
        },
      },
      options
    )
  6. Configure JSX for Satori using @jsxImportSource

    main

    To use JSX with Satori, you must tell your compiler (like TypeScript or Babel) to use Satori's JSX runtime. You can do this by adding the @jsxImportSource pragma directive at the top of your files containing JSX.

    Note: Satori does not support class components; only functional components are supported.

    /** @jsxImportSource satori/jsx */
    
    function MyComponent() {
      return <div style={{ color: 'red' }}>Hello Satori</div>;
    }
  7. Dynamically Load Emojis and Fonts

    main

    Use the loadAdditionalAsset callback to fetch missing assets (fonts or emojis) on the fly. The callback receives a code (e.g., 'emoji', a language code, or 'unknown') and the segment of text being rendered.

    await satori(
      <div>👋 你好</div>,
      {
        loadAdditionalAsset: async (code: string, segment: string) => {
          if (code === 'emoji') {
            return `data:image/svg+xml;base64,...`
          }
          return loadFontFromSystem(code)
        }
      }
    )
  8. Configure Fonts and Typography

    main

    Satori supports TTF, OTF, and WOFF formats (WOFF2 is not currently supported). You must provide font data as an ArrayBuffer (browser) or Buffer (Node.js).

    Multiple fonts can be passed in the fonts array and referenced via fontFamily in your styles.

    await satori(
      <div style={{ fontFamily: 'Inter' }}>Hello</div>,
      {
        width: 600,
        height: 400,
        fonts: [
          {
            name: 'Inter',
            data: inter,
            weight: 400,
            style: 'normal',
          },
          {
            name: 'Inter',
            data: interBold,
            weight: 700,
            style: 'normal',
          },
        ],
      }
    )
  9. Render Emojis and Locales

    main

    Emojis

    Use the graphemeImages option to map specific emojis (graphemes) to image sources. The image will be resized to match the current font size as a square.

    Locales

    Specify the language via the lang attribute on elements to ensure correct rendering for specific locales.

    await satori(
      <div style={{ fontFamily: 'Inter' }}>Next.js is 🤯!</div>,
      {
        graphemeImages: {
          '🤯': 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f92f.svg',
        },
      }
    )
    
    // Using lang attribute for locales:
    await satori(
      <div lang="ja-JP">骨</div>
    )
  10. Configure Font Embedding and Precision

    main

    Font Embedding

    By default, Satori renders text as <path> elements in the SVG to embed font data directly. To use standard <text> elements instead, set embedFont: false.

    Pixel Grid Rounding

    Use pointScaleFactor to control how layout values are rounded to the pixel grid. This improves rendering precision on high-DPI displays.

    Debugging

    Pass debug: true to draw bounding boxes around elements for layout debugging.

    const svg = await satori(
      <div style={{ color: 'black' }}>hello, world</div>,
      {
        embedFont: false,
        pointScaleFactor: 2,
        debug: true,
      },
    )
  11. Configure fonts with FontOptions

    main

    When loading fonts into Satori via the FontLoader, you must provide an array of FontOptions objects. Each object specifies the raw font data and its metadata to ensure correct rendering and fallback behavior.

    Key properties:

    • data: The raw font file as a Buffer or ArrayBuffer.
    • name: The font family name (e.g., 'sans-serif').
    • weight: The numeric weight (e.g., 400, 700) or a WeightName ('normal', 'bold').
    • style: The font style ('normal' or 'italic').
    • lang: An optional locale string (e.g., 'ja') to associate the font with a specific language. If not set, it defaults to an internal unknown suffix.
    const fontOptions: FontOptions[] = [
      {
        name: 'Inter',
        data: fontBuffer,
        weight: 400,
        style: 'normal'
      },
      {
        name: 'Inter',
        data: boldFontBuffer,
        weight: 700,
        style: 'normal'
      }
    ];
  12. CSS Support and Layout Engine

    main

    Satori uses the Yoga layout engine (Flexbox) and is not a complete CSS implementation.

    Key Limitations:

    • No z-index support (elements later in the document are painted on top).
    • No calc() support.
    • currentColor is only supported for the color property.
    • Three-dimensional transforms are not supported.
    • No support for advanced typography (kerning, ligatures) or RTL languages.

    Supported Features:

    • CSS Variables: Supported via --var-name and var(--var-name) with fallbacks.
    • Layout: display (flex, contents, none), position (relative, static, absolute), flexDirection, flexWrap, alignItems, justifyContent, gap, etc.
    • Box Model: margin, padding, width, height, min/max sizes (except min-content, max-content, fit-content), border, borderRadius, boxSizing, boxShadow.
    • Text: fontFamily, fontSize, fontWeight, textAlign, textDecoration, lineHeight, letterSpacing, whiteSpace, wordBreak, textWrap (wrap, balance).
    • Background: backgroundColor, backgroundImage (gradients and url), backgroundSize, backgroundRepeat.
    • Transforms: translate, rotate, scale, skew.
    • Other: opacity, filter, clipPath, objectFit, objectPosition, overflow (visible, hidden).