Skip to content

About

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

saas-design — Figma → site + design system, end to end

A viability check for a fully generated front-end pipeline. One local Figma file (.fig) becomes:

  • apps/site: a static copy of the Figma landing page, rendered with Go templ (exported to plain HTML).
  • apps/design-svelte: a Svelte 5 / SvelteKit design-system app with foundations, primitives, components, widgets and every block.
  • apps/design-react: the same design-system app in React 19 (Vite SSR + static prerender), page for page.
  • All three use the same tokens, semantic CSS, primitives and blocks, generated by @ui8kit/codegen 2.0 from one source per layer. Parity tests check that the three runtimes give identical DOM/ARIA. The two design apps share their content through packages/design-docs, and their prerendered pages are compared DOM for DOM.

Everything between the .fig and the deployed apps is a script in this repo or a pinned public tool. bun run check fails if any generated file drifts from its source.

Developers: start with Quickstart. AI agents: read AGENTS.md first.

Screenshots

Figma (left) vs generated site (right), hero at 1440px
Figma vs site, hero
Site, light Site, dark Site, 390px menu (Sheet)
site light site dark site mobile menu
Design app (Svelte), light Design app (Svelte), dark Design app (Svelte), 390px nav (Sheet)
design light design dark design mobile menu
Design app (React), light Design app (React), dark Design app (React), 390px
design-react light design-react dark design-react mobile

Full-size screenshots, per-section Figma/site pairs and a report.json with height deltas are produced by bun run shots. They are written outside the repo, to /workspace/shots-saas/ (see docs/checks.md).

Pipeline

flowchart LR
  fig[".fig file<br/>(outside the repo)"] -->|"bun run extract<br/>fig2design parse"| figma["fixtures/figma<br/>frames, variables, images"]
  figma -->|"bun run tokens<br/>+ fixtures/tokens/mapping.json"| tokens["shadcn HSL tokens<br/>packages/tokens/theme.css<br/>+ app brand.css"]
  tokens -->|"bun run brand:emit / brand:check"| brandos["brand-os bundle<br/>fixtures/tokens/brand.generated"]
  figma -->|"bun run content"| records["@ui8kit/contract records<br/>fixtures/content/records"]
  records -->|"bun tools/views.ts"| views["view models<br/>fixtures/views/*.json"]
  recipes["codegen 2.0 specs<br/>+ packages/ui/recipes overrides"] -->|"@ui8kit/codegen 2.0 (xgen)"| ui["packages/ui<br/>templ + Svelte 5 + React 19"]
  ui --> adapter["packages/adapter<br/>ui-* classes, @apply only"]
  defs["block DSL<br/>packages/blocks/defs"] -->|"packages/blocks generate"| blocks["packages/blocks<br/>templ + Svelte 5 + React 19"]
  blocks --> adapter
  tokens --> adapter
  views --> site["apps/site<br/>Go templ → static HTML"]
  views --> design["apps/design-svelte<br/>SvelteKit static"]
  views --> designr["apps/design-react<br/>Vite SSR → static"]
  blocks --> site
  blocks --> design
  blocks --> designr
  adapter --> site
  adapter --> design
  adapter --> designr
  site --> check["bun run check<br/>drift, contract, parity, ui8px, lint-apps, builds"]
  design --> check
  designr --> check
  check --> shots["bun run shots / shots:modes<br/>Figma vs site screenshots"]
  shots --> vercel["Vercel<br/>three projects"]
Loading

Layer details: docs/architecture.md.

Tools used

Tool Role here Version used
fig2design (source not public; docs/figma-parser.md) Parses .fig offline into a JSON dump 0.1.0 via npx
@ui8kit/contract (source) Content record schemas + validator 0.2.0 (devDependency)
ui8kit/codegen 2.0 (@ui8kit/codegen, xgen) Brick specs (40 bricks, 72 parts) + emitters for templ, Svelte 5, React 19, Vue 3, Solid, Twig, Latte, Jinja2; its rules detectors drive tools/lint-apps.ts. This repo uses templ, Svelte and React github:ui8kit/codegen#2309848 (tag v0.1.0 = 972b492, the 0.1 line this repo used before)
ui8px (source) Lints utilities (8+4 grid, token colors, no arbitrary values) ui8px@latest via npx
brand-os (source) Brand token contract emit/validate/verify 0.3.0 via npx
templ Go HTML templates v0.3.1070, always via go run …@v0.3.1070
Tailwind CSS v4 Compiles @apply rules (source(none), no content scanning) 4

Repository structure

.cursor/rules/          agent rules (*.mdc): pipeline, grid, tokens, adapter, blocks + retag, contract, git, dark mode, sheet
.cursor/skills/         figma-to-site skill (agent workflow)
.manual/                short command-by-command manual (00–09)
.project/STATUS.md      deliverable status; .project/backlog/ = one file per tool problem
.ui8px/policy/          generated ui8px lint policy (bun tools/ui8px-policy.ts)
docs/                   English guides (this README links them), docs/learn/ (ordered lessons), docs/assets screenshots
fixtures/
  figma/                fig2design dump (generated by `bun run extract`)
  tokens/               mapping.json (hand-edited role decisions) → tokens.json, palette.json, brand contract/bundle
  content/source/       authored content that is not in Figma (FAQ answers, showcase data)
  content/records/      @ui8kit/contract records (generated by `bun run content`)
  views/                view models for both runtimes (generated by `bun tools/views.ts`)
  media/                vector assets extracted from the frame
packages/
  tokens/theme.css      shadcn HSL tokens, light + dark, dark variant, layout theme vars (generated)
  adapter/src/          base.css (hand-written) + primitives/blocks *.generated.css: ui-* classes, @apply only
  ui/                   recipes/*.variants.json (overrides of the codegen 2.0 recipes), scripts/ (registry, generate,
                        showcase, parity), behaviors/ (vanilla JS), generated templ/ + svelte/ + react/; .xgen = pinned codegen
  icons/                lucide subset + brand mark → Go icons.Icon, Svelte Icon.svelte, React Icon
  blocks/               defs/ (block DSL) → generated templ/ + svelte/ + react/ + catalog.json
  design-docs/          framework-neutral docs content of the design apps: nav, block data, foundation scales,
                        ds-* stylesheet, foundations CSS generator (output goes into each app: it uses brand colors)
apps/                   exactly three apps
  site/                 Go: views/layout.templ, cmd/export (static export), scripts/build.sh, vercel.json
  design-svelte/        SvelteKit: src/routes, src/lib (frame, Section, Showcase), vercel.json
  design-react/         React 19: src/pages, src/components, scripts/build.mjs (Vite SSR + prerender), vercel.json
tools/                  generators, checks, screenshot and measuring scripts (bun/TS, bash)

Quickstart

Prerequisites

Tool Version Tested here
Bun ≥ 1.2 1.4.2
Node.js ≥ 20 (npx for fig2design, ui8px, brand-os, Tailwind CLI) 20.19.2
Go ≥ 1.23 (go.mod) 1.27.2
templ v0.3.1070, pinned through go run, nothing to install —
Google Chrome for screenshots and behaviour tests only (/usr/bin/google-chrome, or CHROME=/path) —

Install and verify

git clone https://github.com/ui8kit/saas-design && cd saas-design
bun install
bun run check            # must end with "all checks passed"

Extract a Figma file (optional; the dump is committed)

The .fig must live outside the repo. tools/extract.sh refuses a path inside it, and *.fig is git-ignored.

FIG=/absolute/path/outside/repo/file.fig bun run extract
# runs, from /tmp:  npx -y fig2design@0.1.0 parse "$FIG" --out fixtures/figma --no-config

The variable is FIG; without it the default is /workspace/fig-fixtures/saas.fig. Then regenerate and re-check with the pipeline in AGENTS.md. For a different Figma file, follow docs/replicate-with-new-figma.md.

Run the apps

# site (Go templ → static HTML in apps/site/public)
bun run site:build                         # = bash apps/site/scripts/build.sh
(cd apps/site && bun run serve)            # npx -y serve@14 public -l 4173 → http://localhost:4173

# design system app (SvelteKit)
(cd apps/design-svelte && bun run dev)            # vite dev → http://localhost:5173
bun run design-svelte:build                       # → apps/design-svelte/build (50 prerendered pages)

# design system app (React 19)
bun run design-react:build                        # → apps/design-react/build (50 prerendered pages)
(cd apps/design-react && bun run preview)         # vite preview of build/

Other runtimes

@ui8kit/codegen 2.0 also emits Vue 3, Solid, Twig, Latte and Jinja2. This repo wires templ, Svelte and React. docs/add-a-runtime.md walks through how React was added, as the recipe for the next runtime.

Use it with an AI agent

The repo is written so that an AI coding agent can repeat the result. Point the agent at the repo and ask in plain words. It should read AGENTS.md first; the guides it needs are docs/replicate-with-new-figma.md (another design) and docs/add-a-runtime.md (another framework).

Example prompts:

  • You like this design but want React / Next.js:

    "I want a restaurant website in this same design, on React. Build it in apps/resta."

  • You found another great Figma design:

    "Study this repo and build me a site and a design system for this design, on Vue. The .fig is at /path/outside/the/repo/design.fig."

  • Same design, different content:

    "Keep this design, but turn the landing page into a fitness-coach site. Change the copy and images through the fixtures, not the components."

  • Another page in the same system:

    "Add a pricing page and a blog index to apps/site, reusing the existing blocks."

Note: this repo has three runtimes, Go templ (apps/site), Svelte 5 (apps/design-svelte) and React 19 (apps/design-react), kept in parity. If you don't need both, say so up front, e.g. "I want React only" (or "Vue only", "Svelte only"). The agent then drops the other runtimes' outputs, apps and checks instead of keeping them in sync. How each request is interpreted: AGENTS.md → How to interpret common requests.

Documentation

Doc For
docs/learn/ Reference tutorial: ten ordered lessons, from tokens to deploy, linking the real files
AGENTS.md AI agents: rules, pipeline order, definition of done
docs/architecture.md Layers, data flow, why the adapter layer exists
docs/design-settings.md Habitus corners, spacing rhythm and control sizes on codegen 2.0, with Figma measurements
docs/replicate-with-new-figma.md Repeating this with another .fig
docs/add-a-runtime.md Adding Vue, Solid, Twig/Latte/Jinja2 (how React was added)
docs/checks.md Every check, what it verifies, how to fix failures
docs/deploy-vercel.md Three Vercel projects from one repo
docs/troubleshooting.md Known gaps and fixes (links into .project/backlog)
CONTRIBUTING.md Commit rules, how to propose changes
.manual/ Terse command manual

Status

See .project/STATUS.md. In short:

  • All checks are green, with 0 mismatches in every parity check: primitives templ/Svelte/React, blocks Svelte/React vs templ, and the design apps React vs Svelte. The app-level retag lint reports 0 blocking findings.
  • The site is within 11px of the Figma page height (6277 vs 6288px); see docs/design-settings.md.
  • Dark mode and mobile Sheet navigation work in all three apps.
  • Deploys: all three apps deploy on Vercel on every push to main, at saas-svelte.vercel.app and saas-react.vercel.app, plus the saas-templ site (docs/deploy-vercel.md).

Design credit and license

The source design is Habitus — Habit Tracker App Landing Page on Figma Community, by @olgaaverchenko. All visual design credit goes to them; this repo only re-implements it to test the pipeline. The .fig file is not redistributed here.

The design and design-derived assets are licensed under CC BY 4.0. That covers fixtures/figma images/exports, fixtures/media artwork, design copy in fixtures, and the docs/assets screenshots. The attribution requirements and the full list are in LICENSE-DESIGN.md.

License

  • Code: MIT, © 2026 UI8Kit.
  • Design and design-derived assets: CC BY 4.0. See Design credit and license and LICENSE-DESIGN.md.
  • The upstream tools (fig2design, @ui8kit/contract, ui8kit/codegen, ui8px, brand-os) are MIT-licensed according to their npm metadata.

About

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages