refactor: replace color-mix palette ramp with absolute OKLCH anchors - #627
Conversation
…ion recipes Adds user-manual/system-kolorow.md — a practical, task-oriented walkthrough of the color system built around a real landing-page layout (alternating light/dark bands with a single brand accent). Covers the three-layer mental model, the .sf-surface--* vs data-theme vs --sf-color-text--on-* decision, the primary/action split, ramps vs alpha variants, status tokens, and a section-by-section recipe. Also records three framework nits (status -subtle alpha 0.12 vs 0.10 for info/danger, the subtle-naming overload, and the old-engine .sf-surface degradation). Passes check:doc-refs (all --sf-*/.sf-* references live). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
The numeric brand ramps (--sf-color-{primary,secondary,tertiary,action,
neutral}-50…950) previously generated each step with color-mix() toward the
theme's --sf-color-surface (tints) / --sf-color-text (shades). When a chosen
source colour fell outside the lightness band between those two anchors — a
brand darker than the text colour, or a project that lightened --sf-color-
neutral — the shade half inverted: steps 600–950 came out lighter than 500 and
the ramp folded into a "U" (50 ≈ 950).
Generate each step in OKLCH instead by pulling the family colour's own
lightness a fixed fraction toward an ABSOLUTE target (--sf-palette-tint-l /
--sf-palette-shade-l), clamped with max()/min() so a tint can never end darker
than the base nor a shade lighter. The ladder is now monotonic light→dark for
any source colour and any anchor configuration; chroma is tapered toward the
extremes. Output is visually unchanged for default-palette colours (already
in-band); only out-of-band / moved-anchor cases are corrected. base is
untouched (already absolute-lightness).
Breaking: removed the --sf-palette-mix-50…950 knobs; replaced with two
lightness anchors --sf-palette-tint-l (0.97) and --sf-palette-shade-l (0.1).
- core/tokens.css: new ramp formulas + anchor knobs (base/alpha/status unchanged)
- tests/ramp-monotonic.spec.js: sweep the lightness axis for all 5 families,
assert the ramp never folds and no step is transparent
- token surface: snapshot, annotations, token-tiers, regenerated docs/registry
- demo/index.html: refresh coverage inventory + per-token default strings
- docs/llm-guide.md, user-manual/{colors,system-kolorow}.md: document the model
- configurator/domain-patterns.json: match "palette" so the new knobs categorise
- CHANGELOG: Bug Fixes + Breaking Changes entries
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
The Colors panel's "Palette ramp" section drove the ten removed --sf-palette-mix-* knobs (percentage-toward-surface/text sliders) and previewed each step with the old color-mix() formula. Swap it to the new model: - two 0–1 sliders for the lightness anchors --sf-palette-tint-l / --sf-palette-shade-l (replacing the ten percentage sliders) - Softer / Default / Punchy presets now patch the two anchors - the live primary-palette preview and the mini-palette strips compute each step with the absolute-anchor OKLCH formula, so the preview matches the framework and is always monotonic light→dark - domain-patterns keyword already updated to "palette" so the new knobs land in the colours domain (prior commit) Verified: svelte-check (0 errors), configurator unit suite (164 tests), curation gate, and a production vite build all pass; visually confirmed the panel renders the two anchor sliders and a monotonic palette preview. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. 💤 Files selected but had no reviewable changes (1)
⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR replaces per-step palette mix controls with absolute OKLCH tint and shade anchors, updates configurator controls and previews, refreshes generated token references and registries, adds monotonicity tests, and documents the revised color ramp and color-system usage. ChangesPalette ramp migration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ColorsPanel
participant CSSPaletteTokens
participant Browser
ColorsPanel->>CSSPaletteTokens: update tint and shade anchors
CSSPaletteTokens->>Browser: compute OKLCH palette steps
Browser->>ColorsPanel: render resolved palette swatches
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryReplaces the
Confidence Score: 4/5Safe to merge after fixing the CHANGELOG breaking-change entry, which currently contains layout-bugfix text that has no relation to the palette change. The CSS token formulas are correct and consistent across all five families; the configurator preview mirrors the CSS logic exactly; the monotonic test covers the edge cases that motivated the refactor. The one concrete defect is in CHANGELOG.md: the tokens breaking-change bullet has the layout em→rem description appended to it, leaving users who read the changelog to understand the migration path with a confusing, incomplete entry. CHANGELOG.md — the Breaking Changes bullet for the tokens refactor needs the accidentally-appended layout-fix text removed before this ships. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
SRC["--sf-color-{family} (source, L = l)"]
TINT_L["--sf-palette-tint-l (0.97)"]
SHADE_L["--sf-palette-shade-l (0.1)"]
SRC --> T50["50: max(l, l+(tint_l-l)×0.95) · c×0.20"]
SRC --> T100["100: max(l, l+(tint_l-l)×0.88) · c×0.30"]
SRC --> T200["200: max(l, l+(tint_l-l)×0.72) · c×0.50"]
SRC --> T300["300: max(l, l+(tint_l-l)×0.52) · c×0.72"]
SRC --> T400["400: max(l, l+(tint_l-l)×0.30) · c×0.88"]
SRC --> T500["500: source colour itself"]
SRC --> S600["600: min(l, l+(shade_l-l)×0.16) · c×0.96"]
SRC --> S700["700: min(l, l+(shade_l-l)×0.36) · c×0.88"]
SRC --> S800["800: min(l, l+(shade_l-l)×0.58) · c×0.72"]
SRC --> S900["900: min(l, l+(shade_l-l)×0.78) · c×0.52"]
SRC --> S950["950: min(l, l+(shade_l-l)×0.90) · c×0.38"]
TINT_L -.-> T50
TINT_L -.-> T100
TINT_L -.-> T200
TINT_L -.-> T300
TINT_L -.-> T400
SHADE_L -.-> S600
SHADE_L -.-> S700
SHADE_L -.-> S800
SHADE_L -.-> S900
SHADE_L -.-> S950
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
SRC["--sf-color-{family} (source, L = l)"]
TINT_L["--sf-palette-tint-l (0.97)"]
SHADE_L["--sf-palette-shade-l (0.1)"]
SRC --> T50["50: max(l, l+(tint_l-l)×0.95) · c×0.20"]
SRC --> T100["100: max(l, l+(tint_l-l)×0.88) · c×0.30"]
SRC --> T200["200: max(l, l+(tint_l-l)×0.72) · c×0.50"]
SRC --> T300["300: max(l, l+(tint_l-l)×0.52) · c×0.72"]
SRC --> T400["400: max(l, l+(tint_l-l)×0.30) · c×0.88"]
SRC --> T500["500: source colour itself"]
SRC --> S600["600: min(l, l+(shade_l-l)×0.16) · c×0.96"]
SRC --> S700["700: min(l, l+(shade_l-l)×0.36) · c×0.88"]
SRC --> S800["800: min(l, l+(shade_l-l)×0.58) · c×0.72"]
SRC --> S900["900: min(l, l+(shade_l-l)×0.78) · c×0.52"]
SRC --> S950["950: min(l, l+(shade_l-l)×0.90) · c×0.38"]
TINT_L -.-> T50
TINT_L -.-> T100
TINT_L -.-> T200
TINT_L -.-> T300
TINT_L -.-> T400
SHADE_L -.-> S600
SHADE_L -.-> S700
SHADE_L -.-> S800
SHADE_L -.-> S900
SHADE_L -.-> S950
|
| // lightnesses and return, per sweep, the {step, lum, alpha} of every step. | ||
| function sweepFamily([family, steps, sourceLs]) { | ||
| const root = document.documentElement; | ||
| root.setAttribute('data-theme', 'light'); |
There was a problem hiding this comment.
Dark theme ramp monotonicity is not verified
sweepFamily always sets data-theme='light' and varies the source-light property. The dark theme uses --sf-color-{family}-source-dark tokens, which map to a separate --sf-color-{family} value under data-theme='dark'. A very light source-dark (e.g. L ≈ 0.98) would exercise the same clamp path that used to fold in the old model. Adding a second data-theme='dark' sweep with --sf-color-{family}-source-dark overrides would close this gap and make the guarantee symmetric.
…assignment
- CHANGELOG: the layout em→rem explanation had leaked onto the tokens
Breaking-Changes bullet (an Edit matched only the first sentence of the long
layout line); restore the full layout Bug-Fixes bullet and end the tokens
breaking bullet at its migration note (greptile P1).
- tests/ramp-monotonic.spec.js: add a second data-theme="dark" sweep driving
--sf-color-{family}-source-dark, so monotonicity is verified symmetrically in
both modes, not just light (greptile P2). Now 11 cases, all green.
- tests/ramp-monotonic.spec.js: drop the redundant `ctx.fillStyle = '#000'`
write immediately overwritten by `ctx.fillStyle = c` (code-scanning nit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
demo/index.html (1)
4266-4266: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUpdate the static token count to match the new inventory.
The PR summary notes a reduction in the total token count from 754 to 746 due to removing 10
mixtokens and adding 2anchortokens. Update this hardcoded number so the visual header accurately reflects the new token count.💡 Proposed fix
- <h3 id="cov-tokens-h" class="cov-area-h">Design tokens <span class="cov-count">754</span></h3> + <h3 id="cov-tokens-h" class="cov-area-h">Design tokens <span class="cov-count">746</span></h3>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@demo/index.html` at line 4266, Update the hardcoded cov-count value in the Design tokens header (id="cov-tokens-h") from 754 to 746, leaving the surrounding markup unchanged.
🧹 Nitpick comments (2)
tests/ramp-monotonic.spec.js (1)
22-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover hue, chroma, and anchor overrides in the sweep.
Every family is replaced with the same
oklch(L 0.16 264), so the loop repeats identical ramp math and does not validate “any source colour.” Add representative hue/chroma values and default, extreme, and inverted anchor pairs to protect the central contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/ramp-monotonic.spec.js` around lines 22 - 28, Update the test fixtures in ramp-monotonic.spec.js so the sweep exercises varied source hues and chromas rather than assigning every family the same color. Expand the anchor cases to include default, extreme, and inverted anchor pairs, ensuring the ramp assertions validate behavior for arbitrary source colors and all supported anchor configurations.docs/llm-guide.md (1)
1308-1311: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd missing semicolons to the CSS custom properties.
The properties
--sf-palette-tint-land--sf-palette-shade-lare missing trailing semicolons in this code block. While this is just documentation, adding the semicolons ensures it behaves as valid CSS if users copy and paste it into their stylesheets.♻️ Proposed refactor
/* Absolute OKLCH lightness poles the 50–950 numeric ramp reaches toward */ ---sf-palette-tint-l: 0.97 /* how light the lightest step (50) can reach */ ---sf-palette-shade-l: 0.1 /* how dark the darkest step (950) can reach */ +--sf-palette-tint-l: 0.97; /* how light the lightest step (50) can reach */ +--sf-palette-shade-l: 0.1; /* how dark the darkest step (950) can reach */ /* per-step pull fraction + chroma taper are baked into each family */🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/llm-guide.md` around lines 1308 - 1311, Add trailing semicolons to the `--sf-palette-tint-l` and `--sf-palette-shade-l` CSS custom property declarations in the documented palette block, preserving their existing values and comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@demo/index.html`:
- Around line 4813-4814: In the palette token list, swap the two adjacent
entries so --sf-palette-shade-l appears before --sf-palette-tint-l, preserving
the alphabetical order and matching the cov-data JSON sequence.
In `@user-manual/system-kolorow.md`:
- Around line 430-472: Remove the entire “Znalezione nieścisłości we frameworku”
section from the user-facing manual, including subsections 9.1–9.3, their
developer commentary, code snippets, and details block. Preserve the preceding
manual content and do not incorporate these findings into the documentation;
track them separately in an issue or internal document.
---
Outside diff comments:
In `@demo/index.html`:
- Line 4266: Update the hardcoded cov-count value in the Design tokens header
(id="cov-tokens-h") from 754 to 746, leaving the surrounding markup unchanged.
---
Nitpick comments:
In `@docs/llm-guide.md`:
- Around line 1308-1311: Add trailing semicolons to the `--sf-palette-tint-l`
and `--sf-palette-shade-l` CSS custom property declarations in the documented
palette block, preserving their existing values and comments.
In `@tests/ramp-monotonic.spec.js`:
- Around line 22-28: Update the test fixtures in ramp-monotonic.spec.js so the
sweep exercises varied source hues and chromas rather than assigning every
family the same color. Expand the anchor cases to include default, extreme, and
inverted anchor pairs, ensuring the ramp assertions validate behavior for
arbitrary source colors and all supported anchor configurations.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6f2e73ec-779b-49a2-b56f-fbdfe53ab657
⛔ Files ignored due to path filters (3)
configurator/src/data/api-index.generated.jsonis excluded by!**/*.generated.*configurator/src/data/token-registry.generated.jsonis excluded by!**/*.generated.*dist/css-custom-data.jsonis excluded by!**/dist/**
📒 Files selected for processing (20)
CHANGELOG.mdbadges/badge-optimal.jsonconfigurator/src/components/panels/ColorsPanel.svelteconfigurator/src/data/domain-patterns.jsoncore/tokens.cssdemo/index.htmldocs/api-index.jsondocs/api-index.mddocs/llm-guide.mddocs/registry.jsondocs/token-annotations.jsondocs/token-index.jsondocs/token-index.mddocs/tokens.mdscripts/token-tiers.jstests/ramp-monotonic.spec.jstests/token-api.snapshot.jsontoken-registry.jsonuser-manual/colors.mduser-manual/system-kolorow.md
…r-system-wr49vc # Conflicts: # docs/llm-guide.md
…ange The palette-ramp refactor nets -8 tokens (10 --sf-palette-mix-* removed, 2 anchors added). check:doc-refs enforces the 'N design tokens' claims against the live total; update both README mentions to 746. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
…manual - core/tokens.css: --sf-color-info-subtle and --sf-color-danger-subtle were 0.10 alpha while success/warning were 0.12, so danger/info alert backgrounds rendered slightly fainter than success/warning at the same content. Unify all four status -subtle washes to 0.12 (the finding documented while writing the colour manual). Regenerated value-bearing docs. - user-manual/system-kolorow.md: remove the "Znalezione nieścisłości we frameworku" section (§9) — maintainer-facing findings don't belong in a user manual (PR #627 review); renumber the cheatsheet §10 → §9. Also refresh one stale §8 rationale ("ramp computed for a specific background") to the new solid-colour-doesn't-blend wording. - CHANGELOG: note the status -subtle alpha fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
demo/index.html (1)
4454-4454: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUpdate stale alpha values for status subtle colors. The PR unified all status subtle-color alpha values to
0.12, but the static coverage defaults fordangerandinfowere missed and remain at0.1.
demo/index.html#L4454-L4454: change0.1to0.12in thedata-cov-defaultattribute for--sf-color-danger-subtle.demo/index.html#L4463-L4463: change0.1to0.12in thedata-cov-defaultattribute for--sf-color-info-subtle.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@demo/index.html` at line 4454, Update the static coverage defaults for --sf-color-danger-subtle in demo/index.html:4454-4454 and --sf-color-info-subtle in demo/index.html:4463-4463, changing each alpha value from 0.1 to 0.12 in its data-cov-default attribute.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@demo/index.html`:
- Line 4454: Update the static coverage defaults for --sf-color-danger-subtle in
demo/index.html:4454-4454 and --sf-color-info-subtle in
demo/index.html:4463-4463, changing each alpha value from 0.1 to 0.12 in its
data-cov-default attribute.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 79a2b8f5-3a68-48c9-a367-7ddcb891193b
⛔ Files ignored due to path filters (2)
configurator/src/data/api-index.generated.jsonis excluded by!**/*.generated.*dist/css-custom-data.jsonis excluded by!**/dist/**
📒 Files selected for processing (12)
CHANGELOG.mdREADME.mdcore/tokens.cssdemo/index.htmldocs/api-index.jsondocs/api-index.mddocs/llm-guide.mddocs/token-index.jsondocs/token-index.mddocs/tokens.mdtests/ramp-monotonic.spec.jsuser-manual/system-kolorow.md
🚧 Files skipped from review as they are similar to previous changes (9)
- docs/tokens.md
- CHANGELOG.md
- docs/token-index.md
- tests/ramp-monotonic.spec.js
- docs/api-index.json
- docs/llm-guide.md
- core/tokens.css
- docs/token-index.json
- docs/api-index.md
The status -subtle alpha was unified to 0.12, but the hand-maintained data-cov-default display strings for --sf-color-danger-subtle and --sf-color-info-subtle in the coverage inventory still read 0.1 (PR #627 review). Display-only; all four status -subtle now show 0.12. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
Summary
Replaces the
color-mix()-based palette ramp model with an absolute OKLCH lightness anchor system. The numeric color steps (50–950) now pull each family colour's own lightness a fixed fraction toward absolute targets (--sf-palette-tint-land--sf-palette-shade-l), clamped to prevent folding. This guarantees monotonic light→dark ordering for any source colour and anchor configuration.Key changes:
--sf-palette-mix-*knobs (50, 100, 200, 300, 400, 600, 700, 800, 900, 950); replaced with 2 PUBLIC-ADVANCED anchors:--sf-palette-tint-l(default 0.97) and--sf-palette-shade-l(default 0.1)oklch(from …)relative colour syntax with per-step pull fractions and chroma tapertests/ramp-monotonic.spec.jsto verify the ramp never folds across any source lightnessWhy: The old model folded into a "U" shape when a source colour fell outside the anchor band (e.g., a very dark primary on a light theme). The absolute-anchor model with clamping guarantees a monotonic ladder regardless of source position or theme, while reducing the number of tunable knobs from 10 to 2.
Type
Checklist
feat:,fix:,docs:, …) — enforced by commitlintnpm run lint:csspasses (stylelint)npm run buildrebuildsdist/(bundles are git-ignored; CI rebuilds and stamps headers)npm testpasses (unit + Playwright e2e) — newramp-monotonic.spec.jsverifies monotonicitynpm run check:version)core/*.css,optional/*.css, ortoken-registry.jsonchanged (npm run check:llm-guide)npm run check:macros,check:registry,audit:check)CHANGELOG.mdupdated under## [Unreleased](for user-facing changes)system-kolorow.mdadded with full colour system guideNotes
user-manual/system-kolorow.md(497 lines) provides a complete walkthrough of the three-layer colour model, decision tree, and section-by-section landing page example. Addresses the most common confusion points (.sf-surface--*vsdata-themevs--sf-color-text--on-*).ramp-monotonic.spec.js, which sweeps source lightnesses from 0.06 to 0.98 and confirms step luminance is always non-increasing from 50 to 950.ColorsPanel.svelteto show the newRAMP_CURVE(baked per-step fractions) and two anchor knobs instead of ten mix percentages. Preset curves ("Softer", "Bolder", "High contrast") now tune the two anchors.--sf-palette-mix-*https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF
Summary by CodeRabbit
--sf-palette-tint-land--sf-palette-shade-l.info/dangersubtle alpha levels (0.12).rem.