You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/architecture/active-uix.md

5.9 KiB

title type audience authority status source
ActiveUix — the composition root reference human + agent E1 architecture — how UIX boots, which services it owns, and how it degrades current migrated from src/uix/active-uix/README.md (2026-07-02, docs-book F7.1)

ActiveUix

active-uix is UIX's composition root. Its responsibility is not to be another behavior layer, but to hand morfo, soma, sema and eidos the minimal services they need — without components ever knowing ActiveApp directly.

Whole-system architecture: architecture/active-architecture.md. Executable contract: src/uix/contracts.ts, validated by contracts.test.ts.

Two boot modes

createActiveUix(options) — standalone. Composes its own runtime:

  • creates logger, timers, bus and prefs;
  • the bus uses createSvelteEngineBus({ logger, clock: timers.clock }), same as ActiveApp, so listeners run under untrack and never create accidental reactive dependencies;
  • creates langs, dom (or disabledDom when dom:false), clipboard, format and events according to the options;
  • keeps portal as a generic portal target, so each layer adapts it to its own API (portalTo) without coupling active-uix to that layer;
  • registers the common translations and the per-component catalogs from src/uix/langs/components/*.

attachActiveUix(app, options) — attach to an external ActiveApp:

  • reuses app.prefs, app.langs, app.dom, app.clipboard and app.format when they exist;
  • requires app.langs and app.dom; if either is missing it throws a configuration error;
  • does not re-subscribe langs to prefs.language (that connection belongs to defineActiveLangs inside ActiveApp);
  • registers the common translations and the per-component catalogs;
  • does not own the app's lifecycle.

Minimum contracts per module

Executable source: src/uix/contracts.ts.

Module Minimum required Optional Fallback when missing Error when missing
ActiveUix standalone langs config clipboard:false, format, events, portal, dom:false creates prefs, core services and, with dom:false, a local disabledDom missing langs config
ActiveUix attach ActiveApp core + langs, dom services app.clipboard, app.format, event engine, portal none for required services missing langs or dom on the app; the getter of an absent optional service fails explicitly
SomaRuntime dom from ActiveUix event engine, langs, format none of its own nonexistent morfo/event/part
Sema direct dom or projector when visual is active sound, haptic, visual:false none of its own for UIX services SemaConfigError without dom/projector while visual is active
Eidos dom when applyDom langs, format, prefs, mode/density sources applyDom:false allows render/serialize without DOM missing dom with applyDom active
ADom direct caller's target/window/document breakpoints/window disabledDom only when the caller asks for it ADom's own errors without a real DOM

Ownership and degradation rules

  1. Only composition roots create shared services. morfo, soma, sema, eidos and components never create dom, langs, prefs, format, clipboard or equivalents: they receive them from ActiveUix.
  2. dom:false only degrades in standalone. ActiveUix exposes a local disabledDom and passes it to EngineSemantic too; Sema/events never fall back to direct DOM writes. In attach there is no compensating creation: if the app has no dom, attachActiveUix(app) fails. disabledDom is deliberately MIXED (AUX-2, 2026-07-11): write-shaped calls (apply, listen, …) no-op silently, but reads that MUST return a value — measure, raf, getDocument / getWindow — throw ActiveUixDomDisabledError; a component that measures under dom:false dies loudly instead of computing from a phantom layout.
  3. langs is not locale. prefs.language feeds translations; prefs.locale feeds formats. They never mix.
  4. clipboard is a capability service, not visual DOM. Standalone creates it unless clipboard:false; attach consumes it from app.clipboard when a layer asks for it, and fails with an explicit error if it was not declared.
  5. prefs.direction is the effective direction preference; html[dir] is only its DOM projection.
  6. ActiveUix does not auto-project preferences onto the DOM. arts/prefs projects the cross-modal attrs (dir, data-motion, data-sound, data-haptic) via createActivePrefsDomProjection; ActiveEidos projects the visual ones (data-theme, data-mode, data-density). The frontend artifact was retired and must not reappear as a locale source.
  7. ActiveUix neither creates nor knows Soma or Eidos. Soma.create(...) creates its own scope and Soma.runtime(...); ActiveEidos.create(...) creates the visual scope when the app needs runtime CSS.

Booting a UIX shell

A shell that uses visual components wires three pieces explicitly:

const uix = createActiveUix({ langs, prefs: { schema } });

setActiveUix(uix);
Soma.create();

const prefsProjection = createActivePrefsDomProjection({
	prefs: uix.prefs,
	dom: uix.dom
});

const eidos = ActiveEidos.create({
	theme: 'base',
	modeSource,
	applyDom: true
});

prefsProjection owns dir, data-motion, data-sound and data-haptic. ActiveEidos owns data-theme, data-mode and data-density. Light/dark mode goes to ActiveEidos.modeSource, not to prefs.theme — theme is not part of UIX's core prefs preset and writing it raises prefs::unknown_dimension.

Powered by TurnKey Linux.