@pbroom/color-kit/reactPlane renderer

useColorPlaneRenderer

Rasterizes a color plane into a <canvas> you render: every pixel is the plane's color with the two axis channels set to that position.

functionimport { useColorPlaneRenderer } from '@pbroom/color-kit/react';use-color-plane-renderer.ts:153
function useColorPlaneRenderer(
  plane: ColorPlaneSpec,
  options?: UseColorPlaneRendererOptions,
): ColorPlaneRendererHandle;

The hook owns no DOM. Attach ref and canvasKey to a canvas, size it with CSS, and the hook keeps its backing store at the CSS size × device pixel ratio × resolutionScale (scaled down at lower quality), redrawing on resize and when the plane changes. It renders with WebGL by default and falls back to a CPU renderer when WebGL is unavailable or its context is lost, returning to WebGL once the context is restored; GPU resources are freed on unmount. Redraws are coalesced to one per animation frame and skipped when nothing that affects the pixels changed (moving along an axis channel does not repaint). With the default source: 'displayed', pixels are mapped into the display gamut and edgeBehavior decides whether out-of-gamut pixels clamp or turn transparent.

Parameters

planeColorPlaneSpec
Color and axes of the plane.

Returns

ColorPlaneRendererHandleA ColorPlaneRendererHandle to spread onto the canvas.

Throws

  • When both axes use the same channel.

Example

TSX
import { useColor, useColorPlaneRenderer } from '@pbroom/color-kit/react';

export function Plane() {
  const { requested } = useColor({ defaultColor: '#3b82f6' });
  const { ref, canvasKey } = useColorPlaneRenderer(
    { color: requested, axes: { x: { channel: 'l' }, y: { channel: 'c' } } },
    { displayGamut: 'srgb', edgeBehavior: 'transparent' },
  );
  return <canvas ref={ref} key={canvasKey} style={{ width: 240, height: 160 }} />;
}

Edge cases

  • Use canvasKey as the key. A canvas is locked to the first context kind requested from it, so switching between WebGL and the CPU fallback needs a new element. The hook bumps canvasKey when it does; without it as the canvas key, the fallback cannot paint and the hook warns once.
  • Destructure the handle. Write const { ref, canvasKey } = useColorPlaneRenderer(…). Passing handle.ref straight to JSX makes the React Compiler treat the whole handle as a ref, so reading handle.renderer during render is flagged.
  • Give the canvas a size. The backing store follows the canvas's CSS size × device pixel ratio × resolutionScale (times the quality multiplier), and a zero-sized canvas paints nothing. A ResizeObserver repaints on resize.
  • Context loss. On webglcontextlost the plane switches to the CPU renderer on a fresh canvas, and returns to WebGL when the browser restores the context. GPU resources are freed when the canvas unmounts.
  • Display gamut. Without displayGamut the pixels follow the nearest <Color> provider's active gamut, or 'display-p3' without one.
  • Axes must differ. Both axes on the same channel throw.