Skip to content

explore: colour rendering across all JSON Canvas elements (not just gradients) #61

@LeslieOA

Description

@LeslieOA

Status: parked / low priority. Scoped down from "ship OKLCH" to "explore colour holistically, later." See the post-mortem below for why the first attempt was abandoned.

What this is now

A standing, low-priority invitation to revisit how colour is rendered across the whole canvas — node fills, borders, backgrounds, card tints, edges, group labels, and gradients — rather than chasing one isolated effect. If we touch colour again, do it as a deliberate, holistic pass with a clear visual target, not a point fix.

Background: the OKLCH gradient investigation (closed without shipping)

The original ask was "can we use OKLCH for gradients?" We investigated thoroughly and shipped nothing. The reasoning, preserved so we don't re-tread it:

1. Native OKLCH gradient interpolation — unavailable

  • @shopify/react-native-skia (2.6.x) does not expose an interpolation colour space on MakeLinearGradient / <LinearGradient>. The CSS Color 4 Interpolation struct exists in Skia-the-C++-engine but isn't plumbed through to the JS binding. Skia interpolates gradient stops in sRGB, full stop.
  • Even if it were exposed: the current cc-card-gradient-Ndeg is a single-hue alpha fade (active → activeTransparent, same hue). Interpolation colour space is moot when both endpoints share a hue — OKLCH vs sRGB would be pixel-identical. It would only matter if gradients ever fade between different colours (a future design change).

2. OKLCH palette regen — tried, reverted

We then pivoted to "regenerate the preset palette in OKLCH for perceptually-uniform brightness." Two failure modes:

  • Uniform-L OKLCH was actively wrong. Forcing all six presets to a common OKLCH lightness flattened the deliberately non-uniform Obsidian/hesprs palette (yellow & cyan are meant to be bright/poppy). It read as muted and underwhelming on real canvases — confirmed visually on hesprs-demo.canvas.
  • OKLCH anchored on the real vibrant hexes ≈ identical to the old HSL. active / border / background / activeTransparent are just hex + alpha either way; OKLCH only changes the card-tint computation cosmetically. And its headline safety feature — automatic sRGB gamut mapping — buys nothing here, because every input (preset HSL, user #rrggbb) is already in-gamut sRGB.

Net: OKLCH never produced a user-visible win for this codebase. Continuing would have added a runtime dep (use-color) + import-path caveats to a published library for zero benefit. Abandoned.

Canonical palette (the "Grand" look — keep this)

Source of truth, verified from reference git history at packages/canvas-ui/src/theme.ts (recovered at 709086ec^, just before that package was retired). Byte-identical to our current src/renderer/theme.ts. HSL presets, "chosen to match the Obsidian/hesprs viewer aesthetic":

Code Colour HSL Rendered hex
0 neutral gray [0, 0, 40]
1 red [2, 78, 55] #e63933
2 orange [29, 90, 55] #f48925
3 yellow [48, 90, 55] #f4ca25
4 green [142, 60, 45] #2eb860
5 cyan [204, 80, 55] #309fe8
6 purple [270, 60, 55] #8c47d1

The non-uniform perceived brightness is the aesthetic — do not "correct" it.

Spec conformance note

JSON Canvas spec accepts exactly two color formats: hex (#RRGGBB) and preset codes "1""6". Exact preset shades are explicitly renderer-defined ("intentionally not defined so that applications can tailor the presets"). Spec labels code 5 "cyan"; ours leans blue (#309fe8) — conformant, but a faithful-cyan nudge is a candidate if we ever do this pass.

If/when we pick this up — possible scope

  • Audit colour across all element types (fills, borders, backgrounds, edges, group labels, gradients) for consistency
  • Decide whether gradients should ever fade between different colours (the only thing that unlocks a real OKLCH/perceptual win)
  • Faithful-cyan for preset 5 (cosmetic)
  • Revisit if/when a Rust core lands (palette crate makes perceptual colour + gamut mapping cheap and shared across platforms) — then the architecture argument exists, even if the per-pixel one still doesn't

Decision

Not doing OKLCH now. Keep the canonical HSL palette. This issue stays open as a low-priority exploration of canvas colour as a whole.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestlow priorityNice-to-have; explore when time allows

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions