astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
12 Commits (edc019515618230a2816586555ba79a9c7342e2c)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
49362d89e9 |
feat(sema,sound): un pack se entrega como quieras — y un `data:` no se pide, se descodifica
La entrega deja de ser parte del contrato. Un pack de ficheros puede llegar
como quince URLs o como UN JSON de base64 (`packFromBase64`): mismo tipo, mismo
intercambio en caliente, misma reserva sintética por entrada, y un nombre que
no existe sigue sin compilar. Medido sobre `static/sounds/ui-inline.json`: una
petición en vez de quince, y 69.082 B con brotli frente a 79.332 B de los
ficheros sueltos — el +33 % del base64 lo deshace la compresión, y el JSON gana
además porque nadie comprime `audio/mpeg` y todos comprimen `application/json`.
## `step` no se oía
Era a la vez el MÁS CORTO (18 ms) y el MÁS FLOJO (gain 0.025), y esas dos cosas
se multiplican: el oído integra energía durante ~100-200 ms, así que un tono
corto necesita MÁS amplitud, no menos. Medido, rendía a −29,8 dBFS con la
novena parte de la energía de `touch`. Ahora 0.06 a los mismos 18 ms.
Lo que no había era el guard: la distinguibilidad es una RELACIÓN, y dos
sonidos pueden ser perfectamente distintos entre sí y ser los dos inaudibles.
`sound-names.test.ts` gana un suelo absoluto sobre `gain² × duración`.
## El precalentamiento no precalentaba
- `preload` pedía el contexto con `getOrCreateContext()`, que hace
`await resume()` — y antes del primer gesto esa promesa se queda PENDIENTE en
Chrome, no se rechaza. No descargaba nada hasta que el usuario ya había
pulsado, que es justo la latencia que el preload existe para quitar.
`decodeAudioData` funciona en un contexto suspendido.
- Aplicar un pack en caliente no calentaba la caché: cada nombre pagaba su
viaje la primera vez que sonaba. Ahora `rebuildMap()` llama a `warmSamples()`.
- Con `preferences.sound === 'off'` no se descarga NADA — un pack que no se
puede oír son bytes gastados en silencio. Pero la petición se RECUERDA en vez
de tirarse: el nivel se lee en el dispatch, así que la primera reproducción
audible vacía la cola y encender el sonido no devuelve una caché fría.
## Un `data:` se descodifica en el sitio
`connect-src 'self'` BLOQUEA `fetch('data:…')` — la directiva casa por ESQUEMA
y `'self'` no cubre `data:` — mientras deja pasar una ruta del mismo origen. Un
pack inline enrutado por `fetch` caía a síntesis EN SILENCIO justo en el
entorno que llevó a alguien a hacerlo inline. Y es ~6x más lento. `bytesFor()`
lo resuelve con `atob`.
## De la revisión adversarial
- Las claves del JSON se validan: una que no sea `SoundName` LANZA, igual que
una ruta mala en `assertMapPaths` y por la misma razón — tragarse la errata
da el síntoma «parte de mi pack no se aplicó» sin nada a lo que apuntar.
- `isSoundName` preguntaba `name in SEMA_MAP.sounds`, y `in` recorre el
prototipo: `isSoundName('toString')` devolvía `true`. Inofensivo mientras
todos los llamantes tecleaban el nombre; nada inofensivo al validar red.
- `warmSamples` sólo tenía una de las dos ramas que sí tiene el constructor, así
que una app con canal de sonido propio se calentaba al arrancar y nunca más;
y esa rama leía la preferencia UNA vez, en construcción. Las dos se caían por
lo mismo: ahora comparten `warmUrls()` en vez de duplicarse.
- El demo del catálogo cancela su fetch: elegir `inline` y saltar a `synth`
antes de que llegara reinstalaba el pack sobre un `clearMap()` ya hecho.
- `fallbackFor(name)` borra los dos casts que copiaba todo el que autorase un
pack de ficheros.
## Documentación
`architecture/sema.md` gana la sección de las dos formas de entrega y el
párrafo de `preloadSamples` reescrito — describía un precalentamiento que ya no
es el que ocurre. El README del arte conoce la ruta `data:`. La página de packs
gana su sección equivalente y deja de señalar unos `.wav` sueltos como «el
ejemplo».
Y un fantasma: `soft` no existe — es un nombre del catálogo viejo que quedaba
como ejemplo en ocho sitios, incluido el docstring de `applySounds`, cuyo
ejemplo copiado literalmente LANZABA.
`static/sounds/ui-inline.json` se genera desde `packs/ui-mp3.ts`; el comando
está documentado ahí y reproduce el fichero byte a byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
11b54025d4 |
feat(sema): pack de ejemplo con ficheros mp3, recortados y normalizados
El autor dejo una biblioteca de 35 mp3 en `static/sounds/ui` y pidio
recortarlos y normalizarlos para usarlos como pack alternativo. Medidos
ANTES de tocar nada, los originales tenian tres problemas que habrian
hecho parecer roto al sistema:
· LATENCIA DE ARRANQUE. `button_hard` no empezaba a sonar hasta los
347 ms. Un sonido de pulsacion que llega un tercio de segundo despues
no confirma nada: se lee como eco. `button_squishy` 148 ms,
`blocked` 78 ms, y varios mas con 25 ms de silencio de cabeza.
· DURACIONES FUERA DE ESCALA. `item_select` 862 ms para seleccionar en
una lista donde puedes recorrer cinco elementos por segundo — se
solapan tres a la vez. `success_chime` 1591 ms.
· NIVELES SIN NORMALIZAR, factor 14x entre picos (0.066 … 0.961): unos
inaudibles al lado de otros.
PROCESADO con ffmpeg: recorte de silencio en ambos extremos + loudnorm a
−20 LUFS / pico real −1.5 dB, mono 44.1 kHz. Resultado medido en el
navegador: TODOS arrancan en 0 ms, y las duraciones se desploman —
`button_soft` de 862 ms a 28 ms, que resulta ser la longitud ideal para
un toque; `copy` a 78 ms, casi exacto al `tick` sintetico. 292 KB en total.
⚠️ Los originales NO estaban en git y el procesado los reemplaza. Copia de
seguridad de esta sesion en /tmp/ui-originales (efimera): si los quieres
conservar, guardalos tu.
EL PACK (`src/uix/sema/packs/ui-mp3.ts`) mapea 16 nombres a 16 ficheros.
Es una TRADUCCION, no una busqueda: la biblioteca esta nombrada por
componente (`button_`, `tab_`, `panel_`, `window_`) que es justo el eje
que el vocabulario rechaza, asi que cuatro ficheros compiten por el nombre
`open` y sobran quince. Cada entrada conserva como reserva el sonido
sintetico del framework, de modo que un 404 degrada a la voz por defecto
en vez de enmudecer.
Lo imperfecto queda ESCRITO en el fichero, no escondido: `tick.fulfill`
dura 425 ms y `tick.loss` 723 ms, muy por encima de la ventana perceptual
que persigue el pack sintetico. Es el precio de usar material encontrado
— suena mas rico y se comporta peor. Un pack grabado PARA este sistema se
grabaria a sus duraciones.
`engine.applySoundPack(pack)` instala entradas enteras (frente a
`applySounds`, que retunea valores de las que ya hay); `clearMap()`
revierte tambien el pack. Y el catalogo de la documentacion estrena
conmutador: mismo nombre, otra voz, para comparar A OIDO.
VERIFICADO en el navegador espiando el grafo de audio: con el pack por
defecto `tick` crea dos osciladores a 850/1275 Hz; con `ui-mp3` crea un
buffer de 78 ms y CERO osciladores. El cambio funciona de punta a punta.
sema+morfo+soma 1075/1075 · uix sin errores de tipos nuevos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
9050125076 |
fix(waveform): el buffered vuelve a ser banda recta, y la demo estrena material real
BUFFERED — segunda correccion por MIRADA, y la definitiva.
Las dos formas se construyeron y se miraron. Primero fue el SecondaryRange del
Slider con un velo neutro al 14%: rechazado ("el secundario no puede ser del
mismo color"), y la medicion le dio la razon — velo y onda eran alfas del MISMO
token (--color-content-primary al 14% vs 28%), o sea el mismo gris. Se paso
entonces a una tercera copia recortada del path, con la idea de que "el buffered
ES la onda un escalon mas alla". TAMBIEN rechazado, y por un motivo mas fuerte:
"se hace inapreciable y confunde visualmente".
La leccion, que queda escrita en los dos README: al compartir silueta con la
senal, el ojo lee la banda COMO la senal — es ilegible POR CONSTRUCCION y ningun
color la salva. La forma recta es legible precisamente porque NO es la onda. Asi
que el buffered vuelve al Slider.SecondaryRange (G-2), la parte canonica que ya
existia para esto, en vez de que el waveform pinte lo suyo.
El COLOR si sobrevive de la iteracion anterior: acento lavado
(color-mix del primary-solid con content-primary), que se separa del gris en
TONO y no solo en luminosidad. Tokens de paleta, cero literales. Los tres
colores de la onda son publicos y retunables por el disenador.
Nota de metodo: la distancia RGB avalo un gris que el ojo rechazo al instante
(esa metrica esta dominada por la luminosidad y es ciega al croma), y ademas un
bug propio en la alfa del color-mix dio numeros inflados que se corrigieron. Dos
recordatorios de que la medicion informa pero no decide.
DEMO — material real. El control se llamaba `signal`, que es una de las 8
FAMILIAS del canon, en un componente que declara CERO eventos
(expression: 'delegated'): ensenaba lo contrario de la verdad. Renombrado a
`sample`. Y el material eran los earcons de sema (pitidos de 80-220 ms, `pop`
salia casi plano) porque eran el unico audio del repo; ahora arranca en una
pista real de 2:45 (static/music/t2.wav, aportada por el usuario).
Y un defecto que 30 MB destaparon: el efecto de carga dependia de `source` Y de
`buckets`, asi que mover el slider de buckets volvia a DESCARGAR el fichero
entero. Separado en dos: decode una vez por fuente (caro), rebucketing puro y
barato. Medido: t2 (5 MB, 86 ms) frente al master de 48 kHz/16 bit (30 MB,
186 ms); sus envolventes NO son identicas — delta maximo 0.298 por cubo, medio
0.048, porque los 8 bits suben el suelo de ruido y aplanan los pasajes suaves.
Se elige t2 igualmente: 6x mas ligero por una envolvente marginalmente mas fiel.
Verificado: check 75 = baseline, 0 propios; 35 tests; eidos-lint 0 invalidos;
recipe-css-contract verde; component:audit --only waveform PASS; docs:check 0;
sonda en vivo — 2 paths en la onda, banda recta al 66% en rgb(130,95,161).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
d59b8af9aa |
uix(chat): v2 · emoji-picker (picker completo) + escaparate rico del bloque
Nuevo componente emoji-picker y rediseño del escaparate de mensajeria. emoji-picker (ruta 9 fases): - Compone Popover (open/close/foco/portal) + Command (busqueda + grid + nav de teclado + a11y combobox/listbox, su "grid mode" documentado) + dos ToggleGroup (categorias + tono de piel). Delegated: sin eventos propios (D.1); el grid y las celdas doble-registran Command.List/Item, conservando la a11y pero con contrato visual propio (gana especificidad con selectores de 2 niveles, sin tocar attrs [data-command-*] ajenos — eidos-lint limpio). - Datos: $libs/emoji, dataset vendorizado de emojibase (MIT) horneado por scripts/generate-emoji-data.ts (precedente lucide: JSON crudo en static/ + script generador). ~1906 emoji con nombre CLDR + keywords, 316 con tono de piel single-person. Grid acotado (categoria activa o resultados de busqueda), sin virtualizacion (refinamiento v2). Helpers puros + test (12/12). - morfo delegated (7 partes + header/footer de layout); soma (root + trigger + content + grid + option + preview, provider-test 4/4); eidos (panel empaquetado, receta con tokens --emoji-picker-*); langs es/en; demo 5 tabs (excepcion delegated documentada); READMEs dobles. Escaparate del bloque (web/routes/uix/demos/chat) — rehecho rico y correcto: - Avatares por-autor con color solido (Avatar del ecosistema): antes gris neutro indefinido, ahora teal/ambar/verde/indigo/primary bien contrastados. - Dos columnas: chat-list (sidebar con badges + typing-en-lista) + sala. - Conversacion rica: separador de dia, run agrupado, reaccion, reply citado, recibos de lectura, typing con avatar, y el emoji-picker integrado en el composer (inserta en el draft). - Solape de burbujas (transitorio, estimateSize=48 con mensajes ~90-126px) mitigado subiendo el estimate a 76. Auditoria de tamanos/espacios: recipes del bloque limpios (todo con tokens --space-*/--size-*/--color-*); unico literal (punto tono-capable) tokenizado. Verificacion: check baseline 76 (0 nuevos) · component:audit emoji-picker PASS · eidos-lint invalid=0 · recipe-contract 30/30 · morfo:vocabulary 0 · emoji lib 12/12 · provider-test 4/4 · Playwright PASS (busqueda 'rocket'->rocket+ astronautas, click->onSelect+cierra, teclado, tono oscuro 👋->👋🏿, picker abre en el composer). Capturas claro miradas. next-features §7 marca emoji-picker SHIPPED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
7d4f95005d |
feat(eidos): default fonts -> variable woff2 + full variable-font API
Ship the base theme's default families (Instrument Sans / Lora / Azeret Mono --
identity unchanged) as self-hosted VARIABLE woff2 (SIL OFL, latin subset, wght
range, preload on primary), so the engine's variable path is exercised by the
default theme, not merely capable. The hand-written themes/fonts.css is retired
(@font-face is config-driven from typography.families[].faces); the static TTF
set under static/fonts/air is removed.
Also close the theming-API gaps so it supports ANY variable font, not just
wght+opsz:
- FontAxes is now a 4-letter-tag map. renderFontFace emits a descriptor per
registered axis: wdth -> font-stretch: min% max%, slnt -> font-style: oblique
(OpenType slnt negated to the CSS oblique sign), alongside wght/opsz.
- TypographyStyle.variationSettings -> --style-{name}-font-variation-settings,
applied by the Text recipe (fallback normal), engaging non-standard axes
(GRAD/MONO/custom) and fixed axis defaults.
Verified: variable faces load with weight ranges + mid-axis rendering; new axis
+ variation-settings emission covered by active-eidos-config.test.ts (99 pass);
npm run check src/ = 9-error baseline (0 new); no default-font regression.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
53b6f629f2 |
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the checkpoint verdicts in docs/audit/components/) and the executed fix packages. - P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 + API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d, component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts (role=application removed ×4, aria-selected off the Day, drp translationRef, field data-state prune, pin-input commit-set, media-player renames), 13 new sema packs + 12 morfos family-default → pack. - P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar); onValueCommit terminal-callback norm (pin-input/search/password/textarea + date/time/color-field add); typed validation reason + onInvalid (tags-input, css-field); index/onIndexChange (carousel); deselectable; openDelay/ groupSkipDelay; allowCustomValue; defaultValue prune. - P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel); touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual, 44 AAA). S6 (Field composition) + S8 (calendar-surface) pending. Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline); morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched components; per-component vitest suites green. Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md Excluded (broken by the N1 rename, left broken per user decision, not staged): words/**, palabras/**, chronos, web/routes/alpha/**. Reconciliation pending: the touch-rows ::before for checkbox/switch reverses changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed markers to a labeled-row/Field task — flagged for the user in the handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
29db54f49b |
feat(scroll-frames): video init-seek + start/end segment scrubbing
The video mode now paints a frame immediately: on `loadedmetadata` it seeks to the initial scroll position instead of waiting for the first scroll (the progress-0 loop guard used to leave some browsers black). New `start` / `end` props (seconds, clamped to the real bounds) scrub only a SEGMENT of a clip — progress 0->1 maps to `[start, end]`, `end` defaults to the full duration. Time-based seek means frame rate is irrelevant and duration stays browser-authoritative (read from `loadedmetadata`, never passed by hand). Demo: same-origin `/demos/video.mp4` sample (external URLs fail on cross-origin range requests), live `start` / `end` / `smooth` controls, API rows + snippet parity, README segment example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
5eda0c6aef |
Expand air component system and translator integration
|
6 months ago |
|
|
b30092dd06 |
Refactor air architecture: clean dependency boundaries, enrich Behavior/Dom, fix AudioContext
- getAir() is now the single entry point — returns behavior, dom, translator, logger - behavior.play() encapsulates soundEnabled check + preset resolution - dom.resolve() resolves ResponsiveProp using current viewport/breakpoints - internal/ has no knowledge of config/ (correct dependency direction) - internal/ types stripped of Air prefix; public barrel re-exports with prefix - context.ts defines TranslatorService locally (structurally compatible with TerraTranslator) - button/text components updated to use only getAir(), no direct terra/config imports - AudioContext fix: withRunningContext() resumes on first user gesture before playing - AIR_IMPLEMENTATION_GUIDE updated: 12 semantics, correct APIs, current patterns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
6 months ago |
|
|
9a9c4d4f14 |
Add air sound/motion/behavior systems, refactor responsive, update terra config and tokens
|
6 months ago |
|
|
786658f81f |
Build out air design system foundation
|
6 months ago |
|
|
781bfb7e4b |
Initial commit: SvelteKit application with modular libraries
Add comprehensive library system for internationalization, logging, formatting, and UI state management: - ling: i18n library with translation keys, plural rules, and JSON serialization - logr: logging system with levels, filters, history, and transports - glob: number (numr), date (dati), currency (curr), and unit (unit) formatters - actx: application context integrating all modules with Svelte 5 reactivity - uiux: reactive UI state for theme, toasts, modals, menus, and breakpoints Features: - 247 passing tests across 4 test suites - Svelte 5 runes ($state) for reactive context - Lazy initialization for optional modules - Type-safe configuration with TypeScript - Locale-aware formatting using Intl APIs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
7 months ago |