Commit Graph
5 Commits
Author SHA1 Message Date
spoopyghosty0 27694243f2 Screenshots: copy an image to the clipboard; holiday showers; perfect pacing stays
- Screenshots tab: Copy image (a button on the card under the pointer, the right-click menu and the viewer) puts
  the full-size screenshot on this PC's clipboard (core/clipboard.py: Windows/WSL PowerShell bitmap + file,
  macOS osascript, Linux wl-copy/xclip; Flet's set_image in web mode)
- Clicking a holiday badge showers the window: New Year confetti, winter snow, Valentine hearts, digits of pi,
  clovers, hopping eggs, bouncing pumpkins (moved like the confetti: one page update per phase)
- Perfect pacing after 2.5 minutes on target; the Perfect pacing pill and line stay until the rate slips
- Full charge: only the ring pulses (with a glow behind it), the percentage stays put
- Upload hop a little slower
2026-10-09 15:59:02 -04:00
spoopyghosty0 f7108c0ca4 Fix: a page change could die when a background thread set a control property mid-update
Flet packs a patch by iterating each control's _values dict; Prop.__set__ adds/removes keys there without a lock.
A property set on a background thread (the live Frame card's sample, job progress, the library loader) while the
event loop packed a patch raised "dictionary changed size during iteration" and the update was lost (seen in CI:
a sidebar click left the old page showing). serialize_flet_updates() now makes property writes take the same
re-entrant lock as patches (app.FLET_LOCK). Reproduced with Flet's own encoder: 16 failures in 4 s before, none
after; test_property_writes_wait_for_a_patch_being_packed. The showcase server and ui_smoke serialize like the app.
Tour re-recorded with the fix (clean, no fallback clicks).
2026-10-09 08:04:55 -04:00
spoopyghosty0 f64c93b338 Showcase: every shot waits for its own page before the picture (CI caught Monitor still showing the warm-up page); settling needs 4 identical frames 2026-10-09 00:55:07 -04:00
spoopyghosty0 80a5c0b6d6 Showcase: scripted demo tour (docs/showcase/tour.yaml -> record_tour.py)
One window on the demo library, driven by name like a person would (drawn pointer, eased curved paths, a ring on
each click), filmed with Chrome's screencast (1080p, constant 30 fps from the frame timestamps), then captioned
(lower thirds in the app's colours), given title/end cards and crossfaded by postprod.py (ffmpeg only). Writes
docs/media/frameport-tour.mp4 (+ poster, best quality within 12 MB) and the README teaser docs/images/tour-teaser.webp.
Installs in the tour run a scripted job through the real queue; --draft for quick storyboard checks, --names lists
the clickable names. Element finding prefers the innermost match (a list's text includes its rows').
2026-10-09 00:22:19 -04:00
spoopyghosty0 63f0125954 Showcase: demo library + docs screenshot renderer
scripts/showcase/: the fakes split out of ui_smoke (the pretend Frame now reads the demo library's state, fixed
dates, a Take screenshot fake, a frozen monitor stream for stills), web.py (the GUI in web mode driven by name
through Flutter's semantics tree, drawn cursor, eased pointer paths, settle detection, one browser per window),
steps.py (the step language shared by screenshots and the tour), demo_home.py (21 catalog games from
docs/showcase/demo-library.yaml + demo-analyses.json, art and store details fetched once and cached) and
render_docs.py (docs/showcase/shots.yaml -> docs/images, rewritten only on a visible change; --check for CI).
2026-10-09 00:00:13 -04:00