Commit Graph

16 Commits

Author SHA1 Message Date
c74cb09324 Browse: no vertical scrollbar on the root shelves
The three shelf rows fit the screen, and each scrolls sideways on its own, so the
page around them no longer scrolls vertically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:43:06 +02:00
1da2274076 Pi profile: no glass blur, keep the drift; consolidate the perf knobs
With the ambient canvas off under ?pi=1, the backdrop blur no longer buys anything:
it paid for itself by giving each panel a compositing layer above the animating
canvas, and with nothing animating underneath it was just cost - enough to make the
browse rows visibly sluggish on the device. So the Pi profile now drops every backdrop
blur (`glassBlur`, which the music app and the typing game share), and turns the
drift and the moving mascot back on: plain CSS transform loops the compositor runs by
itself, which measured as noise.

The knob set is consolidated to match: one glass toggle instead of panel and card
blur, one shadows toggle for cards and tiles, the typing game's drift and view
transitions folded into the shared ones, and the backing-store cap fixed by profile
rather than a setting. The parent dialog groups them into Darstellung / Abspielen /
System and hides the canvas tuning while the canvas is off. Stored settings move to
musicmouse.perf.v2, since v1 drafts held the old preset in full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:19:06 +02:00
2a629faf50 Web frontend: switchable dolphin/dinosaur skins
Two kids, two looks: ?theme=dolphin or ?theme=dinosaur picks one, and the
choice is remembered in the browser so the installed home-screen app keeps it.
Everything that differs per child lives in one Skin object per file under
web/src/lib/skins/; layout and feature toggles in lib/theme.ts stay shared.
The dolphin renders pixel-identical to before.

The hardcoded sea hues (210 music, 175 typing game, 340 accent) are now CSS
variables written once at startup, and the Gecko-friendly sRGB gradient stops
come from the skin. The dinosaur is jungle green with a lava-orange accent,
its own mascot, icons, manifest and browser colour.

Nothing underwater is left in the dinosaur skin: leaves instead of bubbles
(play-view canvas, room page, typing game), a walking mascot, lava blobs in
the bubble game, a hatching egg instead of the treasure chest, dino pets that
walk or fly, a prehistoric speed ladder with the T-Rex as the hero rung, and
renamed games and light colours. Pets and ladder rungs are keyed by the
backend's existing ids, used as slots, so the backend and save format are
unchanged. Pets show as emoji until drawings exist.

python-backend/.gitignore: ignore tippen-curriculum-dino.yml, the dino
device's personal curriculum, like the original.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:05:41 +02:00
6981890be0 Web frontend: hide app title and row titles, regroup help sheet, drop Ctrl+d/u
- New SHOW_APP_TITLE switch (off): the mascot + title header goes, the status pill
  stays on a slim row of its own.
- SHOW_ROW_TITLES off; with only icons, the shelf icon moves into a column left of
  the tiles so an icon-only shelf is no taller than one without.
- Help sheet regrouped into sections in a compact two-column grid, and reachable
  from a small keyboard button (not on phones or the typing page).
- Ctrl+d/Ctrl+u half-page jumps removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:53:06 +02:00
0f08e1d16c Web frontend: touch layout for phones
Phones got the kiosk's keyboard-first layout squeezed down: shelves cut off
by the tab rail and a header taking a fifth of the screen. They now get
their own layout, chosen by a media query (narrow, or short landscape on a
touch screen); tablets and desktop are unchanged.

- Pick a group (Musik/Hörbücher/Podcasts), then a category, then scroll
  through a grid of smaller albums.
- A floating glass dock: mini player, Musik/Zimmer tabs (no typing tab - a
  phone has no keyboard for it) and a search button that turns into a real
  search field, raised above the on-screen keyboard.
- Album sheet and room page get compact phone variants.

Browse state stays in the shared UiState, so resizing or rotating keeps
your place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:33:26 +02:00
2db4368fc9 Web frontend: perf panel, cover warmup, incremental browse rendering
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 11:42:33 +02:00
cc3db44c4e Add a ?pi=1 profile, and stop re-deriving search keys per keystroke
Two separate costs, both measured on musicdolphin (Pi 4, 1920x1080 kiosk), where the
app was burning ~70% of a core with nothing happening on screen.

Per-frame work. The ambient canvas repaints a full-screen gradient plus a particle
field every frame, and `usePlaybackClock` pushes a React setState per animation frame
into both PlayView and PlayerBar for the whole length of a track. `?pi=1` (lib/
lowPower.ts) makes those cheaper rather than switching them off: the canvas paints a
quarter of the pixels at 30fps with a bubble cap, and the clock renders ten times a
second - a progress bar advances one pixel every few hundred ms and its label has
one-second resolution, so nothing on screen can tell. Only the effects with no cheap
version actually go: the backdrop-filter glass blur and the decorative CSS loops.
Also drops a redundant full-canvas clearRect that the opaque gradient always covered.

Search. normalize() runs a Unicode NFD decomposition, and albumMatches/songMatches
called it on every album title and every track title on every keystroke - 4969 of them
for a track search, whose answer cannot change until the library does. buildSearchIndex
does it once per library payload; a keystroke is now String.includes over strings that
already exist. On the real library that is 33ms -> 3.4ms for an eight-letter track
query on a laptop, and this runs on a Pi. The same index partitions albums by shelf and
pre-sorts each shelf's categories, which App and BrowseView were deriving separately
from the same data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 13:15:23 +02:00
b8f9f6d537 Give the tab rail its own glass bar and reserve space for it
The three tab buttons now share one frosted glass pill instead of each
floating separately, and BrowseView/RoomView reserve TAB_RAIL_CLEARANCE
of right-side padding so a full-width row or grid never renders under
it - verified against the real library, where dense rows (e.g. Conni's
82 audiobooks) previously butted right up against the rail.

Also gitignore the real (non-.example) tippen-curriculum.yml and
tippen-progress.json, matching config.yml's own privacy treatment,
since the curriculum now contains real reward paths into a personal
library.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 00:16:42 +02:00
57ead93497 Apply lock state to category-tile cover previews too
Verified the whole reward-lock feature against a real library with an
actual browser (Playwright + headless Chromium): the album-grid cards
already showed the question-mark placeholder for a locked album, but
its 2x2 preview thumbnail in the category-tile view (the screen before
drilling into an artist/category) still rendered the real cover art,
since that Cover call never received the locked prop.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 21:37:57 +02:00
7f5e2733c2 Merge the typing game into the music player as a tab, with lock/unlock UI
Moves tippen from a standalone app into web/ as a third tab (audio player /
smarthome / typing), replacing the old single room-toggle corner button with a
vertical icon tab rail. Curriculum and progress now come from the backend
(musicmouse/tippen/*) instead of a build-time YAML import and localStorage.

Adds reward-driven lock rendering: Cover/BrowseView/AlbumModal show a question
mark for locked albums/tracks with a hint on what unlocks them, and
ResultSheet gets a new unlock-animation block alongside the existing
lesson-unlock and aquarium-creature celebrations.

CSS from the two apps is merged carefully: identical rules (bubble/card/
key-cap/view-enter/backdrop-enter and their keyframes) are shared as-is,
while rules that bake in each app's own hue are kept separate under a
`tp-` prefix and scoped to the typing tab's own .tp-stage wrapper, so
neither app's look bleeds into the other's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 21:25:42 +02:00
a5210fead2 Typing lessons like duolingo & musicmouse cleanup 2026-09-12 18:58:02 +02:00
7e5fd5ab75 Animations 2026-09-11 13:56:02 +02:00
fbf03a9847 UI cleanup, visual and keyboard navigation 2026-09-11 13:32:07 +02:00
ba7f082f48 Rework navigation for a consistent music/room toggle and back button
- Replace the "Mein Zimmer"/"Musik" text pills and the help button with
  two fixed circular corner buttons: a music/room toggle (top-right)
  and a single "back one level" button (top-left) used everywhere -
  search, categories, and the play view.
- Split `view` (browse/play) from a new `page` (music/room) in UiState
  so toggling to the room and back leaves the music side - search,
  selection, even the full-screen play view - exactly as it was.
- Back peels one step at a time (search, then track-search mode, then
  group+category together, since a root shelf tile sets both at once
  and undoing that jump should be one step too).
- Album cards: click the cover to open the track list, click the title
  to start playing immediately (matching what Enter already did from
  the keyboard). Audiobook cards drop the artist line and clamp the
  title to a fixed height so covers stay aligned across a row.
- Root shelf group headings ("Musik", "Hörbücher", "Podcasts") are now
  the link into that group's full category grid, replacing the
  separate search-icon button.
- "Taste zuweisen" is now an icon-only round button, moved to the
  bottom-right so it doesn't sit under the new toggle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 11:12:39 +02:00
8aed3b022b updates 2026-08-27 23:46:19 +02:00
edb6e5e027 Web frontend 2026-08-27 12:32:20 +02:00