diff --git a/src/uix/eidos/COLOR_ENGINE_RFC.md b/src/uix/eidos/COLOR_ENGINE_RFC.md index 8a598d04f..60b809483 100644 --- a/src/uix/eidos/COLOR_ENGINE_RFC.md +++ b/src/uix/eidos/COLOR_ENGINE_RFC.md @@ -326,7 +326,10 @@ expone con un input de color por fila + «auto» para volver a derivado. **Los 6 intents NO se derivan** — son hues canónicos del libro (un error es rojo siempre). `harmonize(color, toward, amount)` (M3 `blend.harmonize`) los empuja hacia -la marca un % si el builder quiere cohesión — opt-in, conserva L y C. +la marca un % si el builder quiere cohesión — opt-in, conserva L y C. Un valor +**sutil (~10-15%)** hace que los intents se sientan de la familia **sin perder su +lectura** (rojo sigue rojo); el builder de `/temas/color` lo usa como default (slider +0 = canónico puro → fuerte). Resuelve el "los intents puros chirrían con la marca". **Caveat del +60°**: la rotación de Material puede caer cerca de un intent según el primary (p. ej. `purple + 60° = H6 ≈ red/threat`). Por eso el tema base afinó su diff --git a/web/routes/temas/color/+page.svelte b/web/routes/temas/color/+page.svelte index 51884eb03..7990887e6 100644 --- a/web/routes/temas/color/+page.svelte +++ b/web/routes/temas/color/+page.svelte @@ -118,7 +118,9 @@ let seedHex = $state('#8e4ec6') let builderVariant = $state('tonal') - let harmonizeIntents = $state(false) + // Subtle by default: intents lean toward the brand enough to feel cohesive but + // stay recognizable (red is still red). 0 = pure canonical. (M3 harmonize.) + let harmonizeAmount = $state(0.12) // Per-role overrides the designer pinned (role → hex). Empty = fully derived. let overrides = $state>({}) @@ -184,11 +186,12 @@ for (const { role, seed } of schemeSeeds) { if (role !== 'neutralVariant') emitRole(parts, role, seed, bg) } - if (harmonizeIntents) { + if (harmonizeAmount > 0) { for (const intent of INTENTS) { if (intent === 'neutral') continue const baseHex = activeScales[CANONICAL_INTENT_SCALES[intent]]?.['9'] - if (baseHex) emitRole(parts, intent, harmonize(parseColor(baseHex), seedOklch, 0.22), bg) + if (baseHex) + emitRole(parts, intent, harmonize(parseColor(baseHex), seedOklch, harmonizeAmount), bg) } } return parts.join(';') @@ -252,8 +255,9 @@ con su pick on-solid (APCA), y aplica el tema a TODA la página en vivo (override de --primitive-{'{role}'}-* en .root → reproyecta toda la jerarquía + el chrome neutral; en una app real sería setCssVariables). La - librería de 31 escalas y los 6 intents canónicos NO cambian — salvo que actives - harmonize intents (los empuja hacia la temperatura del seed). Y puedes + librería de 31 escalas NO cambia. Los 6 intents se armonizan suavemente + hacia la marca (slider; 0 = canónico puro) para que no se sientan desentonados, sin perder su + lectura — rojo sigue siendo rojo. Y puedes fijar cualquier rol con su propio color (el input de cada fila); los demás se siguen derivando del seed.

@@ -276,8 +280,9 @@ {/each}
@@ -332,7 +337,9 @@ Escalas funcionales (1-2 fondos · 3-5 componente · 6-8 bordes · 9 sólido · 10 hover · 11-12 texto). El representativo de cada escala es el paso 9. La paleta la trae el tema; el framework envía estas 31 (valores - Radix exactos, listos para autoría OKLCH). + Radix exactos, listos para autoría OKLCH). Es la librería fija de + referencia — el seed del builder NO la cambia: deriva los roles (arriba), + que son escalas generadas nuevas, no miembros de esta lista.

@@ -829,6 +836,10 @@ color: var(--color-content-secondary); cursor: pointer; } + .builder-harmonize input[type='range'] { + max-inline-size: 120px; + accent-color: var(--color-primary-solid); + } .role-pin { display: inline-flex; align-items: center;