Running Storybook
lines with the name field from the target app’s package.json. For example, if you’re working on a cluster game, use --filter=cluster.
For Windows users, you may need to add
cross-env to the storybook npm script in package.json:Three types of stories
1. COMPONENTS/<Component>/component
Tests a single Svelte component in complete isolation. Useful for components that accept props directly, like Symbol or Board.
Examples from the lines app:
COMPONENTS/Game/component— renders the full<Game />component including the loading screenCOMPONENTS/Symbol/component— renders<Symbol />with Storybook controls for stateCOMPONENTS/Symbol/symbols— renders all symbols in all states at once
ComponentsGame.stories.svelte and ComponentsSymbol.stories.svelte.
2. MODE_<GAME_MODE>/bookEvent/<TYPE>
Tests a single bookEvent in isolation. An Action button appears in the corner of the canvas. Clicking it runs playBookEvent() with the corresponding test data from the events file.
Examples:
MODE_BASE/bookEvent/reveal— spins the reels with a base game boardMODE_BASE/bookEvent/freeSpinTrigger— plays the scatter animation and free spin introMODE_BONUS/bookEvent/updateFreeSpin— updates the free spin counterMODE_BONUS/bookEvent/freeSpinEnd— plays the free spin outro and transition back
ⓘ Action is resolved ✅If this message does not appear, the bookEventHandler has not resolved — there is a bug to fix before continuing.
3. MODE_<GAME_MODE>/book/random
Tests a full game book — a complete sequence of bookEvents as the RGS would return them. The Action button runs playBookEvents() which plays each event in the book one after another using sequence().
On each click, a random book is selected from the corresponding *_books.ts data file. Keep clicking to cycle through different scenarios: no-win spins, small wins, big wins, bonus triggers.
Story file structure
Thelines app has these story files in apps/lines/src/stories/:
How to add a new story
Open the appropriateMode<GAME_MODE>BookEvent.stories.svelte file. The pattern is consistent across all story files:
<Story> block for your new event:
namebecomes the story path:MODE_BONUS/bookEvent/updateGlobalMultdatais the bookEvent object from the events fileactionis the function that runs when you click the Action buttonskipLoadingScreen: trueskips the asset loading screen for faster iteration
The Action button and resolution
The Action button is rendered byStoryGameTemplate from components-storybook. It calls the action function you provide in args.
For bookEvent stories, the action calls playBookEvent(data, context), which looks up the handler in bookEventHandlerMap by data.type and runs it.
For book stories, the action calls playBookEvents(book), which runs each event in the book’s events array in sequence using sequence() — one after another, not all at once.
The ⓘ Action is resolved ✅ message appears when the action Promise resolves. For complex bookEvents with animations, this happens after all broadcastAsync calls have completed.
Best practices
- Build the story first, then implement the handler. The story gives you immediate feedback.
- Use
COMPONENTS/<Component>/componentstories for pure visual testing of a component’s props. - Use
MODE_<GAME_MODE>/bookEvent/<TYPE>stories during development to verify each bookEvent works. - Use
MODE_<GAME_MODE>/book/randomstories as the final integration test before marking a feature done. - If a component is hard to debug through emitterEvents, create a
COMPONENTS/<Component>/emitterEventstory that sends a single emitterEvent directly via controls.
