# D14. One component model, headless behaviours (prototype)

Every block type is a component — props schema, template, stylesheet — and the native catalogue is the set of built-in components; screen layouts are screen-level components. Agents create components and fork any template-rendered one, built-ins included; authors edit instances (props form, slots, styles, duplicate, detach). Decided after a review of ten questions (5 Oct 2026):
- **No JavaScript in components.** The page holds the SCORM API and the learner's data. Behaviour comes from the player: activities (quiz, numeric, decision, results) are *headless* — the player owns scoring, saved state, SCORM interactions, focus and announcements; a fork provides the markup through hooks (`data-t-…`) checked by the validator and by axe. Generic primitives (click events, disclosure, tabs, labels) cover the rest; code that needs more is a free object.
- **Rendered at build time.** Templates are parsed with **parse5** (MIT, Node only, not shipped in packages) and rendered by the compiler: the player stays small, the output is deterministic, and the validator analyses exactly what will run.
- **Fallback to native blocks, always.** Declared or generated from the props, checked for dropped text. It is what makes components safe for exports, translation, editors that do not know them, and detach.
- **Forks remember their parent**; a fork of an activity keeps its learner-state key. Components are not scored by themselves (activities sit in their slots).
- **Pinned copies from libraries**, upgraded explicitly; local edits of a library copy are reported. **Breaking changes migrate**: `migrations.mjs` steps run on every instance, all or nothing, and `elabora.lock.json` records the version instances were written for.
*Revisit if:* agents need a behaviour the player lacks (add it as a new headless behaviour rather than opening templates to code), or build-time rendering blocks a feature that needs props changed by events (then render the same templates in the player).
