← All guides

AlgiViz 0.8.0 · Canvas / TypeScript

Custom canvas palettes in AlgiViz 0.8.0

Author: Grundy · Checked: October 19, 2026

A canvas does not inherit CSS colors. When the Grundyjs design preview gained light and dark themes and custom backgrounds, the algorithm visualization kept its own palette. We first solved this with a website renderer, then added palette overrides to AlgiViz 0.8.0 and removed the duplicate drawing code. Here is the problem, the library change and the integration that keeps the current animation frame.

1. Two themes did not cover the website palette

Before 0.8.0, createArrayRenderer accepted only theme: light or dark. Choosing light was useful, but it could not match a custom page background, text or element colors. Changing a CSS variable does not repaint pixels already drawn on a canvas. We needed one source of colors for CSS, the algorithm example and the CanvasTake recording scene. The website remains responsible for detecting the system theme, storing the visitor’s choice and requesting a redraw.

2. The temporary fix revealed a library boundary

AlgiViz already exposed arrayScene, createSceneProjector and createSceneRenderer. The site used them to build a renderer with its own colors, while keeping the existing algorithm steps and player. That worked, but duplicated bar layout, transitions, labels and highlighting rules. A palette should not require maintaining another implementation of the same visualization. The reusable change belonged in the standard array renderer.

3. Override only the colors you need

Install @grundyjs/algiviz@0.8.0. The /canvas entry point now accepts colors alongside theme. It merges the supplied roles with the selected built-in theme. In this setup example, ordinary bars, active items and sorted items retain their light-theme colors. Omitted properties and explicit undefined retain the theme value. Existing calls that specify only the theme and the createSortRenderer alias still work. ArrayPaletteOverrides is the exported type for partial overrides; ArrayRendererOptions describes the whole options object.

import { createArrayRenderer } from "@grundyjs/algiviz/canvas";

const renderer = createArrayRenderer({
    theme: "light",
    colors: {
        background: "#eef4c7",
        text: "#202438",
        held: "#87431d",
    },
});

4. Use semantic roles rather than one accent everywhere

ArrayPalette contains six colors: background for the canvas, text for labels, bar for ordinary elements, sorted for final positions, active for highlighted operations and held for the selected key. This full palette is an example, not a required theme. Keep the states distinguishable and keep the accompanying legend consistent with them. A green sorted region should not silently become indistinguishable from an active comparison when the visitor changes the site accent. AlgiViz does not automatically check color contrast or generate accessible colors.

import type { ArrayPalette } from "@grundyjs/algiviz/canvas";

const palette: ArrayPalette = {
    background: "#f4f1fb",
    text: "#202438",
    bar: "#475569",
    sorted: "#047857",
    active: "#b45309",
    held: "#7c3aed",
};

5. Replace the renderer, keep the current frame

A renderer copies its palette at creation. Mutating the original colors object later does not update it. Create a new renderer for the new theme, then render the frame already held by the view. The browser adapter below accepts a canvas with dimensions already configured and an initial ArrayFrame from your timeline. Feed later frames into view.render(frame); call view.setPalette(theme, colors) from your theme control. It neither creates nor restarts the timeline, and does not seek to time zero. Canvas sizing and devicePixelRatio handling stay in the application’s display adapter.

import { createArrayRenderer } from "@grundyjs/algiviz/canvas";
import type { ArrayPaletteOverrides, ArrayRendererOptions } from "@grundyjs/algiviz/canvas";
import type { ArrayFrame } from "@grundyjs/algiviz/array";

export function createPaletteView(canvas: HTMLCanvasElement, initialFrame: ArrayFrame) {
    const context = canvas.getContext("2d");
    if (!context) throw new Error("Canvas 2D is unavailable");

    let currentFrame = initialFrame;
    let renderer = createArrayRenderer({ theme: "light" });

    const render = (frame: ArrayFrame) => {
        currentFrame = frame;
        renderer.render(context, frame);
    };

    render(initialFrame);

    return {
        render,
        setPalette(theme: ArrayRendererOptions["theme"], colors: ArrayPaletteOverrides = {}) {
            renderer = createArrayRenderer({ theme, colors });
            render(currentFrame);
        },
    };
}

6. The website now needs only a color adapter

The design preview computes light and dark tokens for CSS and canvas. SortingPlayer passes those colors to AlgiViz’s standard renderer; the separate scene renderer was removed. The site calls its canvas background canvasBackground, while the library calls it background, so the remaining adapter only maps property names. Semantic operation colors stay separate from the visitor’s accent. CanvasTake’s recording example reads the same theme tokens but draws its own scene: palette support in AlgiViz does not configure another library automatically.

import type { ArrayPalette } from "@grundyjs/algiviz/canvas";

type SiteCanvasColors = {
    canvasBackground: string;
    text: string;
    bar: string;
    sorted: string;
    active: string;
    held: string;
};

function arrayPalette(colors: SiteCanvasColors): ArrayPalette {
    return {
        background: colors.canvasBackground,
        text: colors.text,
        bar: colors.bar,
        sorted: colors.sorted,
        active: colors.active,
        held: colors.held,
    };
}

7. Verify states, geometry and theme changes

The site checks both themes on start, compare and select frames, including a held item, duplicates and a negative value. It checks background, text and all four element roles, compares drawing coordinates and labels against the default AlgiViz renderer, and verifies that switching palettes leaves the frame and snapshots unchanged. DPR checks also passed. Algorithm checks, lint and the production build passed for the 0.8.0 integration. These automated checks do not establish visual contrast in every custom palette. Also inspect light and dark themes, paused and playing frames, and narrow screens in a browser. Verify readability and the distinction between operation colors before choosing the final palette.

8. What changed and what stayed in the application

The library gained a small extension point instead of a second player or a website-specific theme system. Existing calls keep their default colors. The site controls theme preference, persistence and repainting, while AlgiViz owns the standard array drawing. This integration is currently on the minimal design preview; it is not a claim that every algorithm page has already moved to the new website theme. Future palette tuning can happen in the site’s tokens without copying the array renderer again.