Thirty-three components in isolation
Adopting a zero-mock Storybook catalog for reusable Svelte components, defining the two-importer scope boundary, and enforcing story coverage in CI.
As the game’s UI expanded across three game modes, settings forms, and stats views, thirty-nine Svelte components had accumulated in the repository. Developing or verifying smaller UI pieces, from toggle switches and notice toasts to fruit chips and turn pickers, required booting the dev server and manually driving game state into the exact configuration to make each component appear. A wayfinder track decided to stand up a Storybook catalog using @storybook/sveltekit, creating an isolated environment where reusable components could be visually reviewed and exercised across their edge cases without live gameplay.
Rather than introducing heavy mocking layers or adopting non-standard community template formats, the catalog was built strictly around Component Story Format 3 (CSF3) in TypeScript. Each story imports the real Svelte component directly, styles it through the global design token stylesheet established in the redesign, and wires real runes stores and internationalization proxies without test doubles. For components taking Svelte 5 snippet children, stories use the imperative createRawSnippet API to supply realistic slot content, ensuring every story renders authentic production markup.
flowchart TD
accTitle: Storybook component scope boundary decision flow
accDescr: Flowchart illustrating how components are filtered by production import count to determine whether a Storybook story is required or carved out.
Component[Component in src/lib/components] --> CheckCarveOut{In Carve-Out List?}
CheckCarveOut -- Yes: Full-screen view --> CarvedOut[Carved Out: No Story Required]
CheckCarveOut -- No --> CountImports[git grep production imports]
CountImports --> Threshold{Importers >= 2?}
Threshold -- Yes --> Required[In Scope: Colocated *.stories.ts Required]
Threshold -- No --> Optional[Single-use: Optional / Out of Scope]Not every component belongs in an isolated component catalog. To keep the catalog focused and prevent maintenance overhead, a clear scope rule was established: any component imported by two or more distinct production callers qualifies for a story. Massive, full-screen composite containers, such as entire game boards, settings forms, and recap dialogs, were explicitly carved out in a dedicated scope configuration module. Applying this threshold surfaced thirty-three qualifying components, covering eighty-one named story exports across multiple languages and interactive states.
The catalog integrates @storybook/addon-vitest to run every story file as an automated headless browser test, catching runtime rendering errors and broken store bindings during unit test runs. While these story tests ran cleanly in the local devcontainer, the initial pull request hit a failure in GitHub Actions: the bare virtual machine runner lacked the Chromium binary needed by Playwright’s browser provider. Explicitly adding the browser installation step to the CI workflow aligned the remote runner with the containerized environment.
With thirty-three components documented and a CI gate blocking uncataloged reusable additions, the design system now has an enforced, living gallery. The next step is using the catalog to streamline responsive audits and verify future component refactors before they land in game routes.