What this simulator is, how it works, and how to use it.
What is this?
Rosemaling is a physically based painting simulator. Ordinary
painting apps store display colors (RGB) and blend them with arithmetic; that is
why mixing blue and yellow in them gives grey. Rosemaling instead stores
which real pigments, and how much of each, sit at every point of the
canvas, and computes what that physical film of paint looks like — so
blue + yellow makes green, thin paint glazes, thick paint hides, and a painting
can be re-lit or examined like a real object.
Everything runs on your device, in the browser. After one visit it works fully
offline and can be installed to a home screen; no image or document ever leaves
your machine.
How it works
Every texel of the canvas holds pigment amounts — quantities of
up to eight real paints plus a clear-medium channel — not a color. Appearance is
computed from that state each frame:
Measured pigments. Each paint in the libraries (Golden Matte
Fluid and Heavy Body acrylics, and 40 classical oil pigments) carries measured
absorption and scattering spectra — K(λ) and S(λ) — from published
spectroscopy, sampled on a 31-band grid across the visible spectrum (extended
into UV and near-IR for the technical views).
Spectral Kubelka–Munk optics. Mixtures combine by
concentration-weighted K and S; the renderer solves the finite-thickness
Kubelka–Munk equations for the reflectance of the wet film over whatever lies
beneath it — the ground, or dried paint layers. Thin, medium-rich films fall
into a Beer–Lambert glaze regime; thick films hide. Subtractive mixing,
hiding power, and glazing are consequences of the physics, not painted-on
features.
Two engines, one truth. A WebGPU compute engine runs the
product; a pure-TypeScript CPU engine is the reference implementation the GPU
kernels are validated against, texel for texel.
Brush transport. Strokes exchange paint in both directions —
the brush deposits and picks up — so brushes get dirty, wet paint
smears into wet paint, and the palette surface mixes like a real palette. The
brush's reservoir is spatial: an unevenly loaded brush paints unevenly.
Relief and gloss. Paint has thickness; a height field shades
impasto under a movable directional light, canvas weave catches dry-brush
strokes, and surface gloss follows the medium content.
Light × sensor rendering. The final color is the film's
reflectance integrated against an illuminant and a set of sensor
sensitivities. Swapping those matrices gives daylight, tungsten, UV-365
examination (with real fluorescence, including optical-brightener papers), IR
reflectography, and a measured digital-camera rendering — one renderer, many
instruments.
Using the Paint page
Getting paint onto the brush
Pick a palette (classical oils or a Golden acrylic line) — or press
Edit palette… to assign any paint from any library to the eight wells.
Click a well to arm a squirt, then tap the palette (or
canvas) to drop a glob of paint.
Stroke through the glob to load the brush — like a real
palette. Strokes on the palette surface mix paint exactly as on the canvas.
Painting
Size sets the brush radius (down to 1 px); Size ←
pressure makes pressure drive the radius. With a pen, pressure and
tilt are live; with a mouse, set pressure with the slider or scroll wheel.
Round and flat brushes; the flat's blade can
follow the stroke, hold a fixed angle, or follow pen tilt.
The brush picks up what it touches — drag through wet paint
and the next stroke carries it. Wipe partially unloads the brush;
Rinse empties it.
Glazing:Dip in medium charges the brush with clear
medium; heavily diluted paint goes down as a transparent glaze. Glaze over a
dried layer to deepen color the way real glazing does.
Layers and drying
Dry layer commits the wet paint to the dried stack — it
stops smearing and becomes a substrate you can glaze over.
Dried layers can be undried (made editable again), deleted,
or reordered; nothing is ever flattened to pixels.
The ground select swaps the substrate — white gesso, black,
cream paper, umber-toned, or an optically brightened paper (which glows under
UV).
Looking at the painting
Light azimuth/elevation move the raking light; impasto and
canvas texture respond. Toggle Relief and Texture off for a
flat view.
Spectral view re-renders the same paint under D65 daylight,
tungsten, D50, UV-365 examination, IR reflectography, or a real camera's
sensitivities. A provenance note warns when a view depends on assumed (rather
than measured) data.
Thickness mode shows the film-height map.
Documents
Undo/redo: buttons or Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z.
Save/Load writes a .rosem file — the full
pigment state of every layer, reopenable and re-lightable, not a flat image.
Export PNG renders the current view.
Canvas size adapts to your hardware by default; larger
sizes cost real GPU memory.
The other pages
The Mixing lab is the physics
workbench: pick two or three real paints, sweep the mixing ratio, and compare
spectral Kubelka–Munk mixing against Mixbox and naive RGB interpolation, with
the underlying spectra and a virtual drawdown card. The
Feel bench is a development tool that
replays a deterministic stroke set under different feel parameters so brush
tuning is comparative rather than vibes.
Accuracy & provenance
Rosemaling prefers measured data and says so when it doesn't have it. Each
pigment's spectra are labeled by provenance (measured / derived / assumed, per
spectral range); technical views display a reliability warning when the
materials on screen lean on assumed data outside their measured range. The
simulation is a model, not a metrological instrument: Kubelka–Munk is an
approximation, some scattering coefficients are derived under stated
assumptions, and feel parameters are tuned by hand. Where spectral data could
not be found, plausibility wins over false precision — and the UI tells you.
Golden acrylic paint spectra — two-constant K/S for Golden
Matte Fluid (Okumura 2005, RIT MS thesis) and Golden Heavy Body (Berns 2016,
CIC24), courtesy of Golden Artist Colors and
R. S. Berns / RIT Munsell Color Science Laboratory
(Mellon "Art Spectral Imaging" project). Measured reflectance from the Berns
2022 Golden acrylics release.
Classical oil pigments — IFAC-CNR
Fiber Optics Reflectance Spectra of Pictorial Materials database
(Aldrovandi et al.), 270–1700 nm; digitized from the published plots.
Modern watercolours — IFAC-CNR MoWCReS database. Both cited
with thanks to IFAC-CNR, Florence.
Pigments Checker reference spectra — Cultural Heritage
Science Open Source (CHSOS, A. Cosentino).
Colorimetry — CIE 1931 color-matching functions and standard
illuminants from the official CIE datatables (CIE 018:2019 /
ISO/CIE 11664).
Camera sensitivities — Jiang, Liu, Gu & Süsstrunk,
"What is the Space of Spectral Sensitivity Functions for Digital Color
Cameras?" (WACV 2013), via Zenodo — CC BY-NC-SA 4.0.
Fluorescence data — PhotochemCAD and the Oregon Medical
Laser Center (OMLC) spectra collections; FPbase (CC BY-SA 4.0);
optical-brightener curves digitized from AAT Bioquest; UV-fluorescence
literature by Pelagotti et al. 2005, Pronti et al. 2017, and Caccia et
al. 2023.
"Golden" and other paint names are trademarks of their respective owners and
are used here to identify the measured materials; no affiliation or endorsement
is implied. Simulated renderings are approximations of the named paints, not
color-accurate specifications. If you are a rights holder of any dataset above
and want a correction, please open an issue on the repository.