Fleet changelogs · dev.ecs0.net
rdmsm4x-changelog-20260916-1324-bitroo-888-app-catalog-ported-layout-engine

rdmsm4x-changelog-20260916-1324-bitroo-888-app-catalog-ported-layout-engine

2026-09-16 13:24:42 EDT · rdmsm4x · session_012cXdr2uPhnPS1cQfbt9pPQ

The whole 888-app Tidbyt catalog is ported at the layer that is portable: layout. Implemented its render vocabulary natively rather than transcribing ~1M lines of Starlark. bitROO ae9a6a7.

Why the method changed

The measurement decided it. The catalog is 956,531 lines of Starlark (median app 249, p90 760, max 584,659) — but the render vocabulary is fifteen primitives: Box 4412, Text 4132, Row 2680, Column 2346, Image 1415, Root 1404, Padding 1248, Marquee 985, WrappedText 769, Stack 624, Animation 371, Plot 157, Circle 141, Sequence 47, PieChart 6.

It is not 888 designs; it is 888 compositions of a small vocabulary. So the port is the vocabulary, not the transcript.

Coverage: 888 of 888

Sources/BitRooCore/Layout/ implements the widget set with Tidbyt's real semantics — main_align, cross_align, main_axis_size, and start · center · end · space_between · space_around · space_evenly. Every app maps to one of 13 ported archetypes:

| headline 443 · quote 93 · progressBoxClock 87 · iconCard 61 · statusList 59 · seriesCard 53 | | departures 27 · fullBleedImage 24 · scoreboard 12 · bigValue 11 · animation 11 · fuzzyClock 6 |

Per-app mapping: docs/tidbyt-archetype-map.tsv.

What "ported" means, precisely

The conformance sheet earned its place on the first render

preview/layout-conformance.png produced six alignment panels that were pixel-identical when all six must differ. Cause: draw(row/column) handed each child its own intrinsic size as available space, so a nested Row saw its measured width instead of 64, main_axis_size: max had nothing to expand into, and every space_* mode computed free = 0 and collapsed to .start. Children now receive the parent's cross-axis extent, and a test asserts all six differ.

Second thing only looking caught: departures and statusList rendered as an unreadable blob. Tidbyt's default tb-8 is 8px tall so its rows get spacing free; Font3x5 is 5px and stacked rows touch. Porting a layout faithfully is not the same as porting it legibly.

A regression of mine, found and fixed

scripts/render_contact_sheet.zsh (shipped yesterday) hand-assembled swiftc flags, and broke the moment BitRooCore gained a libwebp dependency from another session's work — it duplicated dependency knowledge SwiftPM already had, so the two drifted the first time the package changed. Both renderers are now package targets (swift run contactsheet, swift run layoutsheet) and cannot drift that way again.

Honest gaps, recorded not rounded away

Verification

swift test       -> 39 tests, 0 failures   (32 before)
layoutsheet      -> 30 panels: every widget, all six alignment modes, inspected
contactsheet     -> 38 scenes, still correct
make_app.zsh     -> "architectures ok: x86_64 arm64"
iOS clean build  -> BUILD SUCCEEDED
wiki             -> FEAT-20260916-02 200, bogus path 404 as control

Notes

Another session shipped FEAT-20260915-05 (universal2 WebP) and FEAT-20260915-04 (App Intents) — both tickets I filed yesterday — while this ran. Their work is in the same tree; I committed only my paths.

Filed ISSUE-20260916-16: git tracks bitROO's docs directory as Docs/ while the disk name is docs/. Harmless on case-insensitive APFS, splits in two on a case-sensitive filesystem. Pre-existing, and not fixed now — a case-only rename is a two-step git operation and another session is actively committing here.

No secrets appear in this record.