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/CANON.md

20 KiB

title type audience authority status sources
UIX Semantic Canon canon human + agent canonical — single source of truth for the semantic vocabulary current
book code
docs/Disenando_lo_que_ocurre_HOMOGENEIZADO.pdf ("Diseñando lo que ocurre", ed. homogeneizada 2026-07 — the earlier v2_3.md no longer exists) src/uix/sema/verbs.ts, src/uix/sema/types.ts, src/uix/intent.ts, src/uix/sema/sema-map.ts, src/uix/morfo/types.ts

UIX Semantic Canon

This is the single source of truth for the framework's semantic vocabulary: the families, intents, verbs, the intent policy, the composition rules, and the expression channels. It exists so the rest of the corpus stops re-transcribing the vocabulary (which is how it silently drifted: "7 families" survived in three docs after the canon moved to 8). Every other doc links here.

Need the concrete closed sets to build from (every family's verbs and default hold, the intents, haptic kinds, part archetypes, palette scales, sizes, variants, shared strings)? They are spelled out — GENERATED from the code, so they never drift — in canon/vocabularies.md. This file is the doctrine; that one is the enumerated lists.

Two anchors hold this canon honest:

  • The book — docs/Disenando_lo_que_ocurre_HOMOGENEIZADO.pdf ("Diseñando lo que ocurre", edición homogeneizada). The editorial source. Each entry cites its chapter.
  • The code — the runtime is the executable form. Concrete values (per-family holds, channel signatures, the full verb lists with author extensions) live in code and are linked, not copied here, on purpose. This doc fixes the doctrine; the code fixes the numbers.

Rule: if you need to state a family, an intent, a verb, or a composition rule in any other doc, link this file — do not paste a copy. A second copy is a future drift.


1. The canonical chain

Every perceptible event resolves through one chain (book ch. 11, §0; ch. 30):

event → family → verb / phase → evaluation (if any) → intent → expression channels → unified reading

The framework encodes this chain literally: morfo declares it, soma executes it (runtime.trigger), sema carries the perceptual vocabulary and dispatches channels, eidos materializes the visual channels. See architecture/active-architecture.md for the layer wiring; this file is only the vocabulary that flows through it.


2. The 8 families

A family is not a component or an effect. It is a recurring class of event that answers one perceptual question (book ch. 8, ch. 21). The eight are the reduction of a wider exploratory set down to a minimal-yet-sufficient grammar (book ch. 8 §1–3).

Canonical list: SemaFamily in src/uix/sema/types.ts (SemaValencedFamily | SemaTransitionalFamily). Per-family base signature, active channels and hold: SEMA_MAP.families in src/uix/sema/sema-map.ts.

Family Perceptual question Accepts intent Book
contact ¿el sistema ha sentido mi acción? leve / anticipatory ch. 22
commit ¿qué quedó fijado o tuvo consecuencia? fully ch. 23
signal ¿algo reclama mi atención? fully ch. 24
handle ¿estoy manipulando directamente este objeto? only on drop ch. 25
emerge ¿algo entró o salió del campo perceptivo? normally no ch. 26
shift ¿cambió el contexto / régimen? normally no ch. 27
sustain ¿esto sigue ocurriendo? normally no ch. 28
delegate ¿quién actúa ahora? no by default ch. 29

contact/commit/signal/handle are the valenced families; emerge/shift/sustain/delegate are the transitional ones (book ch. 9). That split is a classification; it no longer dictates the intent rule — the policy (§4) does.

The perceptual question is a demand on the expression, not a label: a family that fails to answer its own question has failed at the only thing it exists for. shift is the case that proves it — its question IS the crossing, so a shift nobody perceives crossing is the shift invisible of the antipattern catalogue (ch. 34 §14), and it was exactly that here until 2026-08-11: it sounded like a slide and did not slide (§8 rule 5; the sense it now travels in, data-event-direction, in §9).


3. The 6 intents

An intent is the evaluative modulation of an evaluable event — a region of the valence/activation space (Russell), not a color (book ch. 9 §6, ch. 10).

Canonical list: INTENTS in src/uix/intent.ts — owned by UIX itself, not by a layer. Per-intent perceptual deltas: SEMA_MAP.intents in sema-map.ts.

Intent Valence / activation Reading Book
neutral low activation, no strong valence notar sin tono ch. 10
affirm positive, low activation "todo va bien" (confirmación suave) ch. 10
fulfill positive, mid-high activation "objetivo cumplido" (resuelve tensión) ch. 10
risk negative, moderate activation "revisa esto" (corregible) ch. 10
threat negative, high activation "atiende ahora" (aún evitable) ch. 10
loss negative, lower activation, posterior "ya ocurrió" (consecuencia consumada) ch. 10

Three distinctions the inherited semaphore (success/warning/danger/info) collapses, and that this canon keeps apart (book ch. 10 §4):

  • threat ≠ loss — threat convokes action before the consequence; loss registers it after. They must not look/sound the same.
  • affirm ≠ fulfill — soft confirmation vs resolution of a tension.
  • info is not an intent — it is attentional salience → signal.* + neutral.

Intent assignment — undo matrix and binary toggles (framework materialization, 2026-07-07)

Two assignment rules the catalog already practiced consistently. THIS section is the canonical registry; they were canonized at the component-audit checkpoint (verdicts C1/C3 — historical record in audit/components/_veredictos.md):

  • The undo matrix. Removing an item from a collection (commit.unselect) = affirm — an active choice, as affirmative as selecting it (calendar, select, combobox, grid-list, listbox). Un-marking a binary (the uncheck direction of commit.toggle) = neutral. Abandoning or clearing (commit.reset, commit.cancel) = neutral.
  • Binary toggles — two sanctioned models. Mark-done semantics, where the direction itself carries the evaluative load, use two static directional events (checkbox: commit-toggle-check affirm / commit-toggle-uncheck neutral). Mode-switch semantics, where the weight depends on WHAT is being switched, use one event with intent: { fromProp: 'intent', default: 'neutral' } so the consumer grades it (switch, toggle, toggle-group). Choose by the question: does the ON direction intrinsically mean progress/agreement? → static directional. Does context decide? → fromProp.

4. Intent policy — SEMA_FAMILY_POLICY

Whether intent is required is set per family by policy, not by the valenced/transitional split (book ch. 8 §6, ch. 9). Two independent axes, in src/uix/sema/types.ts (SEMA_FAMILY_POLICY):

  • intentRequirement ('required' | 'optional' | 'forbidden') — the compile-time gate. 'required' (only commit and signal) → intent is mandatory in MorfoEventSemantic. 'forbidden' is reserved (no family uses it today). Drives the SemaEvent / MorfoEventSemantic discriminated unions.
  • intentGuidance ('expected' | 'contextual' | 'discouraged') — doctrinal hint, no type effect. commit/signal = expected; contact = discouraged (book ch. 22 §11: "el intent fuerte no debería vivir en el contacto"); the rest = contextual.

Runtime: validateSemaEvent throws when a required family is built without intent.


5. The evaluable-vs-structural rule

The intent lives in the evaluable event (the message), not in the structural container (the frame). (book ch. 9 — "Qué eventos son mensaje y qué eventos son marco"; restated in Appendix A.)

A modal that opens is shift.enter-mode (frame); the warning inside it is signal.warn + threat (message). A spinner is sustain.progress (frame); the failure after it is commit.fail + risk (message). Cargar el intent en el marco es el antipatrón capital (book ch. 34 §5 "Modal rojo", §4 "todo lo que aparece es alerta").

In the framework this is enforced declaratively: the event that carries the intent declares it in its morfo events[].semantic.intent; the frame event does not. The runtime never infers intent (book Appendix A: "El intent no se hereda implícitamente… El runtime no debe adivinar. La semántica debe estar declarada."). This is exactly the morfo → soma → sema → eidos contract.


6. Canonical verbs — SEMA_VERBS

Verbs concrete the action within a family (book ch. 8 §"niveles", ch. 22–29). morfo.events[].semantic.verb MUST be in its family's set; events[].name declares the family — {family}-{verb}[-{nuance}], guaranteed by validateMorfo — so sema / sound / haptic / eidos can subscribe transversally.

Executable source of truth: SEMA_VERBS in src/uix/sema/verbs.ts — including the documented author extensions (e.g. commit.unselect, handle.zoom, signal.inform), tracked in decisions/book-deviations.md. The book's base verbs, by family:

  • contact (ch. 22): press · tap · activate · focus · trigger · release
  • commit (ch. 23): select · toggle · save · submit · confirm · complete · fail · cancel · reset · discard · delete · restore · expire · acknowledge
  • signal (ch. 24): announce · notify · warn · alert · emphasize · remind
  • handle (ch. 25): pick · carry · drop · drag · resize · reorder · rotate · scroll
  • emerge (ch. 26): present · dismiss · open · close · expand · collapse · reveal · hide
  • shift (ch. 27): enter-mode · exit-mode · navigate · route · step · return · context
  • sustain (ch. 28): start · progress · loading · waiting · syncing · processing · streaming · pending · retrying · end
  • delegate (ch. 29): offer · plan · authorize · act · review · escalate · return

Verbs that look like one family but belong to another (book canon): select / toggle / acknowledge are commit (they fix state); edit is expressed as shift.enter-mode (régimen change), not a handle verb.


7. Expression channels + the owner split

The book defines 8 expression channels (book ch. 11–20): tiempo · motion · presencia · profundidad · forma · color · sonido · háptica. "El color expresa el intent, no lo define" (ch. 16); "ningún canal agota la semántica" — robustness = a reading that survives the loss of a channel (ch. 19, ch. 33).

The framework splits these channels by owner (decision recorded in decisions/book-deviations.md D.8):

  • sema runtime channels = sound + haptic only (the two in SemaChannelSignatures), plus the projected visual meta-channel that stamps data-event-* during the hold. motion/color/presence/depth/shape were removed from sema.
  • eidos materializes the visual channels (motion / presence / depth / shape / color) by reacting in CSS to data-event-* + the morfo's state attrs.

How each channel is AUTHORED — the owner split says who materializes a channel; this says what a component actually WRITES, which is the part authors get wrong:

Channel The component writes Where the values live
visual (motion / color / presence / depth / shape) nothing — it declares the EVENT; eidos reacts in CSS to data-event-* eidos recipes + the token engines
sound one NAME, and only when it differs from its family's default SEMA_MAP.sounds — the sound pack
haptic a categorical kind (tick / tap / pulse / success / …) HapticChannel maps kinds to patterns

The rule is the same in all three rows and it is the point: a component says WHAT occurs, never how loud, how bright or how long.

And the intent SELECTS; it does not modulate. Resolution is two lookups — pack[name.intent], then pack[name], then silence. A threat is not a tick with more roughness: it is tick.threat, another sound, designed whole. Where a pack ships no variant for an intent, the intent is simply ignored and the base sounds. That is deliberate: we recognise SOUNDS, not displacements of a parameter, and a system that bends one tone produces variants that differ on paper and are the same to the ear.

The name itself usually comes from the map, not from the component: SEMA_MAP.families[f].sounds is keyed by the event's canonical VERB, so an emerge + close finds close with nothing written anywhere. A component writes a name only when it DIFFERS.

Adding a sound means adding a NAME to the pack, never widening a rule. Detail in architecture/sema.md; what a recording can and cannot carry (the intent only moves its LEVEL — physics, not policy) in decisions/book-deviations.md D.7, retired but kept for that measurement.

So the book's 8 channels are conceptual; at runtime they are owned by different layers. hold (the registration FLOOR — a minimum, never a ceiling: the expression completes before unstamping, capped only by the channel's engineering guard) resolves per family + intent from SEMA_HOLDS_BY_INTENT (holds.ts — the single hold source since 2026-07-06; the duplicated per-family SEMA_MAP hold was removed) over the SEMA_DURATIONS scale (glimpse / brief / settled / noticed / …). The ms are the framework's MATERIALIZATION of the book's qualitative regions (cap. 32, TABLA 32.1/32.2 — the book deliberately gives no numbers); see decisions/book-deviations.md D.12. Persistence (lifecycle) is separate — SignalPersistence in types.ts (book ch. 12 §6, ch. 4 §13: la huella se declara).


8. Composition rules

Real interaction is a temporal composition of events, not one family (book ch. 30, ch. 6 §13). The rules are derived from perceptual need, not decree (ch. 30 §3):

  1. contact precedes the result when there is direct action (agency).
  2. sustain precedes commit when there is a wait (continuity).
  3. threat precedes loss — never commit.delete + threat (before/after the consequence).
  4. emerge does not absorb the content's intent — emerge.open → signal.warn + risk, not emerge.open + risk (frame ≠ message).
  5. shift must orient the context change (focus + title + landmark) — and it must be PERCEIVED crossing it. A frame that swaps with nothing moving is the shift invisible of the antipattern catalogue (ch. 34 §14): the user is somewhere else and was never told they travelled. Until 2026-08-11 shift was exactly that in this framework — it sounded (slide) and did not slide, because BUILTIN_SIGNATURES had a FAMILY-keyed visual signature for contact, commit and delegate and none for shift (emerge and signal have theirs keyed by event name, so they were never mute). It has one now, and it is directional: see data-event-direction in §9.
  6. handle concentrates evaluation on the drop, not the carry.
  7. every open process needs an exit (commit / cancel / fail / persisted-warn).

On simultaneity, attentional dominance (ch. 30 §7): the evaluable event dominates the structural; higher activation dominates lower; on a tie, the most recent.


9. Naming + the declarative layer

Name events, not effects (book ch. 36): contact.press, commit.save + affirm, signal.warn + risk — never redAlert, successToast, shakeError.

The grammar is implemented as a declarative layer above components, tokens and patterns (book Appendix A) — in UIX, the morfo map:

morfo declares  →  soma executes (runtime.trigger)  →  sema vocabulary + channels  →  eidos materializes (reads DOM)

Cross-layer vocabularies that anchor this:

  • Archetypes — cross-component part classification, ARCHETYPE_VOCABULARY in src/uix/morfo/types.ts, emitted as data-archetype.
  • The data-event-* tokens — the contact surface sema stamps and eidos reads (see architecture/sema). Six: data-event · -family · -intent · -direction · -phase · -id.
  • Sense of traversal — data-event-direction, 'forward' | 'backward' (SemaDirection). Two values because the event NAME already carries every distinction a DECLARATION can make (shift-enter-mode ≠ shift-exit-mode); what a name cannot carry is which way THIS occurrence went, since one shift-navigate is the previous month and the next one is the following month. So the sense is decided per emit, like intent, and like intent it is optional — a route with no sense of its own (a month picked from a select) stamps none, because an invented sense is worse than none. It is a SENSE, not an axis: eidos maps it onto the inline axis, so :dir(rtl) flips it and no layer above CSS knows about left or right.

10. Visual canon (sibling)

This file is the semantic canon. The visual canon — the Token Scope Contract (--{component}-* public / --_{component}-* internal; never --eidos-*/--air-*/--terra-*/--soma-*), the 9 color roles, the size scale, and the variant vocabulary (EIDOS_VARIANTS) — lives in eidos/THEMING.md §4–7 and eidos/lib/types.ts. Variants are eidos canon, not theme (THEMING §19): a theme re-tints what is perceptually fixed; it does not invent families, intents or variants.


Sources

  • Book — docs/Disenando_lo_que_ocurre_FINAL.pdf (FINAL edition, 426 pp. — the canonical anchor, tracked in-repo; chapter map in book-map.md): families ch. 8 + 21–29 · intents ch. 9–10 · channels ch. 11–20 · composition ch. 30 · matrices ch. 31 · ranges ch. 32 · accessibility ch. 19 + 33 · validation ch. 35 · theory→system ch. 36 · declarative layer Appendix A.
  • Code — verbs.ts (SEMA_VERBS) · types.ts (SemaFamily, SEMA_FAMILY_POLICY, SignalPersistence) · intent.ts (INTENTS) · sema-map.ts (SEMA_MAP) · morfo/types.ts (ARCHETYPE_VOCABULARY).
  • Deviations from the book — decisions/book-deviations.md.

Powered by TurnKey Linux.