claude-code-system-prompts/system-prompts/skill-design-sync-storybook-source-shape.md
2026-06-05 14:54:12 -06:00

8.9 KiB

Storybook source shape

.storybook/ found — the repo's own Storybook is the preview source. The converter ships storybook-static/ as _sb/ and each preview card is an iframe grid of _sb/iframe.html?id=<storyId>, so whatever renders in their Storybook renders here verbatim (their builder's CSS, addons, and providers apply as-is).

Requires React 18+.

2. Build, then run the converter

  1. Build the DS package and its workspace dependencies. The converter bundles dist/ into window.<Global>. Run <pm> run build; in a monorepo use turbo run build --filter=<pkg> or pnpm -F "<pkg>..." build (the trailing ... is required — bare -F <pkg> skips dependencies and you'll see Cannot find module '@scope/tokens'). If package.json module/exports['.'] points at TS source, find the actual built entry and pass it via --entry. Do this before step 2 — storybook often imports sibling packages from their built dist/, so building storybook first fails with Failed to resolve entry for <pkg>.

  2. Build Storybook directly into ds-bundle/_sb/. Run npx storybook build -c <storybookConfigDir> -o ds-bundle/_sbnot the repo's npm run build-storybook script (that writes to ./storybook-static/ or wherever the script's own -o points, and the converter then exits with [SB_MISSING]). If you've already built to ./storybook-static/, either cp -r storybook-static ds-bundle/_sb or pass --storybook-static storybook-static to the converter. Check ds-bundle/_sb/iframe.html exists and is >10KB — index.json alone can exist with a failed build.

  3. Write design-sync.config.json — only pkg and globalName required. If it already exists, read it first and keep what's there — add or update fields, but don't drop prior entries unless you've confirmed they're stale. Also Read .design-sync/NOTES.md (or whatever cfg.notes points at) — it holds repo-specific gotchas a prior sync recorded. Commit both.

    Field Value
    pkg / globalName package name and the window.* global — required
    buildCmd the DS build command — Claude re-runs this before the converter on re-sync
    entry explicit dist entry if package.json doesn't point at it
    extraEntries package names/subpaths to merge into window.<Global> (icon package, <pkg>/experimental, etc.)
    titleMap {title: ExportName} when story titles don't match export names
    docsDir / docsMap / guidelinesGlob per-component docs + design guidelines
    extraFonts @font-face css or .woff2 files when [FONT_MISSING] fires
    replaces extends the adherence-config raw-element map
    notes path to a notes file — default ./.design-sync/NOTES.md

    .design-sync/NOTES.md is where repo-specific quirks live that don't map to a config field. Append a bullet whenever the user tells you about an issue or you learn something during the self-heal loop, so the next sync picks it up.

  4. Run the converter. Stage the scripts into .ds-sync/ (NOT the repo root — some repos have their own storybook/ dir that would collide). Install converter deps isolated in .ds-sync/node_modules so the repo's lockfile and package manager are untouched:

mkdir -p .ds-sync && cp -r "<skill-base-dir>"/lib "<skill-base-dir>"/storybook .ds-sync/
echo '{"name":"ds-sync-deps","private":true}' > .ds-sync/package.json
(cd .ds-sync && npm i esbuild ts-morph @types/react playwright && npx playwright install chromium)
node .ds-sync/storybook/build.mjs --config design-sync.config.json --node-modules <pkg-node-modules> \
  --pkg-dir <pkg-dir> --out ./ds-bundle
node .ds-sync/storybook/validate.mjs ./ds-bundle

In a monorepo, point --node-modules at the DS package's own node_modules (where its react resolves), and --pkg-dir at the package dir — not the repo root. If all deps are already hoisted at repo root (ls node_modules/{esbuild,ts-morph,playwright} all exist), you can ln -sfn "$(pwd)/node_modules" .ds-sync/node_modules instead of the isolated npm i.

Run build and validate synchronously (foreground) and check each exit code. If chromium install fails, run npx playwright install-deps chromium first; if the environment can't install chromium, set DS_CHROMIUM_PATH=<path-to-system-chromium>.

3. Self-heal loop

Tag Symptom Fix
[SB_MISSING] no iframe.html / index.json in ds-bundle/_sb/ Run npx storybook build -c <dir> -o ds-bundle/_sb (NOT npm run build-storybook — wrong output dir). Or, if ./storybook-static/ already exists, re-run the converter with --storybook-static ./storybook-static. Check PIPESTATUS — the build can exit 0 with a broken output.
[NO_DIST] / [CONFIG] can't find <pkg>/package.json package not built or not found Run the DS build. In the DS's own source repo, --pkg-dir usually needs to point at the built output (e.g. ./dist) where package.json + .d.ts have the published layout, with --entry ./dist/<esm-entry>.
[BUILD_OOM] / JavaScript heap out of memory large monorepo or many type files Retry with NODE_OPTIONS=--max-old-space-size=8192 node .ds-sync/storybook/build.mjs ….
[ZERO_MATCH] no story titles matched an export Check titleMap — titles should resolve to export names.
[TITLE_UNMAPPED] N titles didn't match Add cfg.titleMap entries.
[BUNDLE_EXPORT] N components aren't functions on window.<Global> Check extraEntries for subpath exports; check the dist entry is the full build.
[SCHEDULER_MISSING] DS dist/ imports scheduler directly Usually means react-dom leaked into the DS's compiled dist (it should be a peer dep). Check the DS build's external config.
[PNPM_SELF_PROVISION] packageManager: pnpm@X tries to auto-install and fails Corepack: set COREPACK_ENABLE_STRICT=0 (use system pnpm). npm's own provisioning: npm_config_manage_package_manager_versions=false. Retry.
[FONT_MISSING] <family> referenced in styles.css but no @font-face ships it Check .storybook/preview-head.html for a <link> to a font CDN (host-provided). Either accept system-font substitutes, or add via cfg.extraFonts: [".../X.css"] (a @font-face stylesheet) or a .woff2 path + a matching @font-face in a separate extraFonts .css.
[BUNDLE_MOUNT] first component threw on mount Usually the provider needs a required prop (theme, locale, etc.). Set cfg.provider with props: {"component": "<Provider>", "props": {"theme": {...}}}. For a chain, nest via "inner": {...}.
[BUNDLE_STYLE] rendered but no styling reached the element For CSS-in-JS DSes this usually means the provider wrapper isn't passing a theme — set cfg.provider with the theme prop the DS expects. Otherwise check styles.css has @import './_ds_bundle.css' + the storybook-static CSS concat.
[NO_CHROMIUM] playwright not installed Degraded — .prompt.md has no argTypes table and provider isn't auto-detected. Set cfg.provider manually if the DS needs one.
[TOKENS_MISSING] styles.css has no custom properties Informational — CSS-in-JS DSes may have none.
[IFRAME_LOAD] first preview iframe didn't render _sb/iframe.html failed to load a story. Open it in a browser; check for missing _sb/ assets the strip dropped.
[SB_SIZE] _sb/ >50MB Consider excluding dev/playground/kitchen-sink stories from the storybook config's stories glob.
[PROVIDER_DETECTED] <Chain> Informational — written to config + README so the design agent wraps output the same way.

4. Upload

DesignSync(finalize_plan) with localDir: "./ds-bundle", writes: ["components/**", "_sb/**", "_vendor/**", "guidelines/**", "fonts/**", "_ds_bundle.js", "_ds_bundle.css", "styles.css", "README.md", "_ds_needs_recompile"], deletes: []. Dot-prefixed entries stay local.

As the first write after plan approval, DesignSync(write_files, [{path: "_ds_needs_recompile", localPath: "_ds_needs_recompile"}]) — build.mjs writes this file ({"by":"design-sync-cli"}); uploading it first fences the app's manifest/copy machinery against a half-uploaded state. Then upload everything else (chunked into ≤256-file write_files calls under the same planId). After all other uploads complete, write the sentinel again to re-arm the recompile in case the project was opened mid-sync.

When done, tell the user: the project URL, component count, _sb/ size, and that validate exited clean. Commit design-sync.config.json and .design-sync/NOTES.md.

What this is not

Not an LLM rewriting components. The previews are the repo's own Storybook verbatim; the bundle is their compiled dist/.