In brief
The frontend's job is to present an authoritative round faithfully. Preserve the contract between math events and animation while you change the visual design. A smooth spin with the wrong total is a failed implementation.
- Start with a known outcome, not random visual behavior.
- Separate game-event handlers from individual animation components.
- Await animations that must finish before the next state transition.
Find the files that matter
The official frontend file-structure guide describes a monorepo with sample apps and shared packages. In the lines app, start with the route entry, the game component and game context. Shared packages provide reusable UI, state and layout behavior; changing a shared component may affect more than one sample.
For the reference revision, these are useful places to inspect:
| Location | Why you open it |
|---|---|
apps/lines/src/components/Game.svelte |
Composition of the game screen |
apps/lines/src/game/assets.ts |
Loaded assets and aliases |
apps/lines/src/game/typesBookEvent.ts |
The event types the app understands |
apps/lines/src/game/bookEventHandlerMap.ts |
Translation from math events to presentation |
apps/lines/src/game/stateGame.svelte.ts |
Game presentation state |
apps/lines/src/stories/ |
Repeatable isolated scenarios |
Inspect the actual tree in your revision before editing. A tutorial filename is a map, not permission to create a second, disconnected implementation when the existing one has moved.
Follow one event through the application
The pinned handler map handles events including reveal, winInfo, setTotalWin, bonus transitions and free-spin updates. A reveal drives the board; win information identifies paying positions; total updates carry the amount to present.
Use that sequence to debug. If the board is wrong, first inspect the received board and coordinate mapping. If the highlighted symbols are wrong, compare win positions. If the displayed total is wrong, inspect the amount conversion and the state receiving the total. Do not compensate for one bug by inventing another total in a component.
An animation event is not necessarily a new financial event. A coin shower, label bounce or camera movement can illustrate an already-known result without generating another payout.
Add a custom event deliberately
Suppose Harbor Signals needs a lighthouse pulse when a round-specific multiplier activates. First write a small example of the math event and its meaning. Specify when it occurs, what fields it carries and whether it changes the payout or merely announces a state that has already changed.
Then update the math emitter, the frontend event type, the handler, the presentation component and a deterministic story. Keep the payout calculation in math. The frontend can display the multiplier and animate it; it must not silently multiply the authoritative final total again.
If an event must finish before the board advances, its handler needs a completion signal. A fire-and-forget animation can leave a stale overlay covering the next round. Conversely, awaiting a callback that never arrives can lock the game. Test cancellation, skip and reduced-motion paths as well as normal completion.
Responsive means reorganizing, not shrinking everything
Design the board, controls, help panel and purchase dialog as separate layout responsibilities. On a narrow portrait screen, stack a mode description above its action instead of squeezing the price into a tiny side column. Preserve the board's proportions; allow supporting text to wrap.
Use real short and long labels in layout tests. Check a large currency amount, a translated button and a multi-line error. The layout that looks balanced with “Buy” may fail with a longer localization. Make the inactive, loading and insufficient-balance states equally legible.
These layout recommendations are our engineering approach. The official frontend requirements additionally require usable mobile and mini-player layouts, accessible game information and clear payout communication.
Build a replay set before adding polish
Keep stories for a loss, ordinary win, larger win, bonus entry, bonus end, interrupted round and a long label. Reuse the same outcome IDs after a reskin so you can compare old and new presentation without changing the underlying result.
For each replay, verify the start state, event order, final displayed amount and return to an actionable UI. Play it twice. Leaking listeners or leaving state behind often becomes visible only on the second run.
Avoid debugging only through the local single-HTML package. Source-level Storybook and the standard app build give clearer boundaries. A standalone packaging change can introduce unrelated asset-path or authentication behavior.
Finish this part
You should have one complete round whose data, animation and final amount match, plus a small replay set that survives repeated execution. That stable baseline is the right time to begin the full visual reskin.
