Timer Layout Engine v2: boxes, zones, per-orientation layouts - #19
Timer Layout Engine v2: boxes, zones, per-orientation layouts#19Isorgcom wants to merge 8 commits into
Conversation
renderAll no longer writes style.display for the six data-driven widgets (avg stack, reentries, chips in play, next break, ends at, payouts); it records availability in DATA_AVAIL and new syncVisibility() is the only writer of display for themable elements, combining theme visibility with data availability and the edit-mode force-show rules. This kills the bug where a theme-hidden widget reappeared on the next 2s poll. renderAll writes go through change-guarded setText/setHtml helpers (groundwork for fit-text). applyTheme's image/streaming blocks now manage only src and availability. Server-side, _timer_theme.php gains the missing ends_at defaults + color var and stops emitting visibility/order CSS (JS owns them); a theme-pending class on <html> hides the stage until the first applyTheme, with a 2.5s head-script failsafe so a JS error can never blank a remote display. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Text now auto-shrinks to fit the space an element is allowed: fitAllText() measures scrollWidth/Height overflow against clientWidth/Height in batched clear-read-write passes (one reflow per cycle, 8px floor) and is scheduled only when content changes (setText/setHtml dirty flag), the theme applies, the viewport changes shape, or the clock string changes LENGTH. The ante sub-label moves in-flow (inline-flex column) so measurement finally sees it. Positioned elements get soft extent caps: max-width/height of twice the distance from their center to the nearest viewport edge (divided by transform scale, border-box), so legacy center-point themes stop hanging off-screen with zero stored changes. A debounced reapplyLayout() wired to resize/orientationchange/fullscreenchange re-applies layout + fit — the re-layout hook the timer never had. The event-name font-size rule drops its !important (double-class specificity instead) so fit-text's inline size can win; flow children gain max-width:100% so overflow is measurable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Free-form layout graduates from center points to real boxes. Elements
carry {x,y,w,h} (top-left anchored, % of the new #layoutStage) stored in
layouts.landscape.free (schema 2); applyTheme prefers a box over legacy
pos, so untouched themes render exactly as before and convert only when
edited and saved. Entering edit mode measures the current rendered rects
into boxes (verified drift: 0.03px), drags are extent-aware (edges clamp
to the stage, snap candidates come from the box map with no DOM reads),
and a selection shows an 8-handle resize frame that lives in the stage so
handles never pollute fit-text measurement. checkOverlaps() runs an AABB
pass after every drag/resize, outlining colliding boxes in red with a
count badge in the pill — overlaps are now visible instead of shipped.
The inspector gains W/H steppers, the pill gains a Live toggle (position
against real data instead of placeholders, now realistic widths), Reset
re-seeds boxes from the default flow, and saves mirror box centers into
legacy pos for one release so stale open pages keep positioning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Themes can now run a structured layout where overlap is impossible: five
fixed zones (top bar / left rail / center stage / right rail / bottom
bar) on a CSS grid over #layoutStage, with elements assigned per zone in
an ordered list (layouts.landscape.zones.{opts,assign}). applyLayout()
reparents element nodes into their zones with minimal-move insertBefore
sync (the streaming iframe never reloads from unrelated changes) and
restores original DOM slots when leaving zones mode; both the free-box
and zones sub-trees persist so mode switching loses nothing. Zone items
compress (min-height:0 + shrink) and fit-text shrinks into the bound, so
a center stage holding clock+blinds+labels self-fits instead of clipping.
Empty zones collapse to zero outside the editor. Editor: Free/Zones
segmented switcher in the pill, dashed zone bounds with name labels,
click-to-select + wheel-resize on zone items, Objects panel grouped by
zone with per-row zone dropdown, in-zone reorder arrows, and an Unplaced
group; per-zone size/align/gap controls in the Page inspector. Grid gets
explicit align/justify stretch so the container's flex centering can't
leak in and size zones by content.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A theme now carries independent landscape and portrait layouts (layouts.landscape / layouts.portrait, each with free + zones sub-trees). The display picks the orientation matching the viewport via matchMedia and falls back to the other when one is empty, re-applying live on resize/rotate/fullscreen — verified end-to-end: distinct layouts saved through update_theme swap correctly when the viewport flips, without a reload. All box/zone readers and writers route through currentLayoutOrientationKey(); in the editor an orientation segment (desktop/phone) pins which layout is being edited, letterboxing the stage to a simulated 16:9 or 9:16 rect (all geometry is stage-relative, so the simulation is exact; viewport-fixed snap guides hide). First edit of an undefined orientation seeds an in-memory copy of the defined one, and a copy-from-other button (with confirm) does the same on demand — overlap outlines immediately flag what doesn't survive the aspect change. The QR, image, and streaming elements — previously body-level siblings whose percentages resolved against the viewport — are adopted into #layoutStage at init so boxed geometry is truly stage-relative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner feedback on the first zones cut: ugly defaults, clunky Objects- panel-only editing, too rigid, plus two bugs. Reworked: (1) zone items are now GHOST-DRAGGABLE — pick one up, the zone under the pointer highlights, drop to reassign, with in-zone ordering derived from the drop position; the Objects panel dropdowns remain as the precise fallback. (2) Zone boundaries are draggable dividers (thin blue lines between zones, ns/ew cursors) that resize the top/bottom/left/right zones live, replacing number-field-only sizing. (3) Softer look: dimmer dashed bounds and labels, smaller default zone sizes (10/14/14/8). Bugs: the edit pill now wraps within the viewport (max-width + flex- wrap, centered) so its drag handle can never sit off-screen, and eye icons inside zones anchor to their own item (items are position: relative now; static items made every absolutely-positioned eye pile up at the zone corner and clip to a sliver at the zone edge). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Shelved 2026-08-08. Parking this deliberately, not abandoning it. Everything is pushed; nothing is only local. State: phases 1–5 complete and dev-verified, plus one zones rework. Branch is 8 commits ahead of main and 2 behind (v0.2059 and v0.2060 landed after it was last synced — merge main in before resuming). Two things outstanding when it's picked up again:
Plan file: What already works on this branch (worth not losing): theme-hidden elements no longer reappear on the 2s poll; text auto-shrinks so nothing overflows; elements are real resizable boxes with red overlap outlines; the timer finally re-lays out on resize, rotation and fullscreen; and themes hold separate landscape/portrait layouts that swap live. |
Draft — phases 1–5 complete and dev-tested, phase 6 outstanding. Not ready to merge.
Rebuilds the tournament timer's layout system so elements stop overlapping and the display is genuinely customizable. Plan:
.claude/plans/linked-squishing-hoare.md.Done
syncVisibility()is now the single writer ofstyle.display;renderAll()records availability inDATA_AVAILinstead. Fixes theme-hidden widgets reappearing on the next 2s poll. Adds a first-paint gate with a 2.5s failsafe so a JS error can never blank a remote display, and fixes theends_atserver/client drift.reapplyLayout()finally re-runs on resize / rotate / fullscreen.{x,y,w,h}boxes on#layoutStageinstead of center points: extent-aware drag clamps, 8-handle resize, AABB overlap detection with red outlines and a count badge, W/H steppers, and a live-data preview toggle. Legacy themes convert only on edit+save (measured drift: 0.03px).Remaining (phase 6)
Schema v2 export/import envelope, PHP-side migration + validation in
timer_dl.php/_timer_theme.php, header TOC update, then the version bump and changelog entry.Notes
Zones mode was reworked once and may need more; the owner's initial reaction was that it needed work on look, editing flow, and rigidity. Chromecast receiver (
cast_receiver.php) is deliberately out of scope.