Balance fixes:
- Discord scene 1: normal → let (was 0% success)
- Angel scene 4: svaert → normal (too hard for kids)
- Rarity scene 4: normal → svaert (was 100% win)
- Apple scene 1, Twilight scene 1, Angel scene 1: let → normal
- Overall win rate: 47% (target 40-60%)
Frontend improvements:
- Encouraging failure narration for kids
- Stats dashboard page with backend integration
- Stats button on home page
- API loadStats() function
Evaluation:
- Exhaustive mode: all 32 pony×theme combos
- Per-scene success rate tracking
- JSON output for automated analysis
- Add game_stats table: pony_type, tema, successes, failures, victory, dice rolls
- Record stats automatically when a game finishes (via /api/kast or /api/interact)
- New GET /api/stats endpoint: total games, win rate, by pony type, by tema, recent games
- Stats include: total_games, total_victories, win_rate, by_pony_type, by_tema, recent_games
Played a full game through end-to-end via Playwright (theme select, all
5 interaction types: dice/choice/color/dice/memory, game-end recap) to
find real bugs rather than guessing. The game itself held up well —
history recap correctly shows/hides dice per entry, scores and the
victory/mixed/defeat text all matched expectations, no console errors
or failed requests during a clean run.
One real latent bug found by reading the code: `numDice={dice?.length ||
2}` falls back to 2 for ANY falsy length, including a legitimate 0 (an
empty dice array, which is what choice/color/memory scenes send). It's
currently dead in practice — both call sites already guard with
`!!item.dice?.length` before rendering DiceRoll at all — but that's a
fragile invariant to rely on silently. Switched to `??` so a real empty
array is preserved instead of being coerced to a fake 2-dice default.
(The one transient issue seen mid-playthrough -- four /api/tts 503s --
turned out to be a backend restart happening concurrently with the test,
not reproducible: 5 concurrent + several sequential /api/tts calls
afterward all succeeded cleanly.)
71/71 tests passing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Did a real browser QA pass against the deployed site (Playwright, not just
isolated HTML harnesses) and found two actual bugs the harness-based checks
couldn't catch:
- FloatingBg/Sparkles are `position: fixed` full-viewport layers with
z-index: 1, while page content like .pony-card only has z-index: auto.
Per CSS stacking rules a positioned z-index:1 sibling paints above
z-index:auto content regardless of DOM order, so the floating ponies were
rendering on top of / poking through the theme-select cards. Changed both
to z-index: -1 so they reliably sit behind all normal content.
- COLOR_OPTIONS' hue-rotate values were tuned against the wrong baseline hue:
base.png's actual body hue is ~0deg (red), but e.g. "Blå" (blue) used
hue-rotate(150deg), landing on ~150deg = green, and "Lilla" (purple) used
220deg, landing on ~220deg = blue. Recalibrated all rotations against the
real measured base hue so picking a color now actually produces that
color on the body. Verified before/after with a side-by-side render of
all 8 colors, then confirmed live against the deployed site (clicking
"Kropsfarve: Blå" now visibly turns the body blue, not green).
67/67 tests still passing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FloatingBg previously scattered 8 random emoji (rainbow, butterfly, flower,
balloon, ...) around every page. Replaced them with 8 small PixelPonySprite
instances, each a distinct look (different mane style, body/mane/tail color,
some with a horn or wings), reusing the same drift positions and animation.
Verified the color-filter variety visually via a standalone HTML/CSS render
(same layering logic as PixelPonySprite) since the app's sound-prompt gate
blocks a plain headless screenshot of the real page.
67/67 frontend tests passing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Analyzed every file across all three folders of the source "Pixel Ponies"
pack (NES Style/, root, 32x32/ -- 143 files total) via three parallel
agents, each instructed to actually render and look at every file rather
than infer content from filename (the lesson from the earlier mane/eye-icon
mixup). Findings written to web/app/data/pixel_assets.py, following the
themes.py/pony.py data-module convention:
- NES_STYLE_ASSETS: confirms the 9 "personality" files really are eye-icon
glyphs (not hair), and that unicorn horn.png/pegasus wing.png really are
just alignment-marker dots -- plus a new find: ponyville.png (same 256x256
canvas as the pose sheets) is actually an unused town tileset + a strip of
achievement-style icon badges.
- ROOT_ASSETS: 45 files, mostly mislabeled or incompatible (e.g. pegasus.png
depicts a wolf-like creature with no wings; several "fly*" frames are
blank; one has a hidden low-opacity watermark) -- 14 flagged usable.
- GRID_32_SURVEY: the 76-file scraped collection surveyed by category (not
usable as-is -- different, more detailed art style than the game's own
sprites).
Cropped 9 icon badges (apple/book/heart/horseshoe/hourglass/potion/sparkle/
tree/trophy) from ponyville.png's icon strip into
pony-frontend/public/sprites/scenes/, and mapped 8 of them to the game's 8
adventure themes by actual story content (book -> Twilight's missing book,
heart -> Fluttershy's rabbit, apple -> the apple harvest, sparkle -> Rarity's
gem and Luna's stars, etc. -- see SCENE_ICONS in pixel_assets.py). Backend
now returns "icon" on each theme from /api/content and "themeIcon" on scene
data; frontend shows the pixel icon on theme-select cards and next to the
theme title during gameplay.
74 backend + 65 frontend tests passing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Horn/wings choices were free-standing toggles independent of the chosen
pony type, so e.g. a Jordpony (which has neither in the game's own lore/
stats) could still be given a horn or wings in the configurator.
Wizard steps are now computed from the selected type's hasHorn/hasWings
flags: Jordpony gets 5 steps (type/body/eyes/mane/tail, no horn or wings
step at all), Pegasus 6 (+wings), Enhjørning 6 (+horn), Alicorn 7 (+both).
appearance.hasHorn/hasWings are set directly from the type on pick and are
no longer separately toggleable — the on/off buttons are gone since the
type alone decides whether they exist.
App.test.js's pickPonyAndStartGame helper now clicks "Næste" until "Start
eventyr" appears rather than a fixed count, since step count depends on
which pony type the test picks.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- wing-folded.png/wing-spread.png were drawn in near-white/gray (sat ~0-5%).
The color system recolors via CSS hue-rotate, which has no effect on
desaturated pixels — so every wing color choice looked identical.
Redrew both in a saturated warm tone (~30% sat) so hue-rotate actually
shifts the visible color.
- Tail/horn/eye/wing are flat single-frame overlays with no walk-cycle
frames of their own, so they sat frozen in place while the base/mane
layers bobbed between idle frames — most noticeable on the tail, which
looked static against the moving legs. Added a small synced translate
on the second idle frame so the tail swishes along with the bob.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 9 of the 17 "mane" files (dramatic/fabulous/inquisitive/intelligent/
perky/friendly/practical/stoic/tough) turned out to be small eye/
expression icon glyphs, not hair art, when actually rendered — visually
confirmed via headless-Chrome screenshot of every file's idle frame.
Removed them from MANE_STYLES; 8 real hairstyles remain.
- Searched the full source asset pack (not just the curated "NES Style"
folder) for additional tail art per user feedback that there should be
several tails to choose from — the only other "*tail*" file found
("feisty tail.png") turned out to be the same kind of mismarked eye-icon
sheet, not tail art either. Since no usable multi-style tail/horn/wing
art exists in the pack, hand-drew 3 tail shapes, 3 horn shapes, and 2
wing shapes as flat overlays (same technique as the original single
hand-drawn accents).
- Horn and wings now each get their own wizard step (style grid + own
color row), with an on/off toggle gating the pickers — previously they
were crammed into one shared "extras" step with no style choice at all.
- Wizard is now: type -> body -> eyes -> mane -> tail -> horn -> wings
(7 steps). PixelPonySprite gained Tail/Horn/WingIcon isolated-preview
exports mirroring the existing ManeIcon pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Wings were drawn *behind* the base body layer, so anything overlapping
the torso silhouette was invisible — only a sliver peeked out. Redrew
the wing art and moved it above the base layer so it visibly sits on
the pony's back/spine instead.
- Eyes were baked into base.png and tinted by the body-color filter
(so a blue pony got blue-tinted eyes). Extracted the eye pixels into
their own flat overlay (eye.png) drawn on top with an independent
eyeColor filter, and added a dedicated "Vælg øjenfarve" step.
- Split tail color from mane color (was tied to maneColor) and added its
own "Vælg halefarve" step, isolated to just a color row like the other
single-purpose steps.
- Wizard is now: type -> body -> eyes -> mane -> tail -> extras (6 steps).
Note: App.test.js in this commit also carries test additions from the
concurrently running agent (pixelpony image role, progressbar, game-controls
class assertions) — see prior commit note; same shared-working-tree
situation, verified via the full 62/62 passing suite before commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Reorder wizard: type -> body color -> mane (style + color) -> horn/wings.
Body color now comes right after picking a type, per feedback that the
flow should start with krop rather than manke.
- Mane-style swatches previously rendered a full mini pony (body + mane),
which read as "showing everything" instead of just the hairstyle. Added
ManeIcon, an isolated single-layer render of just the mane sprite, and
use it in the picker grid.
- Every pony now always has a tail (hasTail removed as a toggle) — a real
pony shouldn't be optionally tailless.
- Verified horn/wing/tail placement against the actual base sprite
silhouette with a standalone HTML+CSS harness rendered through headless
Chromium (identical background-image/position math to PixelPonySprite),
confirming the horn sits above the head, not mid-body.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the old single-screen pony-type select with a 4-step wizard:
type -> mane -> colors -> tail/horn/wings, ending in "Start eventyr!"
which starts the game with the chosen type. PonySelectPage is removed;
the wizard is now the 'start' page.
- Fix a real bug: the source sprite pack's horn.png/wing.png sheets turned
out to be 1-3px alignment markers, not visible art, so toggling
horn/wings previously had no visible effect. Replaced with hand-drawn
flat overlay sprites (horn, wing, tail) positioned against the base
sprite's actual silhouette.
- Add a dedicated tail toggle/layer (the pack has no separate tail art
either), using the same hand-drawn-overlay approach.
- Update PixelPonySprite to support flat single-frame overlays alongside
the existing 8x8 sheet layers.
- Rewrite App.test.js flow helpers and PixelPonyConfiguratorPage tests for
the new step-based flow (58 frontend tests passing).
Note: App.js/App.test.js in this commit also carry in-flight
interaction-choice plumbing (handleInteraction/CHOICE_SCENE) from a
concurrently running agent in this same working tree — left as-is since
splitting it out isn't possible without touching files that agent still
has in progress, and the combined state passes the full test suite.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a "Design din Pony" entry point on the home page and a
pixelConfigurator route in App.js so the pixel-art configurator
(added in c19c8af) is actually reachable from the UI.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>