@ -57,29 +57,35 @@ Curva medida (Playwright, `keyboard.type` 20 chars; incluye overhead CDP):
| 300 KB base64 | 12.8 |
| 2 MB base64 | 17.9 |
→ ** ~+4 ms/MB/char**, monotónico. Tras descartar historia/render/html/value, el
residual parece **intrínseco del navegador** : un atributo `src` de varios MB en
el DOM del contenteditable ralentiza el tecleo (layout/entrada). La única forma
de eliminarlo es **que el DOM no cargue el data-URL gigante** .
## Opciones de fix (DECISIÓN PENDIENTE)
1. **Aviso dev + cap de tamaño** (bajo riesgo, mensaje correcto): sin adapter,
`console.warn` en dev («imágenes como base64 hinchan el documento; pasa
`onUploadImage` ») + rechazar/avisar imágenes > N MB en el fallback.
2. **Downscale antes de base64** (trabajo medio): en el fallback, redimensionar
con canvas a un máximo (p.ej. 1600px) antes de convertir → el data-URL baja de
MB a ~decenas de KB → el atasco desaparece en la práctica.
3. **Render como blob URL** (fix completo, complejo): el modelo guarda base64
(persistencia) pero el RENDER usa un `blob:` URL corto → el DOM queda ligero →
cero jank aun con base64. Requiere gestionar el ciclo de vida del blob
(crear/revocar por bloque imagen).
4. **Solo documentar** : el fallback es dev-only; producción usa adapter. Cerrar
sin cambio de código.
**Doctrina existente**: el camino de PRODUCCIÓN es el adapter `onUploadImage`
(F4.1, `31d49c88` ) → el JSON guarda una URL, nunca base64 (test lo verifica). El
base64 es el fallback de conveniencia dev.
→ ** ~+4 ms/MB/char**, monotónico. (Hipótesis inicial ERRÓNEA: «el `src` de MB en
el DOM»; ver la causa real abajo.)
## Causa REAL (hallada por CPU profile — 2026-07-20) ✅ RESUELTA
Un **CPU profile** del tecleo con la imagen de 2MB fue definitivo: ** `samePalabrasDocument`
= 34% de las muestras** (391/1140). Es una **comparación DEEP de documentos** en
`syncExternalState` (el sync del `bind:value` , `palabras-provider.svelte.ts` ):
compara el `value` bindeado contra el doc interno EN CADA cambio. Como el editor
escribe `value` con la MISMA referencia del doc interno (`publishState` →
`this.document` ), esa comparación recorría el string base64 (MB) por tecla **para
nada**. NO era el DOM, ni la historia, ni `html` .
**Fix 1 — `d96e4cde7` ** (el que arregla el atasco): check de igualdad por
REFERENCIA antes del deep-compare — el caso común (ediciones propias) en O(1); el
`samePalabrasDocument` solo corre si la referencia difiere de verdad. Medido:
**20 → 12 ms/char**.
**Fix 2 — `013ef5afc` ** (win secundario): `$adom.DataUrlBlobUrls` + swap del `src`
de los `<img data:…>` por `blob:` URLs en palabras (el modelo conserva el base64).
El `src` de MB en el DOM SÍ añadía ~2-4ms. Medido: **12 → 8 ms/char** . Ubicación
valorada: la utilidad NO va en `<Image>` (ningún consumidor pasa base64 →
abstracción prematura); es reutilizable si algún día aparece uno.
**Sobre la raíz (base64-en-modelo sin adapter)**: sigue siendo dev-only por
diseño. El camino de PRODUCCIÓN es el adapter `onUploadImage` (F4.1, `31d49c88` ) →
el JSON guarda una URL, nunca base64. **Follow-ups opcionales NO hechos** : aviso
dev cuando no hay adapter + cap/downscale de tamaño (el atasco de TECLEO ya está
resuelto por los dos fixes; esto solo acotaría el PESO del documento).
## Repro (para re-verificar cualquier fix)