Brainstormed design for replacing the trusted HTML/JS f-strings (Alpine
selectors, @@TOKEN@@ played-row) with three composing layers:
- htpy-style sugar on the existing Element (kwargs attrs + [] children),
additive, keeps Media/collect_media — no build step.
- Custom Elements (light DOM, TypeScript) for behavior, with the native
connectedCallback lifecycle replacing the onSwap shim.
- A typed contract: one Python Props type per component, codegen'd into a TS
interface + attribute reader, so server↔client drift fails `tsc`.
Toolchain: tsc per-module (no bundler, preserves per-component Media),
build-only/gitignored output, wired into make + Docker. Exemplars:
GameStatusSelector, SessionDeviceSelector, played-row. Alpine retired for
those three; existing .js migrated later.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>