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/process/PLAN-waveform.md

103 lines
19 KiB

feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
# PLAN — `Waveform` (visualización interactiva de audio)
> **Tipo**: plan de creación por fases (process — efímero, NO fuente de verdad).
> **Fecha**: 2026-07-31 · **Estado**: **✅ INICIATIVA COMPLETA 2026-08-01** —
> gate firmado el 2026-07-31 («ok» tras la presentación única: las 8 con las
> recomendaciones) y **F1–F6 cerradas**, F6 con la mirada del usuario.
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
> **Origen**: iniciativa hermana FIRMADA en D-AP2.4 (`PLAN-audio-player-v2.md`):
> componente canónico propio, POST-v1 del player — «tiene superficie de contrato
> real… y sirve fuera del player». Los cimientos que este plan asume ya existen
> y están commiteados: `uix.sound.decode(bytes)` (la puerta de muestras),
> `Slider` con `aria-valuetext` (G-1) y `SecondaryRange` (G-2), y `$libs/plots`
> (`scaleLinear` + `area`/`line`, verificado en el índice).
> **Kickoff sesión nueva**: _"Lee `docs/process/PLAN-waveform.md`; si el gate
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
> está firmado, sigue por la fase abierta (releyendo `component-guide.md` al
> abrir F2)."_
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
---
## 0. Qué es y quién lo consume
La representación de una señal de audio como onda/barras, **interactiva** (el
sector la usa como scrubber: SoundCloud, wavesurfer) o pasiva. Consumidores
reales que la barra ≥2 exige:
| Consumidor | Qué necesita |
| -------------------------------------------------------------------- | ------------------------------------- |
| `media-player` (TimeSlider-onda, v2 del player — FUERA de este plan) | onda + seek + progreso |
| `chat-message` (nota de voz) | onda compacta + seek |
| Estudio sema / editor | onda pasiva de un buffer decodificado |
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
## 1. Referencias (F-1.2, ≥3)
| Ref | Modelo |
| ----------------------- | ---------------------------------------------------------------------------------------------- |
| **wavesurfer.js 7** | el canon del sector: peaks precomputados O decode cliente; render canvas; regions/plugins |
| **peaks.js (BBC)** | separación DATOS/render: `audiowaveform` (server, C++) genera los picos; el cliente solo pinta |
| **SoundCloud** | la UX de referencia: barras + dos colores (pasado/futuro) + seek |
| **WhatsApp voice note** | la forma compacta: barras + cursor, en una fila de chat |
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
**Lectura**: la ruta profesional NO decodifica en el cliente (coste + CORS);
los picos son un dato que la app provee. El decode cliente es la conveniencia
opcional para ficheros locales/pequeños — y nuestra puerta ya existe
(`uix.sound.decode`).
## 2. La observación que encoge el plan
**Un waveform interactivo ES un slider con otra piel.** El drag continuo, el
click-to-jump, el teclado (← → Home End PageUp/Down), `aria-valuemin/max/now`,
`aria-valuetext` (G-1) y el `commit-set` del release — TODO eso ya vive en el
`Slider` canónico y sus señales sema. Re-declararlo sería exactamente la
duplicación que D-AP2.13 acaba de retirar del player.
**Propuesta**: `Waveform` COMPONE `Slider` (el patrón del `TimeSlider` del
player), y su morfo declara solo la capa que el Slider no tiene: la onda.
Consecuencia: **cero eventos propios en v1** (las señales son las del Slider
embebido) y el foco del componente queda en su verdadero contrato — los datos
(`peaks`) y su render.
## 3. Decisiones (gate del usuario — SIN FIRMAR)
| ID | Cuestión | Recomendación |
| ---------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **D-WF.1** | Membresía / composición | **Componer `Slider`** (§2): morfo propio con partes de onda + Slider embebido para toda la interacción. La alternativa (re-implementar drag/teclado/aria) duplica un contrato PASS sin ganar nada |
| **D-WF.2** | Los datos | **`peaks: number[]` (0..1) provistos por la app** (firmado ya en D-AP2.4; la ruta BBC/SoundCloud). Sin fetch ni decode implícitos en el componente |
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| **D-WF.3** | Extractor de picos cliente (opcional) | **`sound.peaks(buffer, buckets)` en el art `$sound`** — es la disposición escrita del plan del motor («percepción: analyser/picos, v2») y el flujo natural es `decode → peaks` en la misma puerta. Alternativas: `$libs` (puro, pero AudioBuffer es plataforma) o el componente (privilegio local, el antipatrón). Superficie: ~20 líneas (min/max por bucket sobre `getChannelData`) |
| **D-WF.4** | Render | **SVG vía `$libs/plots`** (firmado en D-AP2.4): `scaleLinear` + generadores de path. Sin canvas (un canvas suelto exigiría la ciudadanía de `$scene`; para N picos estáticos el SVG sobra y hereda theming/tokens gratis) |
| **D-WF.5** | Formas del render | `shape: 'bars' \| 'wave'` — barras (SoundCloud, default) y área continua espejada (wavesurfer). Ambas son un path distinto sobre los mismos picos; coste marginal |
| **D-WF.6** | Progreso (dos colores) | **`clipPath` por fracción de progreso** sobre un segundo path coloreado — cero re-render por frame (el clip se mueve con una CSS var/attr del provider, como el rAF del player ya alimenta el value del Slider) |
| **D-WF.7** | Interactividad | Interactivo por defecto (seek); `readonly` lo vuelve pasivo (el Slider ya tiene la prop — se reenvía). Sin `disabled` propio: el del Slider |
| **D-WF.8** | Sema | **Sin pack propio en v1**: cero eventos propios (D-WF.1) → las firmas son las del Slider embebido. Dentro del player, el silencio por descendencia YA lo cubre (D-AP2.7 v2). `expression` del morfo acorde (sin pack, guard S11d en paz) |
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
## 4. Contrato propuesto (borrador para F2 — se cierra con la firma)
- **Partes**: `Provider` (group; dueño de props/geometría) · `Wave` (el `<svg>`;
`data-shape`) · `Slider` embebido (montado por el wrapper soma, como
TimeSlider) · `Cursor` (indicator, opcional — la posición actual cuando se
quiere además del clip de color).
- **Props soma**: `peaks: number[]` · `value`/`onValueChange`/`onValueCommit` ·
`min`/`max` (dominio real: segundos) · `shape` · `readonly` · `valueText`
(reenviado a G-1) · `secondaryValue` (reenviado a G-2: buffer/preload sobre
la onda).
- **Eidos**: tokens `--waveform-*` (color pasado/futuro/cursor, bar-width/gap,
radius); tamaño por `data-size` como el slider.
- **A11y**: la del Slider embebido (aria completo + valuetext); el `Wave` es
`aria-hidden` (presentacional — el valor accesible es el slider).
## 5. Fases (tras la firma; método no-cascada; releer `component-guide.md` al abrir F2)
| Fase | Contenido | Verify |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **F1 — `sound.peaks`** ✅ **2026-07-31** | Extractor max-abs por bucket sobre TODOS los canales, normalizado por el bucket más alto (documentado: una grabación floja pinta onda completa; silencio total queda plano); puro, sin contexto ni guard disposed (nada que fugar) | ✅ tests (mono · multicanal con valores float32-exactos · silencio · degenerados) — 42/42 con el port |
| **F2 — Morfo** ✅ **2026-07-31** | 2 partes (provider con `data-shape`/`data-readonly` · `wave` svg presentacional aria-hidden) · **SIN campo `events`** · `expression: 'delegated'` (la firma perceptiva es del Slider embebido) · el part `Cursor` del borrador PODADO como especulativo (el thumb del Slider ES el playhead) | ✅ 4/4 (validate lanza-o-no, no lista · pin de cero eventos vía `'events' in`) · vocabulario limpio |
| **F3 — Soma** ✅ **2026-07-31** | `WaveformProvider` (geometría TESTEABLE en la clase: `buildWavePath` — bars = trazos verticales con FLOOR perceptivo 0.5 y ancho vía `stroke-width` de la recipe; wave = `area()` de plots espejada — · `progressFraction` clampada · label localizado para el Slider) · `WaveformWaveProvider` (renderProps) · wrapper componiendo **Slider completo** (SecondaryRange+Range+Thumb; reenvíos de `readonly`/`disabled`/`step`/`valueText`/`secondaryValue`) · Wave svelte con el **clip de progreso** (2 copias del MISMO path; `data-waveform-played`/`-remaining` hooks eidos-only) | ✅ 4/4 (contrato+geometría exacta `M25.00 15.5V16.5M75.00 1V31` · área cerrada+clamp · Wave presentacional · degradación sin picos) — lección re-aplicada: data reactivos del morfo se miden EN EL ELEMENTO tras tick (syncAttrs) |
| **F4 — Eidos** ✅ **2026-08-01** | Wrapper raíz (carga `slider.css`+`waveform.css`; `data-size` resuelto por ActiveEidos) · `Wave` passthrough · recipe: bars = stroke en UNIDADES DE VIEWBOX (el svg estira con `preserveAspectRatio="none"` → ciclo barra/hueco constante) / wave = fill sin stroke · RTL espejo CSS (`[dir='rtl']` → `scaleX(-1)`, mismo borde que el thumb) · readonly cursor · disabled vía `:has` (la onda vive FUERA del slider) · Slider en scope: track/range transparentes, secondary = velo 14%, thumb = playhead `2px×100%` (scale-active 1: una línea a alto completo no puede crecer sin desbordar), hit = caja completa (specificidad 3-attr, independiente del orden de carga) · tokens `waveform:{height-xs…xl, bar-width, color, color-played, playhead-width}` + generate — `playhead-width` AÑADIDO sobre la lista firmada: el thumb cuadrado (`--slider-thumb-size-*`) no expresa una línea · guards: fila en `component-visual-attrs` + sufijos `played`/`remaining` en la allowlist de `eidos-lint-all` | ✅ `recipe-css-contract` PASS · `eidos-lint` 0 inválidos (4 morfo-backed) · `component-api-contract` PASS · `check` 0 propios |
| **F5 — Demo + dossier** ✅ **2026-08-01** | Demo con picos REALES (fetch `/sounds/*.wav` → `uix.sound.decode` → `uix.sound.peaks`; 5 señales conmutables + `buckets` vivo + degradación declarada si no hay contexto) · cada prop = control vivo (shape/value/step/secondaryValue/readonly/disabled/dir/size) · trace sema del Slider embebido · 6 tabs · READMEs soma+eidos (comparativa wavesurfer/peaks.js/SoundCloud/WhatsApp; `## Passive justification` = delegación D-WF.1/D-WF.8) · **fix F3 declarado**: `dir` NO se reenviaba al Slider embebido — completado el patrón de reenvíos (types+wrapper soma; verificado en vivo: thumb ancla `right:0%` en RTL) | ✅ `component:audit --only waveform` PASS · `docs:check` 0 · `check` 0 propios · sonda en Chrome vivo (5173): picos reales pintados, clip↔thumb lockstep exacto, shape/size/RTL/readonly vivos |
| **F6 — Mirada** ✅ **2026-08-01** | **FIRMADA por el usuario** («podemos darlo por bueno el waveform»), contrastando el render contra el reproductor de **Suno AI** — que valida dos decisiones del gate: **barras** (D-WF.5, lectura SoundCloud) y los dos colores reproducido/pendiente como lo esencial (Suno ni siquiera pinta buffered; en el nuestro es opcional y arranca apagado). La mirada costó DOS correcciones que ninguna sonda había visto: (1) el **anillo del `commit`** enmarcando el control entero — firma global de la familia, exenta ahora en `slider.css`/`media-player.css` (commit `df86a4e50`); (2) el **buffered**, rechazado dos veces — primero por color (velo neutro = mismo token que la onda) y luego por FORMA (copia del path = ilegible por construcción, «confunde visualmente»): acabó en banda recta con acento lavado (`905012507`). Ojo para el futuro: con el panel oculto las CSSTransitions quedan `running` congeladas y `getComputedStyle` da valores INTERMEDIOS — medir la cascada (custom props), no los usados | ✅ mirada del usuario |
feat(waveform): F1-F3 — sound.peaks, morfo delegado y soma componiendo Slider Waveform (gate D-WF.1-8 firmado, PLAN-waveform.md): la visualizacion de audio cuyo contrato es el DATO y su pintura — la interaccion ES el Slider canonico. - F1: uix.sound.peaks(buffer, buckets) en el art — max absoluto por bucket sobre todos los canales, normalizado por el bucket mas alto (documentado); puro, sin contexto. El flujo natural decode -> peaks en la misma puerta. - F2: morfo con DOS partes (provider con data-shape/data-readonly; wave svg presentacional aria-hidden), SIN campo events y expression 'delegated' — re-declarar drag/commit seria la duplicacion que D-AP2.13 retiro del player. El part Cursor del borrador, PODADO como especulativo (el thumb del Slider embebido ES el playhead). - F3: WaveformProvider con la geometria testeable (buildWavePath: bars = trazos verticales con piso perceptivo 0.5 — el silencio pinta linea fina, no hueco — y ancho de barra via stroke-width de la recipe; wave = area() de $libs/plots espejada) + progressFraction clampada; wrapper que compone el Slider COMPLETO (SecondaryRange G-2 + Range + Thumb, con valueText G-1 y readonly/disabled/step reenviados); Wave con el clip de progreso (dos copias del mismo path, hooks eidos-only -played/-remaining). Verificacion: art+port 42/42 - morfo 4/4 - soma 4/4 - check 0 propios en los arboles del waveform - vocabulario limpio. Quedan F4 (recipe eidos + tokens, disenada en el CONTINUE), F5 (demo+dossier+audit) y F6 (mirada del usuario). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
## 6. Fuera de alcance (con disposición)
Regions/selección (el modelo wavesurfer-plugin — el clip v2 del player tiene su
propio diseño congelado) · zoom · render en vivo del micrófono (eso es
analyser + `$scene`, la otra disposición del motor) · minimap.

Powered by TurnKey Linux.