RepoPilot

vercel/satori

Enlightened library to convert HTML and CSS to SVG

Healthy

Healthy across the board

HealthyDependency

Permissive license, no critical CVEs, actively maintained — safe to depend on.

HealthyFork & modify

Has a license, tests, and CI — clean foundation to fork and modify.

HealthyLearn from

Documented and popular — useful reference codebase to read through.

HealthyDeploy as-is

No critical CVEs, sane security posture — runnable as-is.

  • Scorecard: default branch unprotected (0/10)
  • Last commit 4w ago
  • 40+ active contributors
  • Distributed ownership (top contributor 23% of recent commits)
  • MPL-2.0 licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/vercel/satori)](https://repopilot.app/r/vercel/satori)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card

This card auto-renders when someone shares https://repopilot.app/r/vercel/satori on X, Slack, or LinkedIn.

Ask AI about vercel/satori

Grounded in the actual source code. Pick a starter question or write your own.

Or write your own question →

Onboarding doc

Onboarding: vercel/satori

Generated by RepoPilot · 2026-06-19 · Source

🎯Verdict

GO — Healthy across the board

  • Last commit 4w ago
  • 40+ active contributors
  • Distributed ownership (top contributor 23% of recent commits)
  • MPL-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Scorecard: default branch unprotected (0/10)

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard</sub>

TL;DR

Satori is a TypeScript library that converts HTML/CSS and JSX into optimized SVG strings by performing layout calculation, font rendering, and typography handling without a browser. It powers dynamic image generation (like Open Graph cards) by deterministically rendering React-like components to SVG at runtime. Monorepo with pnpm workspaces: src/ contains core TypeScript engine (layout, rendering, typography), src/jsx/ provides experimental JSX runtime without React dependency, standalone build mode (SATORI_STANDALONE env var) bundles WASM inline, and playground/ is a Next.js demo app for testing visual output.

👥Who it's for

Next.js and Node.js developers building dynamic social cards, Open Graph images, and serverless image generation pipelines who need pixel-perfect HTML-to-SVG conversion without headless browsers or external services.

🌱Maturity & risk

Actively developed and production-ready. Vercel maintains it as a core tool for their OG Image Generation product. The project has TypeScript-first architecture, GitHub Actions CI/CD (ci.yml, pr.yml), comprehensive test coverage (vitest), and an interactive playground. Version 0.0.0-development.2 and semantic-release setup indicate active development with frequent releases.

Low risk for core use cases but with architectural constraints: single-maintainer (Vercel team), relies on Yoga Layout WASM module (patched at patches/yoga-layout@3.2.1.patch) which is a hidden dependency, and deliberately supports only a subset of HTML/CSS to keep SVG output small and deterministic. WASM bundling and browser/Node.js dual-platform support add complexity.

Active areas of work

Focus on experimental JSX runtime stabilization and standalone build optimization. CI pipeline validates TypeScript compilation, tests, and linting on every PR. Husky pre-commit hooks enforce code quality. Semantic-release (release.config.cjs) automates versioning.

🚀Get running

git clone https://github.com/vercel/satori.git && cd satori && pnpm install && pnpm dev (starts TypeScript watch build) or pnpm dev:playground (starts Next.js playground on localhost:3000).

Daily commands: pnpm dev (default: src/index.ts watch build) | pnpm dev:playground (Next.js app on http://localhost:3000) | pnpm build (produces dist/ with esm + cjs + standalone) | pnpm test (vitest run) | pnpm test:ui (vitest --ui with coverage).

🗺️Map of the codebase

  • src/satori.ts — Main entry point that orchestrates HTML/CSS to SVG conversion pipeline.
  • src/layout.ts — Yoga layout engine wrapper that computes all element dimensions and positioning.
  • src/builder/svg.ts — Core SVG builder that generates the final SVG output from computed layout and styles.
  • src/text/index.ts — Text rendering and font measurement system that handles typography and glyph processing.
  • src/handler/compute.ts — CSS property computation and style inheritance resolver for the rendering pipeline.
  • src/index.ts — Public API export point exposing satori function and types to consumers.

🧩Components & responsibilities

  • Satori Orchestrator (src/satori.ts) (TypeScript, JSX) — Coordinates parsing, style computation, layout, and SVG building for the full conversion pipeline.
    • Failure mode: Throws on unsupported element types, invalid CSS, or missing required fonts.
  • Layout Engine (src/layout.ts + Yoga WASM) (Yoga WASM, TypeScript) — Computes flexbox dimensions, positions, and text wrap based on CSS and content.
    • Failure mode: Returns incorrect layout for unsupported flex properties or circular constraints.
  • Style Computation (src/handler/compute.ts) (TypeScript, CSS parser) — Resolves CSS property values, applies inheritance, and expands shorthand properties.
    • Failure mode: Silently ignores unknown properties; incorrect inheritance for custom properties.
  • Text Renderer (src/text/) (Font APIs, harfbuzz (via measurer), TypeScript) — Measures text, loads fonts, and generates glyph paths for SVG rendering.
    • Failure mode: Missing fonts cause empty text; measurement failures result in layout corruption.
  • SVG Builder (src/builder/) (SVG spec, TypeScript) — Generates SVG elements, attributes, and effects (gradients, shadows, transforms) from computed styles.
    • Failure mode: Invalid SVG syntax if builder logic has bugs; rendering errors in downstream tools.
  • Style Preprocessor (src/handler/preprocess.ts, expand.ts) (CSS spec, TypeScript) — Normalizes input CSS, validates values, and expands shorthand declarations.
    • Failure mode: Rejects valid CSS or accepts invalid CSS if parsing logic is incomplete.

🔀Data flow

  • User JSX inputElement tree (internal representation) — JSX is transpiled to nested element objects with props and children.
  • Element tree + stylesheetComputed styles (style map per element) — Style computation handler applies CSS rules, inheritance, and preprocessing.
  • Computed styles + fontsLayout constraints (Yoga input) — Style values (width, padding, flex rules) fed to Yoga engine for measurement.
  • Layout output (dimensions, positions)SVG builders — Builders consume layout boxes and styles to generate SVG elements.
  • SVG builders outputFinal SVG string — SVG elements concatenated and returned as serialized string.

🛠️How to make changes

Add a new CSS property handler

  1. Create a builder file in src/builder/ to generate SVG for the new property (e.g., src/builder/new-effect.ts). (src/builder/new-effect.ts)
  2. Add property computation logic in src/handler/compute.ts to parse and validate the CSS value. (src/handler/compute.ts)
  3. Register the builder in src/satori.ts by importing it and calling it during element rendering. (src/satori.ts)

Add support for a new CSS gradient type

  1. Create a gradient builder in src/builder/gradient/ (e.g., conic.ts following linear.ts pattern). (src/builder/gradient/conic.ts)
  2. Update src/builder/gradient/utils.ts to add parsing and validation for the new gradient syntax. (src/builder/gradient/utils.ts)
  3. Register the gradient parser in src/handler/compute.ts background-image handling. (src/handler/compute.ts)

Extend JSX element support

  1. Define new intrinsic element types in src/jsx/intrinsic-elements.ts. (src/jsx/intrinsic-elements.ts)
  2. Add element-specific rendering logic in src/satori.ts element builder switch statement. (src/satori.ts)
  3. Test the new element in playground/pages/index.tsx and add example cards in playground/cards/. (playground/pages/index.tsx)

Add a custom font preset

  1. Create or update a preset object in src/handler/presets.ts with font configuration. (src/handler/presets.ts)
  2. Add font files to playground/public/ for testing in the playground. (playground/public)
  3. Update playground/cards/playground-data.ts to include examples using the new font. (playground/cards/playground-data.ts)

🔧Why these technologies

  • Yoga (flexbox layout engine) — Provides accurate CSS flexbox computation matching browser behavior for deterministic layout.
  • SVG output format — Enables conversion to PNG/raster formats downstream while preserving vector quality.
  • JSX syntax — Makes HTML/CSS specification intuitive and type-safe compared to raw object APIs.
  • WASM (Yoga bundled) — Provides near-native performance for complex layout calculations in Node.js and browser contexts.

⚖️Trade-offs already made

  • No browser/DOM API dependency

    • Why: Satori reimplements CSS rendering from scratch rather than using browser engines.
    • Consequence: Lightweight and portable but requires manual implementation of every CSS feature; subset of CSS supported.
  • Synchronous rendering pipeline

    • Why: Single-pass computation keeps API simple and deterministic.
    • Consequence: Large documents with many fonts may block; async operations (font loading) must complete before satori() call.
  • Limited CSS feature set

    • Why: Focuses on static design output (OG images) rather than full CSS compatibility.
    • Consequence: Media queries, animations, pseudo-states not supported; predictable subset suitable for social cards.

🚫Non-goals (don't propose these)

  • Does not handle interactive elements or event listeners.
  • Does not support CSS animations or transitions.
  • Does not implement full CSS specification; subset focused on static layout and styling.
  • Not a replacement for browser rendering; cannot run arbitrary web pages.

📊Code metrics

  • Avg cyclomatic complexity: ~6.5 — High-level abstractions (builders, handlers) hide complexity; core satori.ts and layout.ts contain moderate cyclomatic complexity; text measurement is CPU-intensive.
  • Largest file: src/satori.ts (450 lines)
  • Estimated quality issues: ~4 — Limited error handling for invalid CSS, incomplete CSS property support documentation, monolithic orchestrator, and missing async font loading capability.

⚠️Anti-patterns to avoid

  • Direct style property access without normalization (Medium)src/handler/compute.ts: Some code paths access parsed CSS values directly without validating against supported property set, risking runtime errors.
  • Synchronous font loading requirement (Medium)src/font.ts, src/text/measurer.ts: Fonts must be fully loaded before satori() call; no async/lazy loading inside render pipeline, limiting scalability.
  • Monolithic satori.ts file (Low)src/satori.ts: Core orchestrator has high cyclomatic complexity handling all element types and builder coordination; difficult to extend.
  • Limited error messages for unsupported CSS (Low)src/handler/compute.ts: Silently ignores unknown CSS properties instead of warning, making debugging user stylesheets harder.

🔥Performance hotspots

  • src/text/measurer.ts (CPU-bound text measurement) — Font metrics and text dimension computation is per-node and cannot be parallelized; scales linearly with document text volume.
  • src/layout.ts (Yoga WASM calls) (Flexbox computation overhead) — Layout engine is synchronous and computes full tree in single pass; complex nested layouts suffer quadratic time.
  • src/builder/gradient/ & src/builder/shadow.ts (SVG generation inefficiency) — Gradient and shadow SVG generation done sequentially per element without batching or optimization.

🪤Traps & gotchas

Yoga Layout WASM module must be initialized before use (handled internally but critical for standalone builds). Font loading is async and required—missing fonts cause silent fallback or render errors. CSS property support is intentionally limited (see docs); unsupported properties are silently ignored. The standalone build inlines WASM via base64, significantly increasing bundle size—use default build for Node.js servers. JSX runtime is experimental and may have API changes. The library does not support React hooks, state, or lifecycle methods—only pure stateless components.

🏗️Architecture

💡Concepts to learn

  • Yoga Layout Engine (WASM) — Satori delegates all Flexbox layout computation to Yoga's WASM module; understanding its constraints (no CSS Grid, limited property set) explains SVG output limitations
  • JSX Transform & Custom Runtime — Satori implements a lightweight JSX runtime without React runtime overhead via @jsxImportSource pragma; critical for understanding why React hooks/state don't work
  • Font Subsetting & Rendering — Satori requires explicit font buffers and metrics calculation for accurate text layout and SVG path generation; missing fonts silently degrade output
  • SVG Deterministic Rendering — By avoiding DOM/browser rendering, Satori guarantees identical output on every call—essential for reproducible server-side image generation and caching
  • CSS Subset Enforcement — Satori intentionally supports only essential CSS properties to minimize SVG size and complexity; developers must understand which properties are valid to avoid silent failures
  • WASM Binary Bundling Strategies — The SATORI_STANDALONE environment variable switches between external WASM file vs. base64-inlined WASM; critical for deployment decisions (bundle size vs. fetch latency)
  • Monorepo Workspaces (pnpm) — Source code, tests, and playground share dependencies via pnpm workspaces; understanding workspace layout and install order prevents build ordering issues
  • vercel/og — Official Next.js integration for Satori-powered OG image generation—the production wrapper around this library
  • RenderingNG/Yoga — Upstream Yoga Layout WASM engine that Satori patches and wraps for layout computation
  • vercel/nextjs — Next.js repository including built-in OG image route handlers that use Satori under the hood
  • puppeteer/puppeteer — Alternative HTML-to-image tool using headless Chrome; Satori chosen when lightweight SVG output and serverless performance are priorities
  • storybook/storybook — Component testing and visual documentation tool—Satori playground is inspired by similar interactive component sandboxes

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for src/builder modules

The src/builder directory contains critical style-to-SVG conversion logic (background-image.ts, border-radius.ts, gradient/, shadow.ts, transform.ts, etc.) but there's no visible test directory structure for these modules. Given this is a conversion library where rendering accuracy is paramount, each builder module needs isolated unit tests to prevent regressions when CSS features are added or modified.

  • [ ] Create test files in src/builder/*.test.ts for each builder module (at minimum: border-radius.ts, gradient/linear.ts, gradient/radial.ts, shadow.ts, transform.ts)
  • [ ] Test edge cases like invalid CSS values, browser-specific prefixes, and fallback behavior
  • [ ] Integrate tests into CI workflow (check if vitest is already configured in tsup.config.ts)
  • [ ] Ensure tests cover both ESM and CJS builds since package.json exports both formats

Add TypeScript strict mode validation and type tests for JSX exports

The package exports JSX runtime with custom imports (#satori/jsx/jsx-runtime and #satori/jsx/jsx-dev-runtime) but there's no visible type testing to ensure TypeScript consumers get correct JSX IntrinsicElements, props validation, and proper type inference. This is critical for a library meant to work with JSX syntax.

  • [ ] Create src/jsx/tests/types.test-d.ts using tsd or similar for JSX type validation
  • [ ] Verify that JSX element props are properly typed and match HTML5 element specifications
  • [ ] Test that the custom JSX runtime works correctly with strict TypeScript settings (strict: true in tsconfig)
  • [ ] Add a test case for the style prop to ensure CSS property unions are correctly typed

Add integration tests for font handling in src/font.ts

The src/font.ts module handles font loading and conversion, which is critical for text rendering but appears to lack integration tests. The playground includes font utilities (playground/utils/font.ts) that load real fonts (inter-latin, material-icons), indicating real-world complexity. Tests should verify font loading from URLs, data URIs, and various formats.

  • [ ] Create src/font.test.ts with tests for font loading via fetch, file paths, and base64 data URIs
  • [ ] Test font fallback behavior when a font fails to load
  • [ ] Test interaction between font configuration in satori options and text rendering in src/builder/text.ts
  • [ ] Add test fixtures for common font formats (.woff, .woff2) used in the playground

🌿Good first issues

  • Add TypeScript type tests for JSX component prop inference (playground/cards/playground-data.ts shows data shapes but no exhaustive type coverage tests for custom components with complex prop types)
  • Expand CSS property coverage tests: src/ tests exist but playground examples lack visual regression tests for transforms, filters, and clip-path properties listed in README
  • Document WASM module initialization and debugging: README covers usage but not how to handle WASM load failures in edge/browser contexts—add examples to playground/pages/api/

Top contributors

Click to expand

📝Recent commits

Click to expand
  • ab49faf — chore: migrate workspace to pnpm 10 (#762) (styfle)
  • 8a0619f — chore: remove pull_request_target (#755) (styfle)
  • a2e0dce — fix bug with fragments in svg (plmrry)
  • eab60ee — feat: builtin minimal JSX runtime (#737) (sanman1k98)
  • d246913 — feat: CSS variables (#736) (shuding)
  • dc07b70 — fix: Consistent text positioning when embedFont is false (#723) (privatenumber)
  • 54a749b — chore: export InitInput and allow Promise (#726) (kumardeo)
  • 9377f70 — feat: Improved object-position support (#734) (shuding)
  • 2b7e825 — feat: Add text-indent support (#733) (shuding)
  • 453fd91 — feat: Support for object-fit fill and scale-down (#732) (shuding)

🔒Security observations

Satori is a user-input processing library (HTML/CSS to SVG) with moderate security concerns. The primary risks relate to: (1) Potential XSS through HTML/CSS conversion without visible sanitization, (2) Opaque WASM binary dependency, and

  • High · Potential XSS via HTML/CSS to SVG Conversion — src/builder/, src/parser/, src/handler/. Satori converts user-provided HTML and CSS to SVG. Without proper sanitization, malicious HTML/CSS input could be converted to SVG containing executable content or scripts. The library processes arbitrary styling and HTML elements which could lead to XSS if user input is not properly validated. Fix: Implement strict input validation and sanitization for HTML/CSS input. Use allowlists for supported CSS properties and HTML elements. Consider using a library like DOMPurify to sanitize HTML input before processing. Document security requirements for users processing untrusted input.
  • High · WASM Binary Security — yoga.wasm, patches/yoga-layout@3.2.1.patch. The package includes yoga.wasm (WebAssembly binary) which is not readable for static analysis. WASM binaries are opaque and difficult to audit, creating potential supply chain risks. The patch file 'patches/yoga-layout@3.2.1.patch' suggests modifications to a critical layout dependency. Fix: Ensure the WASM binary is sourced from verified, official sources with published checksums. Document the provenance of the WASM file. Consider building it from verified source code if possible. Verify integrity using checksums in CI/CD pipeline.
  • Medium · Dynamic Code Generation in Playground API — playground/pages/api/font.ts. The playground includes an API endpoint at 'playground/pages/api/font.ts' that appears to dynamically handle font loading. Dynamic file operations or font loading without proper validation could lead to path traversal or unsafe operations. Fix: Implement strict validation of font parameters. Use allowlists for permitted fonts. Validate file paths to prevent directory traversal. Implement rate limiting on font API endpoints to prevent abuse.
  • Medium · Missing CORS and Security Headers Configuration — playground/pages/api/, playground/pages/_app.tsx, playground/pages/_document.tsx. The playground API ('playground/pages/api/') serves dynamic content without visible CORS or security header configuration. This could expose the API to unauthorized cross-origin requests. Fix: Implement proper CORS policies restricting origins. Add security headers (CSP, X-Frame-Options, X-Content-Type-Options) in Next.js middleware. Document API security requirements.
  • Medium · External Resource Loading Risk — src/builder/background-image.ts, src/handler/image.ts, src/font.ts. The library handles fonts and images (src/builder/background-image.ts, src/handler/image.ts) which may involve loading external resources. Unrestricted external resource loading could lead to SSRF attacks or resource exhaustion. Fix: Implement URL validation and allowlisting for external resources. Add timeout and size limits for fetched resources. Validate image/font URLs against allowed domains. Document handling of untrusted resource URLs.
  • Low · Incomplete Package.json Audit — package.json. The package.json content is truncated, making it impossible to fully assess all dependency versions and their known vulnerabilities. The line 'test:ui': 'NODE_ENV=test vitest --ui --coverage.e' appears incomplete. Fix: Complete and verify all package.json entries. Run 'npm audit' or 'pnpm audit' to identify vulnerable dependencies. Keep all dependencies up to date and monitor security advisories. Use npm audit CI integration in GitHub Actions.
  • Low · Potential ReDoS in CSS/HTML Parsing — src/parser/, src/handler/. The parser modules (src/parser/mask.ts, src/parser/shape.ts) and handler modules process complex CSS/HTML patterns. Maliciously crafted input with deeply nested structures or complex regex patterns could cause performance degradation. Fix: Implement limits on nesting depth and input size. Use robust parsing libraries resistant to ReDoS attacks. Add input size validation and processing timeouts. Test with fuzzing against malicious inputs.

LLM-derived; treat as a starting point, not a security audit.

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Read in the suggested order before editing unfamiliar code. The reading-order list is computed from the actual import graph, not LLM guesses; reading bottom-up materially reduces wrong-edit risk.
  3. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  4. Cite source on changes. When proposing an edit, cite the specific path/to/file.ext:Lstart-Lend you're reasoning about, the same way RepoPilot's own RAG cites code in https://repopilot.app/r/vercel/satori.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live vercel/satori repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/vercel/satori.

What it runs against: a local clone of vercel/satori — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in vercel/satori | Confirms the artifact applies here, not a fork | | 2 | License is still MPL-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 56 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>vercel/satori</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of vercel/satori. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/vercel/satori.git
#   cd satori
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of vercel/satori and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "vercel/satori(\\.git)?\\b" \\
  && ok "origin remote is vercel/satori" \\
  || miss "origin remote is not vercel/satori (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MPL-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MPL-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is MPL-2.0" \\
  || miss "license drift — was MPL-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "src/satori.ts" \\
  && ok "src/satori.ts" \\
  || miss "missing critical file: src/satori.ts"
test -f "src/layout.ts" \\
  && ok "src/layout.ts" \\
  || miss "missing critical file: src/layout.ts"
test -f "src/builder/svg.ts" \\
  && ok "src/builder/svg.ts" \\
  || miss "missing critical file: src/builder/svg.ts"
test -f "src/text/index.ts" \\
  && ok "src/text/index.ts" \\
  || miss "missing critical file: src/text/index.ts"
test -f "src/handler/compute.ts" \\
  && ok "src/handler/compute.ts" \\
  || miss "missing critical file: src/handler/compute.ts"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 56 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~26d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/vercel/satori"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

📚Suggested reading order

Computed from the actual import graph (no LLM). Read in this order to learn the codebase from the foundation up — each step builds on the previous ones.

  1. src/vendor/parse-css-dimension/index.js — Foundation: doesn't import anything internally and is imported by 5 other files. Read first to learn the vocabulary.
  2. playground/utils/font.ts — Foundation: imported by 2, no internal dependencies of its own.
  3. playground/components/introduction.tsx — Built on the foundation; imported by 1 downstream file.
  4. playground/components/panel-resize-handle.tsx — Built on the foundation; imported by 1 downstream file.
  5. playground/pages/index.tsx — Layer 2 — application-level code that wires the lower layers together.

Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Embed this chat in your README →

Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.

<iframe
  src="https://repopilot.app/embed/vercel/satori"
  width="100%" height="500"
  style="border:1px solid #d0d7de; border-radius:8px;"
  allow="microphone"
  loading="lazy"
></iframe>