├── .eslintrc.json
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── config.yml
│ └── feature_request.md
├── card.png
└── workflows
│ ├── ci.yml
│ └── pr.yml
├── .gitignore
├── .husky
└── pre-commit
├── .npmrc
├── .prettierignore
├── .prettierrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── package.json
├── playground
├── LICENSE
├── cards
│ ├── playground-data.ts
│ └── preview-tabs.ts
├── components
│ ├── introduction.module.css
│ ├── introduction.tsx
│ ├── panel-resize-handle.module.css
│ ├── panel-resize-handle.tsx
│ └── resvg_worker.ts
├── decs.d.ts
├── index.d.ts
├── next-env.d.ts
├── package.json
├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── api
│ │ └── font.ts
│ └── index.tsx
├── public
│ ├── favicon.ico
│ ├── iaw-mono-var.woff2
│ ├── inter-latin-ext-400-normal.woff
│ ├── inter-latin-ext-700-normal.woff
│ ├── material-icons-base-400-normal.woff
│ └── og.png
├── styles.css
├── tsconfig.json
└── utils
│ ├── font.ts
│ └── twemoji.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── release.config.cjs
├── src
├── builder
│ ├── background-image.ts
│ ├── border-radius.ts
│ ├── border.ts
│ ├── clip-path.ts
│ ├── content-mask.ts
│ ├── gradient
│ │ ├── linear.ts
│ │ ├── radial.ts
│ │ └── utils.ts
│ ├── mask-image.ts
│ ├── overflow.ts
│ ├── rect.ts
│ ├── shadow.ts
│ ├── svg.ts
│ ├── text-decoration.ts
│ ├── text.ts
│ └── transform.ts
├── font.ts
├── handler
│ ├── compute.ts
│ ├── expand.ts
│ ├── image.ts
│ ├── inheritable.ts
│ ├── preprocess.ts
│ ├── presets.ts
│ └── tailwind.ts
├── index.ts
├── language.ts
├── layout.ts
├── parser
│ ├── mask.ts
│ └── shape.ts
├── satori.ts
├── text
│ ├── characters.ts
│ ├── index.ts
│ ├── measurer.ts
│ └── processor.ts
├── transform-origin.ts
├── types.d.ts
├── utils.ts
├── vendor
│ ├── parse-css-dimension
│ │ ├── LICENSE
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src.js
│ └── twrnc
│ │ ├── deprecate.js
│ │ ├── log.js
│ │ └── picocolors.js
└── yoga
│ ├── index.ts
│ ├── yoga-prebuilt.ts
│ └── yoga-prebuilt.wasm.ts
├── test
├── __image_snapshots__
│ ├── background-clip-test-tsx-test-background-clip-test-tsx-background-clip-should-render-background-clip-text-1-snap.png
│ ├── background-clip-test-tsx-test-background-clip-test-tsx-background-clip-should-render-background-clip-text-compatible-with-mask-1-snap.png
│ ├── background-clip-test-tsx-test-background-clip-test-tsx-background-clip-should-render-background-clip-text-compatible-with-transform-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-combine-text-nodes-correctly-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-render-basic-div-with-background-color-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-render-basic-div-with-text-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-render-basic-div-with-text-and-background-color-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-render-empty-div-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-support-array-in-jsx-children-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-support-hex-colors-1-snap.png
│ ├── basic-test-tsx-test-basic-test-tsx-basic-should-support-skipping-embedded-fonts-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-color-should-fallback-border-color-to-the-current-color-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-color-should-render-black-border-by-default-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-color-should-support-overriding-border-color-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-color-should-support-specifying-border-color-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-not-exceed-the-length-of-the-short-side-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-support-percentage-border-radius-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-support-radius-for-a-certain-corner-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-support-slash-and-2-value-corner-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-support-the-shorthand-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-radius-should-support-vw-vh-em-and-rem-units-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-should-support-the-shorthand-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-style-should-support-dashed-border-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-border-width-should-render-border-inside-the-shape-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-directional-should-support-advanced-border-with-radius-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-directional-should-support-directional-border-1-snap.png
│ ├── border-test-tsx-test-border-test-tsx-border-directional-should-support-non-complete-border-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-make-clip-path-compatible-with-overflow-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-2-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-3-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-4-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-5-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-6-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-border-should-render-clip-path-7-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-make-clip-path-compatible-with-overflow-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-2-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-3-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-4-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-5-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-6-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-render-clip-path-7-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-repect-left-and-top-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-respect-left-and-top-1-snap.png
│ ├── clip-path-test-tsx-test-clip-path-test-tsx-clip-path-should-respect-the-position-value-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-currentcolor-when-background-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-currentcolor-when-border-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-currentcolor-when-inherit-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-hexadecimal-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-hexadecimal-with-transparency-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-hsl-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-hsla-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-inherit-color-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-predefined-color-names-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-rgb-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-background-color-and-color-should-support-rgba-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-syntax-color-in-hsl-1-snap.png
│ ├── color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-syntax-color-in-hsl-if-inherited-1-snap.png
│ ├── dynamic-size-test-tsx-test-dynamic-size-test-tsx-dynamic-size-should-render-image-with-dynamic-height-1-snap.png
│ ├── dynamic-size-test-tsx-test-dynamic-size-test-tsx-dynamic-size-should-render-image-with-dynamic-width-1-snap.png
│ ├── emoji-test-tsx-test-emoji-test-tsx-emojis-should-render-emojis-correctly-1-snap.png
│ ├── emoji-test-tsx-test-emoji-test-tsx-emojis-should-render-emojis-correctly-with-alphabetic-emoji-1-snap.png
│ ├── emoji-test-tsx-test-emoji-test-tsx-emojis-should-render-emojis-correctly-with-word-break-break-all-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-font-size-should-allow-font-size-to-be-0-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-handle-escape-html-when-embed-font-is-false-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-handle-font-family-fallback-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-handle-font-size-correctly-for-element-like-heading-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-handle-font-size-correctly-for-element-like-heading-2-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-handle-font-size-correctly-for-element-like-heading-3-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-not-error-when-no-font-is-specified-and-no-text-rendered-1-snap.png
│ ├── font-test-tsx-test-font-test-tsx-font-should-use-correct-fonts-1-snap.png
│ ├── gap-test-tsx-test-gap-test-tsx-flex-gap-should-support-gap-1-snap.png
│ ├── gap-test-tsx-test-gap-test-tsx-flex-gap-should-support-row-gap-and-column-gap-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-linear-gradient-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-linear-gradient-with-omitted-orientation-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-linear-gradient-with-transparency-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-multiple-direction-keywords-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-other-degree-unit-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-other-degree-unit-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-other-degree-unit-3-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-repeating-linear-gradient-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-linear-gradient-should-support-using-background-instead-of-background-image-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-default-value-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-radial-gradient-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-radial-gradient-with-unspecified-ending-shape-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-3-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-4-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-3-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-compute-correct-cycle-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-compute-correct-cycle-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-background-size-and-background-repeat-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-degree-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-degree-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-degree-3-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-degree-4-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-multiple-repeating-linear-gradient-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-repeating-linear-gradient-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-repeating-linear-gradient-should-support-repeating-linear-gradient-2-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-be-able-to-render-grid-backgrounds-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-calculate-the-gradient-angle-and-length-correctly-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-calculate-the-gradient-angle-and-length-correctly-with-offset-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-render-gradient-patterns-in-the-correct-object-space-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-resolve-gradient-layers-in-the-correct-order-1-snap.png
│ ├── gradient-test-tsx-test-gradient-test-tsx-gradient-should-support-advanced-usage-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-correctly-position-the-background-pattern-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-handle-charset-utf-8-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-handle-charset-utf-8-with-comma-in-data-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-handle-charset-utf-8-with-in-base-64-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-data-uris-with-size-for-supported-image-formats-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-data-uris-with-size-for-supported-image-formats-2-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-data-uris-with-size-for-supported-image-formats-3-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-data-uris-with-size-for-supported-image-formats-4-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-data-uris-with-size-for-supported-image-formats-5-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-resolve-image-data-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-support-double-quotes-inside-url-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-support-single-quotes-inside-url-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-background-image-url-should-support-stretched-background-size-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-clip-content-in-the-border-and-padding-areas-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-clip-content-in-the-border-area-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-deduplicate-image-data-requests-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-have-a-separate-border-radius-clip-path-when-transform-is-used-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-not-throw-when-image-is-not-valid-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-render-svg-with-image-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-resolve-image-data-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-resolve-non-square-image-size-correctly-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-resolve-the-image-size-and-scale-automatically-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-scale-image-to-fit-max-width-and-max-height-but-maintain-the-aspect-ratio-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-scale-image-to-fit-max-width-and-max-height-but-maintain-the-aspect-ratio-2-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-support-array-buffer-as-src-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-support-opacity-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-support-styles-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-support-svg-images-and-percentage-with-correct-aspect-ratio-1-snap.png
│ ├── image-test-tsx-test-image-test-tsx-image-should-support-transparent-image-with-background-1-snap.png
│ ├── language-test-tsx-test-language-test-tsx-detect-language-code-should-not-crash-when-rendering-arabic-letters-1-snap.png
│ ├── layout-test-tsx-test-layout-test-tsx-layout-should-stretch-items-by-default-1-snap.png
│ ├── line-clamp-test-tsx-test-line-clamp-test-tsx-line-clamp-should-not-work-when-display-is-not-set-to-block-1-snap.png
│ ├── line-clamp-test-tsx-test-line-clamp-test-tsx-line-clamp-should-replace-custom-block-ellipsis-with-default-ellipsis-when-too-long-1-snap.png
│ ├── line-clamp-test-tsx-test-line-clamp-test-tsx-line-clamp-should-work-correctly-1-snap.png
│ ├── line-clamp-test-tsx-test-line-clamp-test-tsx-line-clamp-should-work-correctly-when-text-align-center-1-snap.png
│ ├── line-height-test-tsx-test-line-height-test-tsx-line-height-should-work-correctly-1-snap.png
│ ├── line-height-test-tsx-test-line-height-test-tsx-line-height-should-work-correctly-2-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-2-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-3-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-on-img-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-on-positioned-elements-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-image-on-text-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-position-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-repeat-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-mask-size-1-snap.png
│ ├── mask-image-test-tsx-test-mask-image-test-tsx-mask-should-support-multiple-mask-image-1-snap.png
│ ├── overflow-test-tsx-test-overflow-test-tsx-overflow-should-not-show-overflowed-text-1-snap.png
│ ├── overflow-test-tsx-test-overflow-test-tsx-overflow-should-not-work-when-overflow-is-not-hidden-and-overflow-property-should-not-be-inherited-1-snap.png
│ ├── overflow-test-tsx-test-overflow-test-tsx-overflow-should-work-with-ellipsis-nowrap-1-snap.png
│ ├── overflow-test-tsx-test-overflow-test-tsx-overflow-should-work-with-nested-border-border-radius-padding-1-snap.png
│ ├── position-test-tsx-test-position-test-tsx-position-absolute-should-support-absolute-position-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-be-affected-by-container-opacity-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-render-box-shadow-with-offset-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-render-box-shadow-with-offset-and-spread-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-render-multiple-box-shadows-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-render-regular-box-shadow-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-show-box-shadow-without-specifying-height-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-box-shadow-for-transparent-elements-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-box-shadow-spread-with-transparency-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-inset-box-shadows-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-multiple-text-shadows-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-negative-spread-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-support-text-shadows-if-exist-unexpected-comma-1-snap.png
│ ├── shadow-test-tsx-test-shadow-test-tsx-shadow-box-shadow-should-work-correct-with-zero-border-radius-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-parse-view-box-correctly-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-render-svg-attributes-correctly-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-render-svg-nodes-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-render-svg-prefer-size-props-rather-than-view-box-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-render-svg-size-correctly-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-render-svg-without-view-box-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-respect-style-on-svg-node-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-support-current-color-for-svg-fill-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-support-current-color-for-svg-stroke-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-support-current-color-when-color-is-set-on-parent-element-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-support-current-color-when-used-on-svg-nodes-1-snap.png
│ ├── svg-test-tsx-test-svg-test-tsx-svg-should-support-em-in-svg-size-1-snap.png
│ ├── tab-size-test-tsx-test-tab-size-test-tsx-tab-size-tab-renders-as-space-when-white-space-is-not-pre-or-pre-wrap-1-snap.png
│ ├── tab-size-test-tsx-test-tab-size-test-tsx-tab-size-tabs-render-correctly-when-tab-size-is-a-number-1-snap.png
│ ├── tab-size-test-tsx-test-tab-size-test-tsx-tab-size-tabs-render-correctly-when-tab-size-is-a-string-1-snap.png
│ ├── tab-size-test-tsx-test-tab-size-test-tsx-tab-size-tabs-render-correctly-with-default-tab-size-of-8-when-white-space-is-pre-1-snap.png
│ ├── tab-size-test-tsx-test-tab-size-test-tsx-tab-size-tabs-render-correctly-with-default-tab-size-of-8-when-white-space-is-pre-wrap-1-snap.png
│ ├── text-align-test-tsx-test-text-align-test-tsx-text-align-should-work-correctly-when-text-align-center-1-snap.png
│ ├── text-align-test-tsx-test-text-align-test-tsx-text-align-should-work-correctly-when-text-align-end-1-snap.png
│ ├── text-align-test-tsx-test-text-align-test-tsx-text-align-should-work-correctly-when-text-align-left-1-snap.png
│ ├── text-align-test-tsx-test-text-align-test-tsx-text-align-should-work-correctly-when-text-align-right-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-when-text-decoration-line-line-through-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-when-text-decoration-line-line-through-and-text-align-right-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-when-text-decoration-line-underline-and-text-align-right-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-when-text-decoration-style-dashed-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-when-text-decoration-style-dotted-1-snap.png
│ ├── text-decoration-test-tsx-test-text-decoration-test-tsx-text-decoration-should-work-correctly-with-text-decoration-and-transform-1-snap.png
│ ├── text-wrap-test-tsx-test-text-wrap-test-tsx-text-wrap-should-wrap-balancedly-with-text-wrap-balance-1-snap.png
│ ├── text-wrap-test-tsx-test-text-wrap-test-tsx-text-wrap-should-wrap-normally-with-text-wrap-wrap-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-behavior-with-parent-overflow-should-not-inherit-parent-clip-path-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-multiple-transforms-should-support-translate-rotate-and-scale-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-rotate-should-rotate-shape-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-scale-should-scale-shape-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-scale-should-scale-shape-in-two-directions-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-translate-should-support-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-translate-should-translate-shape-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-translate-should-translate-shape-in-x-axis-1-snap.png
│ ├── transform-test-tsx-test-transform-test-tsx-transform-translate-should-translate-shape-in-y-axis-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-em-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-px-and-numbers-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-rem-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-rgb-syntaxs-1-snap.png
│ ├── units-test-tsx-test-units-test-tsx-units-should-support-vh-and-vw-1-snap.png
│ ├── webkit-text-stroke-test-tsx-test-webkit-text-stroke-test-tsx-webkit-text-stroke-should-work-basic-text-stroke-1-snap.png
│ ├── webkit-text-stroke-test-tsx-test-webkit-text-stroke-test-tsx-webkit-text-stroke-should-work-nested-and-complex-text-stroke-1-snap.png
│ ├── webkit-text-stroke-test-tsx-test-webkit-text-stroke-test-tsx-webkit-text-stroke-should-work-nested-text-stroke-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-normal-should-have-line-break-before-fast-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-normal-should-not-render-extra-line-breaks-with-white-space-normal-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-normal-should-not-render-extra-spaces-with-white-space-normal-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-normal-should-wrap-automatically-with-white-space-normal-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-pre-should-always-preserve-extra-line-breaks-with-white-space-pre-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-pre-should-always-preserve-extra-spaces-with-white-space-pre-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-pre-should-not-wrap-with-white-space-pre-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-pre-should-render-line-breaks-correctly-without-separators-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-n-in-content-should-render-consecutive-line-breaks-with-pre-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-n-in-content-should-render-n-as-a-line-break-with-pre-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-n-in-content-should-render-n-as-a-whitespace-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-white-space-nowrap-should-not-wrap-with-white-space-nowrap-and-swallow-extra-spaces-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-white-space-pre-line-should-always-collapse-spaces-and-preserve-line-breaks-with-white-space-pre-line-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-white-space-pre-wrap-should-always-preserve-extra-line-breaks-with-white-space-pre-wrap-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-white-space-pre-wrap-should-always-preserve-extra-spaces-with-white-space-pre-wrap-1-snap.png
│ ├── white-space-test-tsx-test-white-space-test-tsx-white-space-with-white-space-pre-wrap-should-automatically-wrap-with-white-space-pre-wrap-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-break-all-should-always-break-words-eagerly-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-break-word-should-break-words-if-cannot-fit-into-one-line-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-break-word-should-not-break-cjk-with-word-break-keep-all-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-break-word-should-try-to-wrap-words-if-possible-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-break-word-should-wrap-first-and-then-break-long-words-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-normal-should-not-break-long-word-1-snap.png
│ ├── word-break-test-tsx-test-word-break-test-tsx-word-break-normal-should-not-break-word-if-possible-to-wrap-1-snap.png
│ └── word-break-test-tsx-test-word-break-test-tsx-word-break-should-support-non-breaking-space-1-snap.png
├── assets
│ ├── MontserratSubrayada-Regular.ttf
│ ├── Roboto-Bold.ttf
│ ├── Roboto-Regular.ttf
│ ├── playfair-display.ttf
│ ├── Χαίρετ
│ ├── こんにちは
│ ├── 你好
│ └── 안녕
├── background-clip.test.tsx
├── basic.test.tsx
├── border.test.tsx
├── clip-path.test.tsx
├── color-models.test.tsx
├── dynamic-size.test.tsx
├── emoji.test.tsx
├── error.test.tsx
├── event.test.tsx
├── font.test.tsx
├── gap.test.tsx
├── gradient.test.tsx
├── image.test.tsx
├── language.test.tsx
├── layout.test.tsx
├── line-clamp.test.tsx
├── line-height.test.tsx
├── mask-image.test.tsx
├── overflow.test.tsx
├── position.test.tsx
├── shadow.test.tsx
├── svg.test.tsx
├── tab-size.test.tsx
├── text-align.test.tsx
├── text-decoration.test.tsx
├── text-wrap.test.tsx
├── transform.test.tsx
├── units.test.tsx
├── utils.tsx
├── webkit-text-stroke.test.tsx
├── white-space.test.tsx
└── word-break.test.tsx
├── tsconfig.json
├── tsconfig.wasm.json
├── tsup.config.ts
├── turbo.json
├── vitest.config.ts
└── wasm.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "node": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:react/recommended",
10 | "plugin:react/jsx-runtime",
11 | "plugin:@typescript-eslint/recommended"
12 | ],
13 | "overrides": [
14 | {
15 | "files": ["src/**/*.js", "src/**/*.ts"],
16 | "rules": {
17 | "prefer-const": "off"
18 | }
19 | },
20 | {
21 | "files": ["test/**/*.ts`", "test/**/*.tsx"],
22 | "rules": {
23 | "react/jsx-key": "off"
24 | }
25 | }
26 | ],
27 | "parser": "@typescript-eslint/parser",
28 | "parserOptions": {
29 | "project": [
30 | "./tsconfig.json",
31 | "./playground/tsconfig.json",
32 | "./tsconfig.wasm.json"
33 | ]
34 | },
35 | "plugins": ["react", "react-hooks", "@typescript-eslint"],
36 | "rules": {
37 | "no-inner-declarations": 0,
38 | "no-useless-escape": 1,
39 | "@typescript-eslint/ban-ts-comment": 1,
40 | "@typescript-eslint/no-extra-semi": 0,
41 | "@typescript-eslint/no-shadow": 2,
42 | "@typescript-eslint/ban-types": 0,
43 | "@typescript-eslint/no-namespace": 0,
44 | "react-hooks/rules-of-hooks": 2,
45 | "react-hooks/exhaustive-deps": 1,
46 | "react/prop-types": 0
47 | },
48 | "ignorePatterns": ["dist/", "node_modules", "vendor"]
49 | }
50 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @shuding
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a bug report for Satori
4 | ---
5 |
6 | # Bug report
7 |
8 | ## Description / Observed Behavior
9 |
10 | What kind of issues did you encounter with Satori?
11 |
12 | ## Expected Behavior
13 |
14 | How did you expect Satori to behave here?
15 |
16 | ## Reproduction
17 |
18 | Create a shareable reproduction link for the issue using https://og-playground.vercel.app.
19 |
20 | ## Additional Context
21 |
22 | Satori version, and any other context about the problem here.
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Question & Ideas
4 | url: https://github.com/vercel/satori/discussions
5 | about: Ask questions and share your thoughts with other community members
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Request a new feature for Satori
4 | ---
5 |
6 | # Feature Request
7 |
8 | ## Description
9 |
10 | What do you want to add to Satori, and why?
11 |
12 | ## Additional Context
13 |
14 | You can add a shareable link using https://og-playground.vercel.app, or any other context that helps explaining this feature request here.
15 |
--------------------------------------------------------------------------------
/.github/card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vercel/satori/aa7cdb6b0d47e93781822c3ec4a7614fb2e68949/.github/card.png
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: ['main']
6 | pull_request:
7 | branches: ['main']
8 |
9 | concurrency:
10 | group: ${{ github.workflow }}-${{ github.ref }}
11 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
12 |
13 | jobs:
14 | integrity:
15 | # prevents this action from running on forks
16 | if: github.repository_owner == 'vercel'
17 | runs-on: ubuntu-latest
18 | strategy:
19 | matrix:
20 | node: [ 20 ]
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v3
24 | - name: Use pnpm
25 | run: corepack enable pnpm && pnpm --version
26 | - name: Use Node.js ${{ matrix.node }}
27 | uses: actions/setup-node@v3
28 | with:
29 | node-version: ${{ matrix.node }}
30 | cache: 'pnpm'
31 | - run: pnpm install
32 | - run: pnpm ci-check
33 |
34 | test:
35 | # prevents this action from running on forks
36 | if: github.repository_owner == 'vercel'
37 | name: Node.js ${{ matrix.node }} on ${{ matrix.os }}
38 | timeout-minutes: 5
39 | strategy:
40 | fail-fast: false
41 | matrix:
42 | os: [ubuntu-latest]
43 | node: [18, 20]
44 | runs-on: ${{ matrix.os }}
45 | permissions:
46 | contents: write # to be able to publish a GitHub release
47 | issues: write # to be able to comment on released issues
48 | pull-requests: write # to be able to comment on released pull requests
49 | id-token: write # to enable use of OIDC for npm provenance
50 | steps:
51 | - name: Checkout
52 | uses: actions/checkout@v3
53 | - name: Use pnpm
54 | run: corepack enable pnpm && pnpm --version
55 | - name: Use Node.js ${{ matrix.node }}
56 | uses: actions/setup-node@v3
57 | with:
58 | node-version: ${{ matrix.node }}
59 | cache: 'pnpm'
60 | - run: pnpm install
61 | - run: pnpm build
62 | - run: pnpm test
63 | - name: Maybe Release
64 | if: matrix.os == 'ubuntu-latest' && matrix.node == 20 && github.event_name == 'push' && github.ref == 'refs/heads/main'
65 | env:
66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
67 | NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}
68 | NPM_CONFIG_PROVENANCE: 'true'
69 | run: pnpm dlx semantic-release@24.2.3
70 |
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | name: PR
2 | on:
3 | pull_request:
4 | types: [opened, edited, synchronize]
5 | pull_request_target:
6 | types: [opened, edited, synchronize]
7 |
8 | jobs:
9 | lint:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: amannn/action-semantic-pull-request@0b14f54ac155d88e12522156e52cb6e397745cfd
13 | env:
14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | .vercel
4 | .vscode
5 | .next
6 | .idea
7 | .turbo
8 | dist
9 | .pnpm-debug.log
10 | __diff_output__
11 | .eslintcache
12 | coverage
13 |
14 | playground/public/yoga.wasm
15 | playground/tsconfig.tsbuildinfo
16 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | pnpm lint-staged
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shell-emulator=true
2 | provenance=true
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .github/
2 | node_modules
3 | **/.next/**
4 | **/_next/**
5 | **/dist/**
6 | src/vendor/
7 | pnpm-lock.yaml
8 | *.md
9 | coverage/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": false,
4 | "singleQuote": true,
5 | "jsxSingleQuote": true,
6 | "semi": false
7 | }
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Satori Contribution Guidelines
2 |
3 | Thank you for reading this guide and we appreciate any contribution.
4 |
5 | ## Ask a Question
6 |
7 | You can use the repository's [Discussions](https://github.com/vercel/satori/discussions) page to ask any questions, post feedback, or share your experience on how you use this library.
8 |
9 | ## Report a Bug
10 |
11 | Whenever you find something which is not working properly, please first search the repository's [Issues](https://github.com/vercel/satori/issues) page and make sure it's not reported by someone else already.
12 |
13 | If not, feel free to open an issue with a detailed description of the problem and the expected behavior. A bug reproduction using [Satori’s playground](https://og-playground.vercel.app) will be extremely helpful.
14 |
15 | ## Request for a New Feature
16 |
17 | For new features, it would be great to have some discussions from the community before starting working on it. You can either create an issue (if there isn't one) or post a thread on the [Discussions](https://github.com/vercel/satori/discussions) page to describe the feature that you want to have.
18 |
19 | If possible, you can add another additional context like how this feature can be implemented technically, what other alternative solutions we can have, etc.
20 |
21 | ## Local Development
22 |
23 | This project uses [pnpm](https://pnpm.io). To install dependencies, run:
24 |
25 | ```bash
26 | pnpm install
27 | ```
28 |
29 | To start the playground together with Satori locally, run:
30 |
31 | ```bash
32 | pnpm dev:playground
33 | ```
34 |
35 | And visit localhost:3000.
36 |
37 | To only start the development mode of Satori, run `pnpm dev` in the root directory (recommended to test together with the playground to see changes in live).
38 |
39 | ## Adding Tests
40 |
41 | Satori uses [Vitest](https://vitest.dev) to test and generate snapshots. To start and live-watch the tests, run:
42 |
43 | ```bash
44 | pnpm dev:test
45 | ```
46 |
47 | It will update snapshot images as well.
48 |
49 | You can also use `pnpm test` to only run the test.
50 |
--------------------------------------------------------------------------------
/playground/cards/preview-tabs.ts:
--------------------------------------------------------------------------------
1 | const previewTabs = [
2 | 'SVG (Satori)',
3 | 'PNG (Satori + resvg-js)', // https://github.com/yisibl/resvg-js
4 | 'PDF (Satori + PDFKit)',
5 | 'HTML (Native)',
6 | ]
7 |
8 | export default previewTabs
9 |
--------------------------------------------------------------------------------
/playground/components/introduction.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | position: fixed;
3 | left: 20px;
4 | bottom: 20px;
5 | width: 700px;
6 | min-height: 200px;
7 | max-width: calc(100vw - 40px);
8 | max-height: calc(100vh - 40px);
9 | margin: auto;
10 | border-radius: 8px;
11 | display: flex;
12 | flex-direction: column;
13 | justify-content: flex-start;
14 | padding: 20px;
15 | color: #ddd;
16 | font-size: 14px;
17 | backdrop-filter: blur(24px);
18 | background-color: rgb(0 0 0 / 88%);
19 | box-shadow: 0 20px 40px #0000005c, 0 0 0 1px #868686;
20 | z-index: 4;
21 | opacity: 0;
22 | line-height: 1.6;
23 | letter-spacing: -0.01rem;
24 | word-spacing: -0.12rem;
25 | animation: fadein 0.4s ease 0.4s forwards;
26 | }
27 |
28 | .container p {
29 | margin: 0;
30 | margin-bottom: 1em;
31 | }
32 |
33 | .container code {
34 | background-color: #4a4a4a;
35 | padding: 0 4px;
36 | border-radius: 4px;
37 | }
38 |
39 | .container button {
40 | appearance: none;
41 | border: none;
42 | background: white;
43 | border-radius: 5px;
44 | padding: 8px 12px;
45 | width: 120px;
46 | align-self: flex-start;
47 | font-family: inherit;
48 | font-weight: 600;
49 | cursor: pointer;
50 | transition: all 0.2s ease;
51 | }
52 |
53 | .container button:hover {
54 | background: #ccc;
55 | }
56 |
57 | @keyframes fadein {
58 | from {
59 | opacity: 0;
60 | }
61 | to {
62 | opacity: 1;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/playground/components/introduction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './introduction.module.css'
3 |
4 | interface IProps {
5 | onClose: React.MouseEventHandler 👋 Welcome to the Vercel OG Image playground!
13 | You can use this tool to test and preview OG image cards generated with{' '}
14 | @vercel/og
. To learn more about how to add it to your
15 | project, please read{' '}
16 |
21 | our documentation
22 | {' '}
23 | or the{' '}
24 |
29 | announcement post
30 |
31 | .
32 |