PixiJSTypeScriptCanvas 2DGSAPWeb AudioVitest
Керування
- Wheel: tap Spin or press Space or Enter, or drag and flick the wheel by hand
- Scratch: rub the gold foil with a finger or the mouse; Reveal all (or Space) lifts it at once
- Daily drop: tap today's box or press Open box; the demo date arrows move the campaign day so every box can be tried
- Keys 1, 2 and 3 switch games; the arrow keys move between the tabs; Escape closes the prize card
- How odds work shows the live odds sheet; Campaign editor renames prizes and changes weights and colours, and the wheel repaints live
- Add ?seed=7 to the address for a repeatable run, or ?mode=scratch or ?mode=advent to open a game directly
Needs WebGL. Without it the poster is shown. Respects the reduced-motion setting: the wheel jumps to the result with a short fade, the foil comes off with one tap, boxes open without movement and there is no confetti. Sound is off until you turn it on. Plays, stock, edits and the report are saved in this browser. Portfolio demo: no real prizes, nothing is sent.
Як це зроблено
A gamified promo kit for Crumb & Co., a fictional bakery and coffee chain running an autumn campaign: a wheel of fortune, a scratch card and a daily-drop advent calendar on one page, plus the tools a marketing team would ask for (an odds sheet, a campaign editor and a report). Portfolio demo: the coupons are made up, nothing is sent or stored outside this browser.
How it's built
- Campaign logic as a "server".
core/ is plain TypeScript with no PixiJS imports: a weighted prize table with stock limits, a seeded RNG (mulberry32, ?seed= for repeatable runs), daily play limits per mechanic, a coupon generator and a small typed state machine (idle, playing, result) per mechanic. One call, play(campaign, mechanic, rng), checks the limit, draws the prize, takes stock and issues the code; the client only acts the result out. A real campaign would run this on a server. - Odds. Sold-out prizes drop out of the draw and the remaining weights scale up; the "How odds work" dialog shows the live sheet for the wheel and card and for the daily boxes, which never come up empty. Unit tests draw a million times and check every prize within 0.2 points of its listed chance, run 20,000 plays to prove stock never goes below zero, and check limits, storage parsing and the editor bounds.
- Coupons look like
CRUMB-XXXX-XXXX from a 32-character alphabet without 0/O and 1/I. The last character is a Luhn mod N check digit; a test confirms every single-character typo is rejected. - Wheel. The prize is drawn first, then
planSpin works out a slow-down curve (angle = travel x (1 - (1 - t)^2.6)) whose starting speed matches the flick or button press and whose end lands inside the drawn segment, between 3 and 6.5 seconds and at least three turns. Sometimes the stop is placed one peg short of a big prize. Pegs kick a sprung leather flapper, bulbs chase with the speed and a faint ghost copy of the wheel gives motion blur. After the stop the last peg pushes the wheel back a fraction, never across a segment edge. The wheel can be dragged and flicked in either direction. - Scratch card. The foil is a PixiJS render texture; the pointer stamps circles into it with the erase blend mode, interpolated along the stroke. How much is gone is tracked on a 28 x 28 grid in card space instead of reading pixels back; past 55% the rest lifts by itself. The nine cells are only drawn when the first scratch starts the play, and the layout follows a three-match rule: exactly three of the prize on a win, never three of anything on a loss.
- Daily drop. Twelve pastry boxes, one per campaign day; today's box glows, past ones are stamped missed, future ones are locked. The demo date stepper moves the campaign day so every box (and fresh plays for the wheel and the card) can be tried.
- Art. Everything is painted with Canvas 2D at boot and handed to PixiJS as textures: the wheel face with curved labels, wood rim and brass pegs, the scalloped frame on its stand, bulbs, the flapper, eight prize illustrations (croissant, flat white, cookie, cinnamon bun, bean bag, discount tags, an empty plate), the ticket, the foil, the boxes, lids, tags and stamps. Every scene is laid out on a 600 x 600 board and scaled to fit, so the scratch texture never has to be rebuilt on resize. Fonts: Shrikhand, Caveat and Nunito, loaded only on this page.
- Everything readable is HTML in the same illustrated style: the hanging shop sign and tab boards, the chalkboard with the demo date, prize list and stock, the coupon ticket with Copy and a mock "Add to wallet", the odds dialog, the editor drawer and the till-receipt report (plays, wins, win rate, coupons used, conversion, wins by prize). A polite live region reads every result out; the canvas is hidden from screen readers.
- Campaign editor: rename prizes and wheel labels, change weights and colours; the wheel repaints live and the odds sheet follows. Plays, stock, edits and the report are saved in this browser; Reset demo starts the campaign over.
- Reduced motion: the wheel jumps to its result behind a short fade, a tap lifts the whole foil, boxes open without movement, and there is no confetti, flapper swing or bulb chase.
- Performance. Pixel ratio capped at 2, smaller textures on weak devices, particles are a capped sprite pool, and the ticker stops while the board is off screen or the tab is hidden. If the graphics context is lost, the poster covers the board.
- Sound is generated with Web Audio (no files) and off until turned on.