SVG + Color Batch
This stack runs image pixels through @stopcock/img, color math through @stopcock/color, then uses @stopcock/svg and @stopcock/svg/la to build the final vector overlay.
import { fromRGBA, simulateCVD } from '@stopcock/img'import { rgb } from '@stopcock/color'import { circle, fill, group, image, linear, pattern, rect, render, stroke, use, viewBox,} from '@stopcock/svg'import { symmetry, toQuad } from '@stopcock/svg/la'
const source = fromRGBA(rgbaBytes, width, height)const simulated = simulateCVD('deuteranopia', 1)(source)const href = canvasDataUrl(simulated)
const tile = pattern(image(href, width, height), width, height)const badgeFill = linear([ { offset: 0, color: rgb(0.2, 0.8, 0.45) }, { offset: 1, color: rgb(0.1, 0.4, 0.9) },])
const badge = toQuad([ [300, 58], [380, 42], [396, 112], [316, 132],])(fill(badgeFill)(rect(1, 1)))
const dots = symmetry(fill(rgb(1, 1, 1))(circle(7)), 2, [1, 0, 0, 1, 18, -4])
const doc = viewBox( 0, 0, 420, 220,)(group([fill(tile)(rect(260, 168)), badge, stroke(rgb(1, 1, 1), 5)(use(badge)), dots]))
render(doc)The important seam is the buffer convention: simulateCVD strips RGBA bytes into a packed Float64Array RGB channel buffer, calls the color batch API once over the full image, then recombines alpha. SVG stays vector-native and only quotes the processed bitmap through an <image> inside a hoisted <pattern>.