@pixerate/editor 0.137.0 → 0.139.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.d.cts +3 -3
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/index.cjs +57 -57
- package/dist/animation-editor/index.d.cts +6 -5
- package/dist/animation-editor/index.d.ts +6 -5
- package/dist/animation-editor/index.js +4 -4
- package/dist/{arrange-CKXK_hf7.d.cts → arrange-j_mLiFMO.d.cts} +1 -1
- package/dist/{arrange-BUREmgD9.d.ts → arrange-q5HQvnnB.d.ts} +1 -1
- package/dist/{bezier-Dywv3Bw8.d.ts → bezier-B6cK8SR6.d.ts} +2 -2
- package/dist/{bezier-CZ2AhjID.d.cts → bezier-CEJ8Uw4O.d.cts} +2 -2
- package/dist/{brushTypes-C7N3EBK7.d.cts → brushTypes-MX5UVs_m.d.cts} +27 -2
- package/dist/{brushTypes-C7N3EBK7.d.ts → brushTypes-MX5UVs_m.d.ts} +27 -2
- package/dist/{brushes-DJmUbIgz.d.ts → brushes-CQpL7_Lc.d.ts} +2 -107
- package/dist/{brushes-CnvZSYYU.d.cts → brushes-aEnjqoji.d.cts} +2 -107
- package/dist/{brushstrokeRender-IMFY3FF6.cjs → brushstrokeRender-PP6NTF6M.cjs} +52 -24
- package/dist/brushstrokeRender-PP6NTF6M.cjs.map +1 -0
- package/dist/{brushstrokeRender-2FAXA3XC.js → brushstrokeRender-QGEYJ4OZ.js} +40 -12
- package/dist/brushstrokeRender-QGEYJ4OZ.js.map +1 -0
- package/dist/{builtins-Cc-bH-3U.d.cts → builtins-BakDiKWf.d.cts} +3 -2
- package/dist/{builtins-ZU1GJnUA.d.ts → builtins-CE33vyv2.d.ts} +3 -2
- package/dist/canvas/index.cjs +16 -9
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +60 -14
- package/dist/canvas/index.d.ts +60 -14
- package/dist/canvas/index.js +10 -3
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-PRSRYHQD.cjs → chunk-3QHPFSQM.cjs} +36 -36
- package/dist/{chunk-PRSRYHQD.cjs.map → chunk-3QHPFSQM.cjs.map} +1 -1
- package/dist/{chunk-QBWEH3IM.cjs → chunk-3T5O225T.cjs} +391 -76
- package/dist/chunk-3T5O225T.cjs.map +1 -0
- package/dist/{chunk-EQQMGO42.js → chunk-C2J7GOMJ.js} +18 -5
- package/dist/chunk-C2J7GOMJ.js.map +1 -0
- package/dist/{chunk-2XS6LTUP.cjs → chunk-C46AZEBE.cjs} +104 -339
- package/dist/chunk-C46AZEBE.cjs.map +1 -0
- package/dist/{chunk-HUO3TI4C.js → chunk-CPSMARTX.js} +6 -241
- package/dist/chunk-CPSMARTX.js.map +1 -0
- package/dist/{chunk-KEENUAFN.cjs → chunk-DLLUOVQX.cjs} +18 -5
- package/dist/chunk-DLLUOVQX.cjs.map +1 -0
- package/dist/{chunk-LSXXAJG3.js → chunk-J7DSKTKB.js} +5 -4
- package/dist/chunk-J7DSKTKB.js.map +1 -0
- package/dist/{chunk-6S6362D2.js → chunk-NI6RORDS.js} +2 -2
- package/dist/{chunk-XN2NBLV5.cjs → chunk-PMEHFHSP.cjs} +82 -82
- package/dist/{chunk-XN2NBLV5.cjs.map → chunk-PMEHFHSP.cjs.map} +1 -1
- package/dist/{chunk-5FSRTP6E.js → chunk-PQFVLOMR.js} +319 -4
- package/dist/chunk-PQFVLOMR.js.map +1 -0
- package/dist/{chunk-OIBIRXRG.js → chunk-PSPLRQL6.js} +2 -2
- package/dist/{chunk-SYT2TLQF.js → chunk-QEIN6JQO.js} +2 -2
- package/dist/{chunk-3D77LOBM.js → chunk-TJBYBSTN.js} +51 -6
- package/dist/chunk-TJBYBSTN.js.map +1 -0
- package/dist/{chunk-DFSZO2B5.cjs → chunk-UFL5N4DK.cjs} +5 -4
- package/dist/chunk-UFL5N4DK.cjs.map +1 -0
- package/dist/{chunk-TLCTTQFF.cjs → chunk-VEHVXRJU.cjs} +17 -17
- package/dist/{chunk-TLCTTQFF.cjs.map → chunk-VEHVXRJU.cjs.map} +1 -1
- package/dist/{chunk-5OOIUXNJ.cjs → chunk-XFXHA5MU.cjs} +55 -10
- package/dist/chunk-XFXHA5MU.cjs.map +1 -0
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.d.cts +3 -3
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/index.js +1 -1
- package/dist/effects/index.d.cts +5 -4
- package/dist/effects/index.d.ts +5 -4
- package/dist/{export-DwnZ_hvQ.d.ts → export-0ZaTK__4.d.ts} +4 -4
- package/dist/{export-41rL6Cne.d.ts → export-C45v6MYq.d.ts} +1 -1
- package/dist/{export-CyJdfP_Z.d.cts → export-D-7WCDJ9.d.cts} +4 -4
- package/dist/{export-D9mXp05Q.d.cts → export-DSdCfd6O.d.cts} +1 -1
- package/dist/grain-BWmGZxP4.d.cts +58 -0
- package/dist/grain-BWmGZxP4.d.ts +58 -0
- package/dist/{helpers-v6GMazzg.d.cts → helpers-Cavy1TB7.d.cts} +21 -1
- package/dist/{helpers-C-RgeyvH.d.ts → helpers-LZQ4cpg4.d.ts} +21 -1
- package/dist/image-editor/index.cjs +695 -677
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +12 -11
- package/dist/image-editor/index.d.ts +12 -11
- package/dist/image-editor/index.js +23 -5
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{opentype-KR_jj6b_.d.cts → opentype-BpIJhGpj.d.cts} +1 -1
- package/dist/{opentype-a1KAW-qs.d.ts → opentype-CyxDScVz.d.ts} +1 -1
- package/dist/paint/index.cjs +21 -3
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +72 -5
- package/dist/paint/index.d.ts +72 -5
- package/dist/paint/index.js +20 -2
- package/dist/paint-editor/index.cjs +171 -171
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +77 -29
- package/dist/paint-editor/index.d.ts +77 -29
- package/dist/paint-editor/index.js +12 -12
- package/dist/{pathfinder-BHS4vQNm.d.cts → pathfinder-BMQEcS0k.d.cts} +2 -2
- package/dist/{pathfinder-BVvTIBMo.d.ts → pathfinder-CQIxubuP.d.ts} +2 -2
- package/dist/{pool-CZQOrSXZ.d.ts → pool-Cynuj89K.d.ts} +1 -1
- package/dist/{pool-FjZZmZ80.d.cts → pool-DedjxDKo.d.cts} +1 -1
- package/dist/{rand-8xbUb6ur.d.ts → rand-COS4_E1g.d.ts} +17 -1
- package/dist/{rand-Cw9VLrVC.d.cts → rand-D1JqpR-p.d.cts} +17 -1
- package/dist/{svg-DTb40ICU.d.cts → svg-RcixtBFR.d.cts} +2 -2
- package/dist/{svg-CSz3mzkw.d.ts → svg-nWBJEpnk.d.ts} +2 -2
- package/dist/{tools-Ca0kI1qo.d.cts → tools-CL82d7nw.d.cts} +1 -1
- package/dist/{tools-B0wXP5cF.d.ts → tools-DrxgDnXY.d.ts} +1 -1
- package/dist/vector/index.cjs +995 -955
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +44 -18
- package/dist/vector/index.d.ts +44 -18
- package/dist/vector/index.js +55 -15
- package/dist/vector/index.js.map +1 -1
- package/dist/video-editor/index.d.cts +5 -4
- package/dist/video-editor/index.d.ts +5 -4
- package/dist/{warp-DTOp0lON.d.cts → warp-CHi_P_G6.d.cts} +1 -1
- package/dist/{warp-pd7hrH4T.d.ts → warp-CPaHULUL.d.ts} +1 -1
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +12 -5
- package/skills/pixerate-vector/SKILL.md +4 -2
- package/dist/brushstrokeRender-2FAXA3XC.js.map +0 -1
- package/dist/brushstrokeRender-IMFY3FF6.cjs.map +0 -1
- package/dist/chunk-2XS6LTUP.cjs.map +0 -1
- package/dist/chunk-3D77LOBM.js.map +0 -1
- package/dist/chunk-5FSRTP6E.js.map +0 -1
- package/dist/chunk-5OOIUXNJ.cjs.map +0 -1
- package/dist/chunk-DFSZO2B5.cjs.map +0 -1
- package/dist/chunk-EQQMGO42.js.map +0 -1
- package/dist/chunk-HUO3TI4C.js.map +0 -1
- package/dist/chunk-KEENUAFN.cjs.map +0 -1
- package/dist/chunk-LSXXAJG3.js.map +0 -1
- package/dist/chunk-QBWEH3IM.cjs.map +0 -1
- /package/dist/{chunk-6S6362D2.js.map → chunk-NI6RORDS.js.map} +0 -0
- /package/dist/{chunk-OIBIRXRG.js.map → chunk-PSPLRQL6.js.map} +0 -0
- /package/dist/{chunk-SYT2TLQF.js.map → chunk-QEIN6JQO.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/paint-editor/noise.ts","../src/paint-editor/paper.ts","../src/paint-editor/engine.ts","../src/paint-editor/stickers.ts","../src/paint-editor/procedural.ts","../src/paint-editor/brushes.ts"],"sourcesContent":["// Portions ported from photocraft/crates/paint/src/procedural.rs and rng.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Seeded, deterministic noise for paper grain and brush jitter (photocraft's counter-based\n * randomness and tileable value noise, on 32-bit integer hashes instead of 64-bit ones so it runs\n * fast in JavaScript). Every value is a pure function of its inputs, so a paper or a stroke\n * regenerates identically on every machine.\n */\n\nexport { mix32, hash2, rand01 } from '../paint/rand';\nimport { hash2, mix32, rand01 } from '../paint/rand';\n\n/** Uniform in [-1, 1). */\nexport function randSigned(seed: number, index: number, stream: number): number {\n return rand01(seed, index, stream) * 2 - 1;\n}\n\n/** A seed from a string (FNV-1a, then mixed). */\nexport function seedFromString(text: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n h ^= text.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return mix32(h >>> 0);\n}\n\nconst smooth = (t: number) => t * t * (3 - 2 * t);\n\n/** A periodic lattice of `px × py` random values, sampled with smooth interpolation. */\nclass Lattice {\n readonly values: Float32Array;\n constructor(readonly px: number, readonly py: number, salt: number) {\n this.values = new Float32Array(px * py);\n for (let j = 0; j < py; j++) for (let i = 0; i < px; i++) this.values[j * px + i] = hash2(i, j, salt);\n }\n\n /** Value noise at (x, y) in lattice cells; wraps every `px` / `py` cells. */\n at(x: number, y: number): number {\n const { px, py } = this;\n const x0 = Math.floor(x);\n const y0 = Math.floor(y);\n const tx = smooth(x - x0);\n const ty = smooth(y - y0);\n const i0 = ((x0 % px) + px) % px;\n const j0 = ((y0 % py) + py) % py;\n const i1 = (i0 + 1) % px;\n const j1 = (j0 + 1) % py;\n const v = this.values;\n const a = v[j0 * px + i0] + (v[j0 * px + i1] - v[j0 * px + i0]) * tx;\n const b = v[j1 * px + i0] + (v[j1 * px + i1] - v[j1 * px + i0]) * tx;\n return a + (b - a) * ty;\n }\n}\n\n/**\n * Tileable fractal value noise in 0..1 over a `size`-pixel square: `cellsX × cellsY` lattice cells\n * at the base octave (unequal counts give fibres and streaks), doubling per octave, so the result\n * repeats exactly every `size` pixels.\n */\nexport class TileableNoise {\n private readonly octaves: Lattice[] = [];\n\n constructor(readonly size: number, cellsX: number, cellsY: number, octaves: number, salt: number) {\n let cx = Math.max(1, Math.round(cellsX));\n let cy = Math.max(1, Math.round(cellsY));\n for (let o = 0; o < octaves; o++) {\n this.octaves.push(new Lattice(cx, cy, (salt + o * 7919) | 0));\n cx *= 2;\n cy *= 2;\n }\n }\n\n /** Fractal noise at pixel (x, y). */\n at(x: number, y: number): number {\n let sum = 0;\n let amp = 1;\n let norm = 0;\n const u = x / this.size;\n const v = y / this.size;\n for (const l of this.octaves) {\n sum += l.at(u * l.px, v * l.py) * amp;\n norm += amp;\n amp *= 0.5;\n }\n return norm > 0 ? sum / norm : 0.5;\n }\n}\n","/**\n * Paper: a generated grain height map (0 = valley, 1 = peak) that tiles across the canvas, a paper\n * colour, grain depth, and the three properties wet media will read later (absorption,\n * permeability, roughness). Dry media catch the peaks: a light stroke only marks the high grain, a\n * firm one fills the valleys too. Everything is generated from a pattern and a seed, so a paper is\n * a few numbers in the document, never a bitmap, and no third-party texture is bundled.\n */\n\nimport { hash2, TileableNoise } from './noise';\n\n/** Grain generators. Each is our own procedural pattern (no scanned textures). */\nexport type GrainPattern =\n | 'smooth'\n | 'cold-pressed'\n | 'hot-pressed'\n | 'rough'\n | 'vellum'\n | 'laid'\n | 'ingres'\n | 'sanded'\n | 'canvas'\n | 'linen'\n | 'gesso';\n\nexport const GRAIN_PATTERNS: readonly GrainPattern[] = ['smooth', 'cold-pressed', 'hot-pressed', 'rough', 'vellum', 'laid', 'ingres', 'sanded', 'canvas', 'linen', 'gesso'];\n\n/** Paper families, as a library groups them. */\nexport type PaperFamily = 'watercolor' | 'drawing' | 'pastel' | 'canvas' | 'panel' | 'smooth';\n\nexport const PAPER_FAMILIES: readonly PaperFamily[] = ['watercolor', 'drawing', 'pastel', 'canvas', 'panel', 'smooth'];\n\n/** How a height map is tuned for one kind of media. */\nexport interface GrainTuning {\n /** Height contrast around the middle, 0..3 (default 1). */\n contrast: number;\n /** Swap peaks and valleys (default false). */\n invert: boolean;\n}\n\nexport type PaperTiling = 'repeat' | 'mirror';\n\nexport interface PaperSettings {\n /** The library preset this paper started from (`custom` when it matches none). */\n preset: string;\n name: string;\n family: PaperFamily;\n pattern: GrainPattern;\n /** Grain seed: another seed gives another sheet of the same paper. */\n seed: number;\n /** Paper colour #rrggbb. */\n color: string;\n /** Grain scale: 1 is the pattern's natural size, 2 twice as coarse (0.25..8). */\n scale: number;\n /** How the grain tile repeats: `repeat` or `mirror` (alternate tiles flipped, so seams vanish). */\n tiling: PaperTiling;\n /** Grain depth 0..1: how much grain-responsive dry media skip the valleys (0: none). */\n depth: number;\n /** How much the grain shades the paper colour on screen and in exports, 0..1. */\n shading: number;\n /** The height map as dry media read it. */\n dry: GrainTuning;\n /** The height map as wet media will read it (stored now; wet media is a later phase). */\n wet: GrainTuning;\n /** Wet media: how fast the paper takes up water, 0..1. */\n absorption: number;\n /** Wet media: how far water spreads inside the paper, 0..1. */\n permeability: number;\n /** Wet media: how much the grain catches pigment, 0..1. */\n roughness: number;\n /** Metallic paper (gold or silver leaf, pearlescent card): the grain catches the light, 0..1 (default 0). */\n metallic?: number;\n}\n\n/** Side of the generated grain tile in pixels (at scale 1). */\nexport const GRAIN_TILE = 256;\n\nconst unit = (v: unknown, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d);\nconst clampNum = (v: unknown, lo: number, hi: number, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d);\nconst HEX = /^#[0-9a-f]{6}$/i;\n\ntype PaperPreset = PaperSettings;\n\nconst tuning = (contrast = 1, invert = false): GrainTuning => ({ contrast, invert });\n\nfunction preset(\n id: string,\n name: string,\n family: PaperFamily,\n pattern: GrainPattern,\n color: string,\n o: { depth: number; absorption: number; permeability: number; roughness: number; scale?: number; seed?: number; shading?: number; contrast?: number }\n): PaperPreset {\n return {\n preset: id,\n name,\n family,\n pattern,\n seed: o.seed ?? 1,\n color,\n scale: o.scale ?? 1,\n tiling: 'mirror',\n depth: o.depth,\n shading: o.shading ?? 0.5,\n dry: tuning(o.contrast ?? 1),\n wet: tuning(1),\n absorption: o.absorption,\n permeability: o.permeability,\n roughness: o.roughness,\n };\n}\n\n/** The built-in paper library: generated papers in families. */\nexport const PAPER_LIBRARY: readonly PaperPreset[] = [\n preset('cold-pressed', 'Cold pressed watercolour', 'watercolor', 'cold-pressed', '#f7f3ea', { depth: 0.5, absorption: 0.7, permeability: 0.5, roughness: 0.6 }),\n preset('hot-pressed', 'Hot pressed watercolour', 'watercolor', 'hot-pressed', '#f8f6ef', { depth: 0.25, absorption: 0.55, permeability: 0.4, roughness: 0.25 }),\n preset('rough-watercolor', 'Rough watercolour', 'watercolor', 'rough', '#f5f0e4', { depth: 0.75, absorption: 0.8, permeability: 0.6, roughness: 0.85 }),\n preset('cartridge', 'Cartridge', 'drawing', 'vellum', '#fbfaf6', { depth: 0.3, absorption: 0.4, permeability: 0.3, roughness: 0.35 }),\n preset('laid', 'Laid paper', 'drawing', 'laid', '#f3ecdc', { depth: 0.45, absorption: 0.45, permeability: 0.35, roughness: 0.45 }),\n preset('ingres', 'Charcoal paper', 'drawing', 'ingres', '#ede6d6', { depth: 0.6, absorption: 0.4, permeability: 0.3, roughness: 0.65 }),\n preset('sanded-pastel', 'Sanded pastel paper', 'pastel', 'sanded', '#d8cfc0', { depth: 0.7, absorption: 0.3, permeability: 0.2, roughness: 0.9, shading: 0.35 }),\n preset('pastel-card', 'Grey pastel card', 'pastel', 'sanded', '#9c978e', { depth: 0.55, absorption: 0.3, permeability: 0.2, roughness: 0.75, scale: 1.5, shading: 0.3 }),\n preset('cotton-canvas', 'Cotton canvas', 'canvas', 'canvas', '#efe9dc', { depth: 0.55, absorption: 0.35, permeability: 0.25, roughness: 0.6 }),\n preset('fine-linen', 'Fine linen', 'canvas', 'linen', '#e9e2d2', { depth: 0.45, absorption: 0.3, permeability: 0.25, roughness: 0.5 }),\n preset('gesso', 'Gesso panel', 'panel', 'gesso', '#f6f4ef', { depth: 0.35, absorption: 0.2, permeability: 0.15, roughness: 0.4 }),\n preset('smooth', 'Smooth bristol', 'smooth', 'smooth', '#ffffff', { depth: 0, absorption: 0.3, permeability: 0.2, roughness: 0.05, shading: 0 }),\n];\n\nexport const DEFAULT_PAPER: Readonly<PaperSettings> = PAPER_LIBRARY[0];\n\n/** A paper from the library by id, or `undefined`. */\nexport function paperPreset(id: string): PaperSettings | undefined {\n const p = PAPER_LIBRARY.find((x) => x.preset === id);\n return p ? clonePaper(p) : undefined;\n}\n\nexport function clonePaper(p: PaperSettings): PaperSettings {\n return { ...p, dry: { ...p.dry }, wet: { ...p.wet } };\n}\n\nfunction readTuning(raw: unknown, d: GrainTuning): GrainTuning {\n const r = raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : {};\n return { contrast: clampNum(r.contrast, 0, 3, d.contrast), invert: typeof r.invert === 'boolean' ? r.invert : d.invert };\n}\n\n/**\n * A paper with every field in range. Missing fields come from `base` (default: the library preset\n * named by `raw.preset`, else cold pressed).\n */\nexport function normalizePaper(raw: Partial<PaperSettings> | Record<string, unknown> = {}, base?: PaperSettings): PaperSettings {\n const r = raw as Record<string, unknown>;\n const b = base ?? (typeof r.preset === 'string' ? paperPreset(r.preset) : undefined) ?? clonePaper(DEFAULT_PAPER);\n return {\n preset: typeof r.preset === 'string' && r.preset ? r.preset : b.preset,\n name: typeof r.name === 'string' && r.name.trim() ? r.name.trim() : b.name,\n family: PAPER_FAMILIES.includes(r.family as PaperFamily) ? (r.family as PaperFamily) : b.family,\n pattern: GRAIN_PATTERNS.includes(r.pattern as GrainPattern) ? (r.pattern as GrainPattern) : b.pattern,\n seed: typeof r.seed === 'number' && Number.isFinite(r.seed) ? Math.round(Math.abs(r.seed)) % 2147483647 : b.seed,\n color: typeof r.color === 'string' && HEX.test(r.color) ? r.color.toLowerCase() : b.color,\n scale: clampNum(r.scale, 0.25, 8, b.scale),\n tiling: r.tiling === 'repeat' || r.tiling === 'mirror' ? r.tiling : b.tiling,\n depth: unit(r.depth, b.depth),\n shading: unit(r.shading, b.shading),\n dry: readTuning(r.dry, b.dry),\n wet: readTuning(r.wet, b.wet),\n absorption: unit(r.absorption, b.absorption),\n permeability: unit(r.permeability, b.permeability),\n roughness: unit(r.roughness, b.roughness),\n ...(unit(r.metallic, b.metallic ?? 0) > 0 ? { metallic: unit(r.metallic, b.metallic ?? 0) } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Height maps\n// ---------------------------------------------------------------------------\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/** One pattern's raw height (0..1) at pixel (x, y) of a `n`-pixel tile. */\nfunction patternHeights(pattern: GrainPattern, n: number, seed: number): Float32Array {\n const out = new Float32Array(n * n);\n const salt = Math.imul(seed | 0, 0x9e3779b1) + 17;\n if (pattern === 'smooth') return out.fill(1);\n const noise = (cx: number, cy: number, oct: number, s = 0) => new TileableNoise(n, cx, cy, oct, salt + s);\n const k = n / GRAIN_TILE;\n switch (pattern) {\n case 'cold-pressed': {\n const base = noise(20 * k, 20 * k, 4);\n const fine = noise(64 * k, 64 * k, 2, 3);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.8 + 0.5 + (fine.at(x, y) - 0.5) * 0.5 + (hash2(x, y, salt) - 0.5) * 0.12);\n break;\n }\n case 'hot-pressed': {\n const base = noise(40 * k, 40 * k, 3);\n for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.1 + 0.6 + (hash2(x, y, salt) - 0.5) * 0.08);\n break;\n }\n case 'rough': {\n const base = noise(10 * k, 10 * k, 5);\n const blot = noise(28 * k, 28 * k, 2, 5);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 2.4 + 0.5 + (blot.at(x, y) - 0.5) * 0.7 + (hash2(x, y, salt) - 0.5) * 0.15);\n break;\n }\n case 'vellum': {\n const base = noise(40 * k, 40 * k, 3);\n for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.6 + 0.55 + (hash2(x, y, salt) - 0.5) * 0.2);\n break;\n }\n case 'laid': {\n // Fine laid lines across, chain lines down every eighth of the tile, a little pulp noise.\n const pulp = noise(32 * k, 32 * k, 3);\n const chain = n / 8;\n for (let y = 0; y < n; y++) {\n const laid = 0.5 + 0.5 * Math.cos((2 * Math.PI * y) / 4);\n for (let x = 0; x < n; x++) {\n const c = Math.abs(((x + 0.5) % chain) - chain / 2) / (chain / 2);\n const chainLine = c > 0.94 ? -0.35 : 0;\n out[y * n + x] = clamp01(0.3 + 0.5 * laid + chainLine + (pulp.at(x, y) - 0.5) * 0.6);\n }\n }\n break;\n }\n case 'ingres': {\n // Long vertical fibres with grit.\n const fibres = noise(64 * k, 12 * k, 3);\n const base = noise(16 * k, 16 * k, 3, 7);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) {\n const g = hash2(x, y, salt ^ 0x55);\n out[y * n + x] = clamp01((fibres.at(x, y) - 0.5) * 1.5 + (base.at(x, y) - 0.5) * 0.7 + 0.55 + (g < 0.1 ? -0.3 : 0));\n }\n break;\n }\n case 'sanded': {\n // Fine grit: high-frequency noise and sharp single-pixel pits.\n const grit = noise(96 * k, 96 * k, 2);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) {\n const h = hash2(x, y, salt);\n out[y * n + x] = clamp01((grit.at(x, y) - 0.5) * 2.4 + 0.5 + (h - 0.5) * 0.7);\n }\n break;\n }\n case 'canvas':\n case 'linen': {\n // Over / under weave; linen has finer, irregular threads.\n const period = (pattern === 'canvas' ? 8 : 5) * k;\n // An even thread count keeps the over / under alternation seamless across the tile edge.\n const threads = Math.max(2, 2 * Math.round(n / period / 2));\n const p = n / threads;\n const slub = noise(threads, threads, 2, 11);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) {\n const fx = (x + 0.5) / p;\n const fy = (y + 0.5) / p;\n const cx = Math.floor(fx);\n const cy = Math.floor(fy);\n const warp = Math.sin(Math.PI * (fx - cx));\n const weft = Math.sin(Math.PI * (fy - cy));\n const top = (cx + cy) % 2 === 0 ? warp : weft;\n const irregular = pattern === 'linen' ? (slub.at(x, y) - 0.5) * 0.5 : 0;\n out[y * n + x] = clamp01(0.2 + 0.7 * top + irregular + (hash2(x, y, salt) - 0.5) * 0.15);\n }\n break;\n }\n case 'gesso': {\n // Brushed gesso: soft horizontal streaks over a fine tooth.\n const streaks = noise(2 * k, 28 * k, 3);\n const tooth = noise(64 * k, 64 * k, 2, 13);\n for (let y = 0; y < n; y++)\n for (let x = 0; x < n; x++) out[y * n + x] = clamp01((streaks.at(x, y) - 0.5) * 1.8 + (tooth.at(x, y) - 0.5) * 0.9 + 0.55);\n break;\n }\n }\n return out;\n}\n\nconst rawCache = new Map<string, Float32Array>();\n\n/** The raw height map of a pattern (`GRAIN_TILE` square, 0..1), generated once per pattern and seed. */\nexport function grainHeights(pattern: GrainPattern, seed: number, size = GRAIN_TILE): Float32Array {\n const key = `${pattern}:${seed}:${size}`;\n let h = rawCache.get(key);\n if (!h) {\n h = patternHeights(pattern, size, seed);\n if (rawCache.size > 32) rawCache.delete(rawCache.keys().next().value as string);\n rawCache.set(key, h);\n }\n return h;\n}\n\n/**\n * A paper's height field over the canvas (document pixels), tuned for one kind of media. Read it\n * with `at(x, y)`: bilinear, tiled by `paper.tiling`, at `paper.scale`.\n */\nexport class PaperGrain {\n readonly size = GRAIN_TILE;\n private readonly heights: Float32Array;\n private readonly scale: number;\n private readonly mirror: boolean;\n readonly flat: boolean;\n\n constructor(paper: PaperSettings, media: 'dry' | 'wet' = 'dry') {\n const raw = grainHeights(paper.pattern, paper.seed);\n const t = paper[media];\n this.flat = paper.pattern === 'smooth';\n if (t.contrast === 1 && !t.invert) this.heights = raw;\n else {\n const out = new Float32Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n const v = clamp01((raw[i] - 0.5) * t.contrast + 0.5);\n out[i] = t.invert ? 1 - v : v;\n }\n this.heights = out;\n }\n this.scale = paper.scale;\n this.mirror = paper.tiling === 'mirror';\n }\n\n /** Tile cell index for a coordinate in grain pixels (mirrored on odd tiles when mirroring). */\n private wrap(v: number): number {\n const n = this.size;\n if (!this.mirror) return ((v % n) + n) % n;\n const p = ((v % (2 * n)) + 2 * n) % (2 * n);\n return p < n ? p : 2 * n - 1 - p;\n }\n\n /** Height 0..1 at document position (x, y). */\n at(x: number, y: number): number {\n const u = x / this.scale - 0.5;\n const v = y / this.scale - 0.5;\n const x0 = Math.floor(u);\n const y0 = Math.floor(v);\n const fx = u - x0;\n const fy = v - y0;\n const n = this.size;\n const h = this.heights;\n const a = this.wrap(x0);\n const b = this.wrap(x0 + 1);\n const c = this.wrap(y0) * n;\n const d = this.wrap(y0 + 1) * n;\n const top = h[c + a] + (h[c + b] - h[c + a]) * fx;\n const bot = h[d + a] + (h[d + b] - h[d + a]) * fx;\n return top + (bot - top) * fy;\n }\n}\n\n/**\n * How much of a dry dab lands at grain height `h` (0..1): the media catches the peaks first, and\n * pressure pushes it into the valleys. `depth` is the paper's grain depth times the brush's grain\n * response; at 0 everything lands (1).\n */\nexport function grainCatch(h: number, depth: number, pressure: number): number {\n if (depth <= 0) return 1;\n const t = depth * (0.75 - 0.65 * Math.min(1, Math.max(0, pressure)));\n const u = clamp01((h - t + 0.18) / 0.36);\n return 1 - depth + depth * u * u * (3 - 2 * u);\n}\n\n/** `#rrggbb` → [r, g, b] 0..255. */\nexport function hexToRgb8(hex: string): [number, number, number] {\n const n = parseInt(hex.slice(1, 7), 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\n/**\n * The paper as opaque RGBA over `rect` (document pixels): its colour, darkened in the valleys by\n * `shading`.\n */\nexport function renderPaper(\n paper: PaperSettings,\n rect: { x: number; y: number; width: number; height: number },\n grain = new PaperGrain(paper),\n light?: { azimuth: number; elevation: number }\n): Uint8ClampedArray {\n const [r, g, b] = hexToRgb8(paper.color);\n const out = new Uint8ClampedArray(rect.width * rect.height * 4);\n const shade = grain.flat ? 0 : paper.shading * 0.16;\n const metal = light ? (paper.metallic ?? 0) : 0;\n // Metallic paper: a highlight where the grain's slope faces the half-way vector of the light.\n let hx = 0;\n let hy = 0;\n let hz = 1;\n if (metal > 0 && light) {\n const az = (light.azimuth * Math.PI) / 180;\n const el = (light.elevation * Math.PI) / 180;\n const lx = Math.cos(el) * Math.sin(az);\n const ly = -Math.cos(el) * Math.cos(az);\n const lz = Math.sin(el) + 1;\n const n = Math.hypot(lx, ly, lz);\n hx = lx / n;\n hy = ly / n;\n hz = lz / n;\n }\n for (let y = 0; y < rect.height; y++) {\n for (let x = 0; x < rect.width; x++) {\n const i = (y * rect.width + x) * 4;\n const px = rect.x + x + 0.5;\n const py = rect.y + y + 0.5;\n const k = shade ? 1 - shade * (1 - grain.at(px, py)) : 1;\n let spec = 0;\n if (metal > 0) {\n const gx = (grain.at(px + 1, py) - grain.at(px - 1, py)) * 4;\n const gy = (grain.at(px, py + 1) - grain.at(px, py - 1)) * 4;\n const nl = Math.hypot(gx, gy, 1);\n const nh = Math.max(0, (-gx * hx - gy * hy + hz) / nl);\n spec = metal * Math.pow(nh, 24) * 0.9;\n }\n out[i] = Math.min(255, r * k * (1 - 0.25 * metal) + spec * (r * 0.6 + 102));\n out[i + 1] = Math.min(255, g * k * (1 - 0.25 * metal) + spec * (g * 0.6 + 102));\n out[i + 2] = Math.min(255, b * k * (1 - 0.25 * metal) + spec * (b * 0.6 + 102));\n out[i + 3] = 255;\n }\n }\n return out;\n}\n","/**\n * The paint editor's dry-media stroke engine, on the shared brush engine (`@pixerate/editor/paint`):\n *\n * - Pen input: pressure, tilt (`tiltX` / `tiltY` or `altitude` / `azimuth`), barrel rotation\n * (`twist`) and time (for velocity). Position and pressure are smoothed separately.\n * - `PenDabWalker` walks the points into the shared `Dab`s at `spacing × diameter`, with every\n * pen channel interpolated, and applies the brush's dynamics, rotation mode and jitter.\n * Jitter is a pure hash of the stroke seed and the dab index, so a stroke replays exactly.\n * - `DryStroke` rasterizes each dab with the shared round tip, multiplies it by how much of it the\n * paper grain catches (`grainCatch`), and builds it up in the shared `CoverageMap`; the session\n * then composites the coverage with the shared `applyStrokeToTile`.\n * - Symmetry: one stroke can paint several copies of its points (mirror and kaleidoscope), each\n * with its own walker, into the same coverage, so the copies are one stroke and one undo step.\n *\n * Pure data in, pixels out: no DOM, no framework.\n */\n\nimport { CoverageMap, dabRect, rasterizeDab, type BrushSettings, type Dab, type StrokePoint } from '../paint/brush';\nimport type { RasterRect } from '../raster/surface';\nimport type { PaintBrush } from './brushes';\nimport { randSigned } from './noise';\nimport { grainCatch, type PaperGrain } from './paper';\n\n/** One pen sample in document pixels. Every channel but x and y is optional. */\nexport interface PenPoint {\n x: number;\n y: number;\n /** 0..1 (missing: 1, a mouse). */\n pressure?: number;\n /** Milliseconds since any fixed origin (for velocity; missing: no velocity dynamics). */\n t?: number;\n /** Pointer Events tilt in degrees, -90..90 (used when `altitude` / `azimuth` are missing). */\n tiltX?: number;\n tiltY?: number;\n /** Radians from the surface: π/2 is upright, 0 lies flat. */\n altitude?: number;\n /** Radians clockwise from the +x axis (screen y points down): where the pen leans. */\n azimuth?: number;\n /** Barrel rotation in degrees clockwise, 0..359. */\n twist?: number;\n}\n\n/** A pen's lean as altitude and azimuth, or `null` when the sample has no tilt. */\nexport function penOrientation(p: PenPoint): { altitude: number; azimuth: number } | null {\n if (typeof p.altitude === 'number' && Number.isFinite(p.altitude)) {\n const altitude = Math.min(Math.PI / 2, Math.max(0, p.altitude));\n const azimuth = typeof p.azimuth === 'number' && Number.isFinite(p.azimuth) ? p.azimuth : 0;\n return { altitude, azimuth };\n }\n const hasX = typeof p.tiltX === 'number' && Number.isFinite(p.tiltX);\n const hasY = typeof p.tiltY === 'number' && Number.isFinite(p.tiltY);\n if (!hasX && !hasY) return null;\n return tiltToOrientation(hasX ? p.tiltX! : 0, hasY ? p.tiltY! : 0);\n}\n\n/** Pointer Events `tiltX` / `tiltY` (degrees) → altitude and azimuth (radians). */\nexport function tiltToOrientation(tiltX: number, tiltY: number): { altitude: number; azimuth: number } {\n const clampT = (v: number) => Math.min(89.999, Math.max(-89.999, v));\n const tx = Math.tan((clampT(tiltX) * Math.PI) / 180);\n const ty = Math.tan((clampT(tiltY) * Math.PI) / 180);\n const r = Math.hypot(tx, ty);\n if (r < 1e-9) return { altitude: Math.PI / 2, azimuth: 0 };\n let azimuth = Math.atan2(ty, tx);\n if (azimuth < 0) azimuth += 2 * Math.PI;\n return { altitude: Math.atan(1 / r), azimuth };\n}\n\nconst pressureOf = (p: PenPoint) => (typeof p.pressure === 'number' && Number.isFinite(p.pressure) ? Math.min(1, Math.max(0, p.pressure)) : 1);\n\n/**\n * Exponential smoothing of position and of pressure, each by its own amount (0..0.95). Feed raw\n * samples; the first sample passes through.\n */\nexport class PenSmoother {\n private pos: { x: number; y: number } | null = null;\n private pressure: number | null = null;\n private readonly a: number;\n private readonly ap: number;\n\n constructor(position: number, pressure: number) {\n this.a = 1 - Math.min(0.95, Math.max(0, position));\n this.ap = 1 - Math.min(0.95, Math.max(0, pressure));\n }\n\n push(p: PenPoint): PenPoint {\n const pr = pressureOf(p);\n if (!this.pos) {\n this.pos = { x: p.x, y: p.y };\n this.pressure = pr;\n return p;\n }\n this.pos = { x: this.pos.x + (p.x - this.pos.x) * this.a, y: this.pos.y + (p.y - this.pos.y) * this.a };\n this.pressure = this.pressure! + (pr - this.pressure!) * this.ap;\n return { ...p, x: this.pos.x, y: this.pos.y, pressure: this.pressure };\n }\n\n /** Where the smoothed position is now (or `null` before the first sample). */\n get position(): { x: number; y: number } | null {\n return this.pos;\n }\n}\n\n/** A linear map of document vectors `[a, b, c, d]`: (x, y) → (a·x + b·y, c·x + d·y). */\nexport type Linear2 = readonly [number, number, number, number];\n\n/** How one copy of a stroke maps the input: a point map and its linear part (for dab angles). */\nexport interface StrokeCopy {\n map(p: PenPoint): PenPoint;\n linear: Linear2;\n}\n\nexport const IDENTITY_COPY: StrokeCopy = { map: (p) => p, linear: [1, 0, 0, 1] };\n\n/** A dab with the pen state it was made at (the shared `Dab` plus pressure for the grain). */\nexport interface PenDab extends Dab {\n pressure: number;\n /** Direction of travel at the dab, radians counter-clockwise with y up (as `angle`). */\n direction: number;\n /** The dab's index within its copy of the stroke (0, 1, 2 …). */\n index: number;\n /** Path length (px, along the smoothed samples of this copy) travelled to the dab: what gradient paint maps by distance. */\n travel: number;\n /** ms since the stroke's first timed sample, or `null` when the samples carry no time. */\n time: number | null;\n /** Pen lean, 0 upright .. 1 flat. */\n lean: number;\n /** Pen speed (px/ms), or `null` when the samples carry no time. */\n speed: number | null;\n}\n\nconst enum Stream {\n Size = 1,\n Angle = 2,\n Opacity = 3,\n Scatter = 4,\n}\n\ninterface Sample {\n x: number;\n y: number;\n pressure: number;\n lean: number;\n azimuth: number;\n twist: number | null;\n speed: number | null;\n /** Path length to this sample. */\n travel: number;\n /** ms since the first timed sample. */\n time: number | null;\n}\n\n/** Speed (px/ms) at which velocity dynamics reach their full effect. */\nconst FULL_SPEED = 2.5;\n\n/**\n * Walks pen samples into dabs, incrementally (any chunking gives the same dabs). Dab angles are in\n * the shared rasterizer's convention: radians, counter-clockwise with y up.\n */\nexport class PenDabWalker {\n private last: Sample | null = null;\n private nextAt = 0;\n private pendingFirst: Sample | null = null;\n private index = 0;\n private dir = 0;\n private lastT: number | null = null;\n private firstT: number | null = null;\n private speed: number | null = null;\n private travelled = 0;\n\n constructor(\n readonly brush: PaintBrush,\n private readonly seed = 0,\n private readonly linear: Linear2 = [1, 0, 0, 1]\n ) {}\n\n private sample(p: PenPoint): Sample {\n const o = penOrientation(p);\n let speed: number | null = null;\n let time: number | null = null;\n if (this.last) this.travelled += Math.hypot(p.x - this.last.x, p.y - this.last.y);\n if (typeof p.t === 'number' && Number.isFinite(p.t)) {\n if (this.firstT === null) this.firstT = p.t;\n time = p.t - this.firstT;\n if (this.last && this.lastT !== null && p.t > this.lastT) {\n const v = Math.hypot(p.x - this.last.x, p.y - this.last.y) / (p.t - this.lastT);\n this.speed = this.speed === null ? v : this.speed + (v - this.speed) * 0.35;\n }\n this.lastT = p.t;\n speed = this.speed ?? 0;\n }\n return {\n x: p.x,\n y: p.y,\n pressure: pressureOf(p),\n lean: o ? 1 - o.altitude / (Math.PI / 2) : 0,\n azimuth: o ? o.azimuth : 0,\n twist: typeof p.twist === 'number' && Number.isFinite(p.twist) ? p.twist : null,\n speed,\n travel: this.travelled,\n time,\n };\n }\n\n private diameter(s: Sample): number {\n const tip = this.brush.tip;\n const dyn = this.brush.dynamics;\n let d = tip.size;\n if (tip.pressureSize) d *= dyn.minSize + (1 - dyn.minSize) * s.pressure;\n d *= 1 + dyn.tiltSize * s.lean * 1.5;\n if (s.speed !== null && dyn.velocitySize) d *= Math.max(0.05, 1 + dyn.velocitySize * Math.min(1, s.speed / FULL_SPEED) * (dyn.velocitySize < 0 ? 0.85 : 1));\n return d;\n }\n\n private stepLen(s: Sample): number {\n return Math.max(0.5, Math.max(1, this.diameter(s)) * Math.max(0.01, this.brush.tip.spacing));\n }\n\n /** A rasterizer angle (CCW, y up) mapped through this copy's linear part. */\n private mapAngle(theta: number): number {\n const [a, b, c, d] = this.linear;\n if (a === 1 && b === 0 && c === 0 && d === 1) return theta;\n const vx = Math.cos(theta);\n const vy = -Math.sin(theta);\n return Math.atan2(-(c * vx + d * vy), a * vx + b * vy);\n }\n\n private dab(s: Sample): PenDab {\n const { tip, dynamics: dyn, rotation } = this.brush;\n const i = this.index++;\n const seed = this.seed;\n let diameter = this.diameter(s);\n if (dyn.sizeJitter) diameter *= Math.max(0.05, 1 + dyn.sizeJitter * randSigned(seed, i, Stream.Size));\n const base = (tip.angle * Math.PI) / 180;\n let angle: number;\n if (rotation === 'stroke') angle = this.dir + base;\n else if (rotation === 'barrel' && s.twist !== null) angle = this.mapAngle(base - (s.twist * Math.PI) / 180);\n else if (dyn.tiltRoundness > 0 && s.lean > 0.02) angle = this.mapAngle(base - s.azimuth);\n else angle = this.mapAngle(base);\n if (dyn.angleJitter) angle += dyn.angleJitter * Math.PI * randSigned(seed, i, Stream.Angle);\n let opacity = tip.pressureOpacity ? s.pressure : 1;\n opacity *= 1 - dyn.tiltOpacity * s.lean * 0.8;\n if (s.speed !== null && dyn.velocityOpacity) opacity *= Math.max(0, 1 + dyn.velocityOpacity * (Math.min(1, s.speed / FULL_SPEED) - 0.5));\n if (dyn.opacityJitter) opacity *= 1 - dyn.opacityJitter * (randSigned(seed, i, Stream.Opacity) * 0.5 + 0.5);\n const flow = tip.flow * (1 - dyn.pressureFlow + dyn.pressureFlow * s.pressure);\n let { x, y } = s;\n if (dyn.scatter) {\n const off = dyn.scatter * diameter * randSigned(seed, i, Stream.Scatter);\n // Across the stroke: the direction of travel turned a quarter (document y points down).\n x += Math.sin(this.dir) * off;\n y += Math.cos(this.dir) * off;\n }\n return {\n x,\n y,\n radius: Math.max(0.5, diameter / 2),\n alpha: Math.min(1, Math.max(0, flow)),\n opacity: Math.min(1, Math.max(0, opacity)),\n angle,\n roundness: Math.min(1, Math.max(0.01, tip.roundness * (1 - dyn.tiltRoundness * s.lean * 0.8))),\n pressure: s.pressure,\n direction: this.dir,\n index: i,\n travel: s.travel,\n time: s.time,\n lean: s.lean,\n speed: s.speed,\n };\n }\n\n push(p: PenPoint, out: PenDab[]): void {\n const a = this.last;\n const s = this.sample(p);\n if (!a) {\n this.last = s;\n this.pendingFirst = s;\n this.nextAt = this.stepLen(s);\n return;\n }\n const dx = s.x - a.x;\n const dy = s.y - a.y;\n const len = Math.hypot(dx, dy);\n if (len > 1e-9) this.dir = Math.atan2(-dy, dx);\n if (this.pendingFirst) {\n out.push(this.dab(this.pendingFirst));\n this.pendingFirst = null;\n }\n if (len > 1e-9) {\n while (this.nextAt <= len + 1e-9) {\n const f = Math.min(1, this.nextAt / len);\n const lerp = (u: number, v: number) => u + (v - u) * f;\n const q: Sample = {\n x: a.x + dx * f,\n y: a.y + dy * f,\n pressure: lerp(a.pressure, s.pressure),\n lean: lerp(a.lean, s.lean),\n azimuth: lerpAngle(a.azimuth, s.azimuth, f),\n twist: a.twist !== null && s.twist !== null ? lerpDegrees(a.twist, s.twist, f) : s.twist,\n speed: a.speed !== null && s.speed !== null ? lerp(a.speed, s.speed) : s.speed,\n travel: a.travel + this.nextAt,\n time: a.time !== null && s.time !== null ? lerp(a.time, s.time) : s.time,\n };\n out.push(this.dab(q));\n this.nextAt += this.stepLen(q);\n }\n this.nextAt -= len;\n }\n this.last = s;\n }\n\n finish(out: PenDab[]): void {\n if (this.pendingFirst) {\n out.push(this.dab(this.pendingFirst));\n this.pendingFirst = null;\n }\n }\n}\n\nfunction lerpAngle(a: number, b: number, t: number): number {\n let d = b - a;\n while (d > Math.PI) d -= 2 * Math.PI;\n while (d < -Math.PI) d += 2 * Math.PI;\n return a + d * t;\n}\n\nfunction lerpDegrees(a: number, b: number, t: number): number {\n let d = b - a;\n while (d > 180) d -= 360;\n while (d < -180) d += 360;\n return a + d * t;\n}\n\nexport interface DryStrokeOptions {\n /** The paper's dry height field, or `null` for no grain. */\n grain: PaperGrain | null;\n /** The paper's grain depth, 0..1 (multiplied by the brush's grain response). */\n paperDepth: number;\n /** Jitter seed (record it to replay the stroke exactly). */\n seed?: number;\n /** Copies of the stroke (symmetry); default one identity copy. */\n copies?: readonly StrokeCopy[];\n}\n\n/**\n * One dab-engine stroke (dab and eraser brushes): smoothing, the dab walk of every copy, grain and\n * build-up in a shared coverage map.\n */\nexport class DryStroke {\n readonly coverage = new CoverageMap();\n dabCount = 0;\n private readonly smoother: PenSmoother;\n private readonly walkers: PenDabWalker[];\n private readonly copies: readonly StrokeCopy[];\n private readonly depth: number;\n private buf = new Float32Array(0);\n private lastRaw: PenPoint | null = null;\n private lastFed: PenPoint | null = null;\n\n constructor(readonly brush: PaintBrush, private readonly options: DryStrokeOptions) {\n this.smoother = new PenSmoother(brush.tip.smoothing, brush.pressureSmoothing);\n this.copies = options.copies?.length ? options.copies : [IDENTITY_COPY];\n this.walkers = this.copies.map((c, i) => new PenDabWalker(brush, ((options.seed ?? 0) + i * 7919) | 0, c.linear));\n this.depth = options.grain && !options.grain.flat ? Math.min(1, Math.max(0, options.paperDepth * brush.grain)) : 0;\n }\n\n /** Feeds raw pen samples; returns the document rectangles the new dabs touched. */\n push(points: readonly PenPoint[]): RasterRect[] {\n const dabs: PenDab[] = [];\n for (const raw of points) {\n this.lastRaw = raw;\n const p = this.smoother.push(raw);\n this.lastFed = p;\n this.copies.forEach((c, i) => this.walkers[i].push(c.map(p), dabs));\n }\n return this.paint(dabs);\n }\n\n /** Ends the stroke: the smoothed path catches up with the last raw sample; a single tap paints one dab. */\n finish(): RasterRect[] {\n const dabs: PenDab[] = [];\n const raw = this.lastRaw;\n const fed = this.lastFed;\n if (raw && fed && (raw.x !== fed.x || raw.y !== fed.y)) this.copies.forEach((c, i) => this.walkers[i].push(c.map({ ...raw, pressure: fed.pressure }), dabs));\n for (const w of this.walkers) w.finish(dabs);\n return this.paint(dabs);\n }\n\n private paint(dabs: PenDab[]): RasterRect[] {\n const rects: RasterRect[] = [];\n const hardness = this.brush.tip.hardness;\n const grain = this.options.grain;\n for (const d of dabs) {\n const rect = dabRect(d, hardness);\n const n = rect.width * rect.height;\n if (this.buf.length < n) this.buf = new Float32Array(n);\n const vals = this.buf.subarray(0, n);\n rasterizeDab(d, hardness, rect, vals);\n if (this.depth > 0 && grain) {\n for (let yy = 0, k = 0; yy < rect.height; yy++) {\n const y = rect.y + yy + 0.5;\n for (let xx = 0; xx < rect.width; xx++, k++) {\n if (vals[k] > 0) vals[k] *= grainCatch(grain.at(rect.x + xx + 0.5, y), this.depth, d.pressure);\n }\n }\n }\n this.coverage.accumulate(rect, vals, d.opacity);\n rects.push(rect);\n this.dabCount++;\n }\n return rects;\n }\n}\n\n/** The shared engine's tip for the Mixer Brush engine (it smooths and walks by itself, so smoothing is applied before). */\nexport function mixerTip(brush: PaintBrush): BrushSettings {\n return { ...brush.tip, smoothing: 0, pressureSize: brush.tip.pressureSize };\n}\n\n/** Pen samples → the shared engine's stroke points (pressure only). */\nexport function toStrokePoint(p: PenPoint): StrokePoint {\n return { x: p.x, y: p.y, pressure: pressureOf(p), ...(typeof p.t === 'number' ? { t: p.t } : {}) };\n}\n","/**\n * Stickers: textured stamps sprayed along a stroke onto a sticker layer, where each stays an object\n * that can be moved, turned, resized, recoloured or deleted afterwards. A sticker layer is a pixel\n * layer whose pixels are drawn from its stickers (`renderStickers`), so the compositor, exports and\n * every layer operation see ordinary pixels.\n *\n * The stamps are our own procedural shapes (dot, star, heart, leaf, petal flower, confetti, splat,\n * sparkle, ring), each with a little shading and a seeded paper-like texture, so no artwork is\n * bundled. The spray (`StickerSpray`) is deterministic: the same points, seed and brush give the\n * same stickers.\n */\n\nimport { TILE, TiledSurface, finishTile, tileKey, type RasterRect, type Tile, type TileKey } from '../raster/surface';\nimport { TileMedium, type PaintTileTarget } from '../paint/exchange';\nimport { PaintGradientSampler, type PaintGradientSource } from '../paint/gradient-paint';\nimport type { PaintBrush } from './brushes';\nimport { IDENTITY_COPY, PenDabWalker, PenSmoother, type PenDab, type PenPoint, type StrokeCopy } from './engine';\nimport { hash2, rand01 } from './noise';\n\nexport type StampKind = 'dot' | 'star' | 'heart' | 'leaf' | 'flower' | 'confetti' | 'splat' | 'sparkle' | 'ring';\nexport const STAMP_KINDS: readonly StampKind[] = ['dot', 'star', 'heart', 'leaf', 'flower', 'confetti', 'splat', 'sparkle', 'ring'];\n\n/** One sticker (document pixels). */\nexport interface Sticker {\n id: string;\n stamp: StampKind;\n x: number;\n y: number;\n /** Diameter in pixels. */\n size: number;\n /** Degrees clockwise. */\n rotation: number;\n /** #rrggbb */\n color: string;\n /** 0..1 */\n opacity: number;\n /** Texture seed. */\n seed: number;\n}\n\n/** Sticker spray settings (each 0..1 unless noted). */\nexport interface StickerSettings {\n /** The stamps to spray (picked at random per sticker). */\n stamps: StampKind[];\n /** Stickers per tip diameter of travel. */\n density: number;\n /** Random size change. */\n sizeJitter: number;\n /** Random turn, as a fraction of ±180°. */\n rotationJitter: number;\n /** How far from the path stickers land, in tip diameters (0..2). */\n scatter: number;\n /** Random colour change (hue and lightness). */\n colorJitter: number;\n}\n\nexport const DEFAULT_STICKER: Readonly<StickerSettings> = { stamps: ['star'], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };\n\nconst unit = (v: unknown, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d);\n\nexport function normalizeStickerSettings(raw: Partial<StickerSettings> = {}, base: StickerSettings = DEFAULT_STICKER): StickerSettings {\n const stamps = Array.isArray(raw.stamps) ? raw.stamps.filter((s): s is StampKind => STAMP_KINDS.includes(s as StampKind)) : base.stamps;\n return {\n stamps: stamps.length ? [...new Set(stamps)] : [...base.stamps],\n density: unit(raw.density, base.density),\n sizeJitter: unit(raw.sizeJitter, base.sizeJitter),\n rotationJitter: unit(raw.rotationJitter, base.rotationJitter),\n scatter: typeof raw.scatter === 'number' && Number.isFinite(raw.scatter) ? Math.min(2, Math.max(0, raw.scatter)) : base.scatter,\n colorJitter: unit(raw.colorJitter, base.colorJitter),\n };\n}\n\n/**\n * Coverage of a stamp at a point (u, v) of its unit square (−1..1, y down), 0..1, before shading.\n * `t` is the sticker's seed for shapes with random parts (splat, confetti).\n */\nexport function stampCoverage(kind: StampKind, u: number, v: number, t: number): number {\n const r = Math.hypot(u, v);\n const a = Math.atan2(v, u);\n const edge = (d: number) => Math.min(1, Math.max(0, d * 24 + 0.5));\n switch (kind) {\n case 'dot':\n return edge(0.95 - r);\n case 'ring':\n return edge(Math.min(0.95 - r, r - 0.6));\n case 'star': {\n // Five points, one straight up: the outline radius falls from the points to the notches.\n const f = (((a + Math.PI / 2) * 5) / (2 * Math.PI)) % 1;\n const notch = Math.min(f < 0 ? f + 1 : f, 1 - (f < 0 ? f + 1 : f)) * 2;\n return edge(0.95 - 0.55 * notch - r);\n }\n case 'sparkle': {\n // A four-pointed twinkle (an astroid): |u|^0.6 + |v|^0.6 ≤ 1.\n const q = Math.pow(Math.abs(u) / 0.95, 0.6) + Math.pow(Math.abs(v) / 0.95, 0.6);\n return edge((1 - q) * 0.4);\n }\n case 'heart': {\n const x = u * 1.1;\n const y = -v * 1.1 + 0.15;\n const q = x * x + y * y - 0.55;\n return edge(-(q * q * q - x * x * y * y * y) * 3);\n }\n case 'leaf': {\n // A pointed oval with a midrib.\n const w = 0.42 * Math.sqrt(Math.max(0, 1 - u * u));\n const inside = edge(w - Math.abs(v + 0.15 * u * u));\n const rib = Math.abs(v + 0.15 * u * u) < 0.03 && Math.abs(u) < 0.85 ? 0.65 : 1;\n return inside * rib;\n }\n case 'flower': {\n const petals = 0.6 + 0.35 * Math.abs(Math.cos(2.5 * a));\n const body = edge(petals - r);\n return r < 0.22 ? Math.max(body, 1) * 0.85 : body;\n }\n case 'confetti': {\n // A small turned rectangle.\n return edge(Math.min(0.9 - Math.abs(u), 0.35 - Math.abs(v)));\n }\n case 'splat': {\n // A blob with drops: a bumpy outline plus a few satellites.\n let rr = 0.55;\n for (let k = 1; k <= 3; k++) rr += 0.08 * Math.sin(a * (k + 2) + hash2(k, 1, t) * 6.28) / k;\n let c = edge(rr - r);\n for (let k = 0; k < 4; k++) {\n const ang = hash2(k, 7, t) * Math.PI * 2;\n const dist = 0.72 + 0.2 * hash2(k, 9, t);\n const dx = u - Math.cos(ang) * dist;\n const dy = v - Math.sin(ang) * dist;\n c = Math.max(c, edge(0.08 + 0.06 * hash2(k, 11, t) - Math.hypot(dx, dy)));\n }\n return c;\n }\n }\n}\n\nfunction hexRgb(hex: string): [number, number, number] {\n const n = parseInt(hex.slice(1, 7), 16);\n return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255];\n}\n\n/** The pixel rectangle a sticker covers. */\nexport function stickerRect(s: Sticker): RasterRect {\n const r = s.size / 2 + 1;\n const x0 = Math.floor(s.x - r);\n const y0 = Math.floor(s.y - r);\n return { x: x0, y: y0, width: Math.ceil(s.x + r) - x0, height: Math.ceil(s.y + r) - y0 };\n}\n\n/**\n * Draws one sticker through a `TileMedium` (straight source-over): the stamp's coverage, lit a\n * little from the top left and given a fine seeded texture, in its colour and opacity.\n */\nexport function drawSticker(medium: TileMedium, s: Sticker): RasterRect {\n const rect = stickerRect(s);\n const n = rect.width * rect.height;\n const cov = new Float32Array(n);\n const field = new Float32Array(n * 3);\n const rad = s.size / 2;\n const a = (s.rotation * Math.PI) / 180;\n const ca = Math.cos(a);\n const sa = Math.sin(a);\n const [r, g, b] = hexRgb(s.color);\n for (let yy = 0, p = 0; yy < rect.height; yy++) {\n for (let xx = 0, px = rect.x; xx < rect.width; xx++, p++, px++) {\n const dx = px + 0.5 - s.x;\n const dy = rect.y + yy + 0.5 - s.y;\n const u = (dx * ca + dy * sa) / rad;\n const v = (-dx * sa + dy * ca) / rad;\n if (u < -1.05 || u > 1.05 || v < -1.05 || v > 1.05) continue;\n // Supersample the edge 2 × 2.\n let c = 0;\n for (let k = 0; k < 4; k++) c += stampCoverage(s.stamp, u + ((k & 1) - 0.5) / rad / 2, v + ((k >> 1) - 0.5) / rad / 2, s.seed);\n c /= 4;\n if (c <= 0) continue;\n cov[p] = c;\n // Shading: lighter towards the top left, and a fine paper texture.\n const shade = 1 + 0.12 * (-(u + v) / 2) + 0.06 * (hash2(px, rect.y + yy, s.seed) - 0.5);\n field[p * 3] = Math.min(1, Math.max(0, r * shade));\n field[p * 3 + 1] = Math.min(1, Math.max(0, g * shade));\n field[p * 3 + 2] = Math.min(1, Math.max(0, b * shade));\n }\n }\n medium.deposit(rect, cov, s.opacity, [r, g, b], null, field);\n return rect;\n}\n\n/** A colour moved in lightness and hue by up to `amount` (deterministic). */\nfunction jitterColor(hex: string, amount: number, seed: number, i: number): string {\n const [r, g, b] = hexRgb(hex);\n const l = (rand01(seed, i, 61) - 0.5) * amount * 0.6;\n const h = (rand01(seed, i, 63) - 0.5) * amount;\n // A small rotation in RGB around grey, then lightness.\n const m = (r + g + b) / 3;\n const rot = (c0: number, c1: number) => c0 + (c1 - c0) * h;\n const out = [rot(r, g), rot(g, b), rot(b, r)].map((c) => Math.min(1, Math.max(0, c + l + (c - m) * 0)));\n return '#' + out.map((c) => Math.round(c * 255).toString(16).padStart(2, '0')).join('');\n}\n\nexport interface StickerSprayInit {\n brush: PaintBrush;\n target: PaintTileTarget;\n /** The paint colour #rrggbb. */\n color: string;\n seed: number;\n copies: readonly StrokeCopy[];\n /** The next sticker number on the layer (ids `st<n>`). */\n nextId: number;\n /** Gradient paint (resolved): each sticker takes its dab's colour (across the tip: by its offset). */\n paint?: PaintGradientSource | null;\n}\n\n/** A sticker-spray stroke: drops stickers along the path and draws them as it goes. */\nexport class StickerSpray {\n dabCount = 0;\n readonly stickers: Sticker[] = [];\n private readonly smoother: PenSmoother;\n private readonly walkers: PenDabWalker[];\n private readonly copies: readonly StrokeCopy[];\n private readonly medium: TileMedium;\n private lastRaw: PenPoint | null = null;\n private lastFed: PenPoint | null = null;\n private next: number;\n\n constructor(readonly init: StickerSprayInit) {\n const b = init.brush;\n this.smoother = new PenSmoother(b.tip.smoothing, b.pressureSmoothing);\n this.copies = init.copies.length ? init.copies : [IDENTITY_COPY];\n // One walked dab per sticker: spacing from the density.\n const spacing = Math.max(0.05, 1 / Math.max(0.05, b.sticker.density * 4));\n const walk: PaintBrush = { ...b, tip: { ...b.tip, spacing }, dynamics: { ...b.dynamics, scatter: 0, sizeJitter: 0, angleJitter: 0 } };\n this.walkers = this.copies.map((c, i) => new PenDabWalker(walk, (init.seed + i * 7919) | 0, c.linear));\n this.medium = new TileMedium(init.target, {});\n this.next = init.nextId;\n }\n\n push(points: readonly PenPoint[]): RasterRect[] {\n const rects: RasterRect[] = [];\n for (const raw of points) {\n this.lastRaw = raw;\n const p = this.smoother.push(raw);\n this.lastFed = p;\n this.copies.forEach((c, i) => {\n const dabs: PenDab[] = [];\n this.walkers[i].push(c.map(p), dabs);\n for (const d of dabs) this.drop(d, rects);\n });\n }\n return rects;\n }\n\n finish(): RasterRect[] {\n const rects: RasterRect[] = [];\n const raw = this.lastRaw;\n const fed = this.lastFed;\n this.copies.forEach((c, i) => {\n const dabs: PenDab[] = [];\n if (raw && fed && (raw.x !== fed.x || raw.y !== fed.y)) this.walkers[i].push(c.map({ ...raw, pressure: fed.pressure }), dabs);\n this.walkers[i].finish(dabs);\n for (const d of dabs) this.drop(d, rects);\n });\n return rects;\n }\n\n private drop(d: PenDab, rects: RasterRect[]): void {\n const st = this.init.brush.sticker;\n const i = this.next;\n const seed = this.init.seed;\n const size = d.radius * 2 * (1 - st.sizeJitter * 0.7 * rand01(seed, i, 51));\n const off = st.scatter * d.radius * 2;\n const a = rand01(seed, i, 53) * Math.PI * 2;\n const dist = rand01(seed, i, 55) * off;\n const base = this.colorAt(d, Math.cos(a) * dist, Math.sin(a) * dist);\n const sticker: Sticker = {\n id: `st${this.next++}`,\n stamp: st.stamps[Math.floor(rand01(seed, i, 57) * st.stamps.length)] ?? 'dot',\n x: Math.round((d.x + Math.cos(a) * dist) * 100) / 100,\n y: Math.round((d.y + Math.sin(a) * dist) * 100) / 100,\n size: Math.max(2, Math.round(size * 10) / 10),\n rotation: Math.round(((-d.angle * 180) / Math.PI + (rand01(seed, i, 59) * 2 - 1) * 180 * st.rotationJitter) * 10) / 10,\n color: st.colorJitter > 0 ? jitterColor(base.color, st.colorJitter, seed, i) : base.color,\n opacity: Math.round(Math.min(1, d.opacity * this.init.brush.tip.opacity * base.alpha) * 1000) / 1000,\n seed: Math.floor(rand01(seed, i, 65) * 1e9),\n };\n this.stickers.push(sticker);\n rects.push(drawSticker(this.medium, sticker));\n this.dabCount++;\n }\n\n private sampler: PaintGradientSampler | null | undefined;\n\n /** A sticker's colour: the paint colour, or gradient paint at its dab (`dx`, `dy` from the dab's centre). */\n private colorAt(d: PenDab, dx: number, dy: number): { color: string; alpha: number } {\n const g = this.init.paint;\n if (!g) return { color: this.init.color, alpha: 1 };\n this.sampler ??= new PaintGradientSampler(g, this.init.seed);\n const s =\n g.map.by === 'across-tip'\n ? this.sampler.sample(((dx * Math.sin(d.direction) + dy * Math.cos(d.direction)) / Math.max(0.5, d.radius) + 1) / 2)\n : this.sampler.dab(d);\n return { color: '#' + s.rgb.map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255).toString(16).padStart(2, '0')).join(''), alpha: s.alpha };\n }\n}\n\n/** A sticker list rendered over a transparent layer, through a tile target. */\nexport function renderStickers(stickers: readonly Sticker[], target: PaintTileTarget): void {\n const medium = new TileMedium(target, {});\n for (const s of stickers) drawSticker(medium, s);\n}\n\n/** Checks and rounds a sticker change; throws a sentence naming the bad field. */\nexport function normalizeStickerUpdate(u: Partial<Omit<Sticker, 'id'>>): Partial<Omit<Sticker, 'id'>> {\n const out: Partial<Omit<Sticker, 'id'>> = {};\n if (u.stamp !== undefined) {\n if (!STAMP_KINDS.includes(u.stamp)) throw new Error(`stamp ${JSON.stringify(u.stamp)} is not a stamp; use ${STAMP_KINDS.join(', ')}.`);\n out.stamp = u.stamp;\n }\n for (const k of ['x', 'y'] as const) if (u[k] !== undefined) {\n if (!Number.isFinite(u[k])) throw new Error(`${k} must be a number of pixels.`);\n out[k] = u[k];\n }\n if (u.size !== undefined) {\n if (!(u.size >= 2 && u.size <= 2048)) throw new Error(`size ${u.size} is out of range; use 2..2048 px.`);\n out.size = u.size;\n }\n if (u.rotation !== undefined) {\n if (!Number.isFinite(u.rotation)) throw new Error('rotation must be degrees.');\n out.rotation = u.rotation;\n }\n if (u.color !== undefined) {\n if (!/^#[0-9a-f]{6}$/i.test(u.color)) throw new Error(`color ${JSON.stringify(u.color)} must be #rrggbb.`);\n out.color = u.color.toLowerCase();\n }\n if (u.opacity !== undefined) {\n if (!(u.opacity >= 0 && u.opacity <= 1)) throw new Error(`opacity ${u.opacity} is out of range; use 0..1.`);\n out.opacity = u.opacity;\n }\n return out;\n}\n\n/** A sticker layer's pixels: its stickers drawn bottom first over a transparent layer. */\nexport function stickerSurface(stickers: readonly Sticker[]): TiledSurface {\n const live = new Map<TileKey, Uint8ClampedArray>();\n const target: PaintTileTarget = {\n offset: { x: 0, y: 0 },\n lockTransparency: false,\n selection: null,\n readTile: (tx, ty) => live.get(tileKey(tx, ty)) ?? null,\n writeTile: (tx, ty) => {\n const k = tileKey(tx, ty);\n let t = live.get(k);\n if (!t) live.set(k, (t = new Uint8ClampedArray(TILE * TILE * 4)));\n return t;\n },\n };\n renderStickers(stickers, target);\n const tiles = new Map<TileKey, Tile>();\n for (const [k, d] of live) {\n const t = finishTile(d, 4, 0);\n if (t) tiles.set(k, t);\n }\n return new TiledSurface(4, tiles, 0);\n}\n","/**\n * Procedural brush engines: marks made by small simulations driven by the pen, rather than by\n * stamping the tip.\n *\n * - **Particle brushes** (`engine: 'particle'`): a handful of particles follow the pen by their own\n * rules. `string`: strands of masses on springs, dragged behind the pen like hair or wet string;\n * `spring`: each particle tied to the pen by a spring, overshooting and wobbling; `orbit`:\n * particles circling the pen (spirograph curls); `flow`: particles thrown off the pen and carried\n * by a swirling flow field until they fade. Each is drawn as `dot`s, a continuous `line`, or a\n * `sequence` of beads spaced along its path.\n * - **Bristle brushes** (`engine: 'bristle'`): a tuft of bristles, each its own thin line. Pressure\n * splays the tuft, tilt flattens it, and bristles lag behind the tip by their stiffness, so they\n * bend into curves at turns; each bristle carries its own paint and runs dry at its own pace, so\n * long strokes break into dry-brush streaks.\n *\n * Both are deterministic (seeded) and step the simulation by distance travelled, not by how the\n * input was sampled, so a replay paints the same marks. They build up a `CoverageMap` like the dab\n * engine, so opacity, blend modes, locks, stencils and symmetry work as for any dry brush.\n */\n\nimport { CoverageMap, dabRect, rasterizeDab, TIP_GRADIENT_STEPS, type Dab } from '../paint/brush';\nimport { PaintGradientSampler, type PaintGradientSample, type PaintGradientSource } from '../paint/gradient-paint';\nimport type { RasterRect } from '../raster/surface';\nimport type { PaintBrush } from './brushes';\nimport { IDENTITY_COPY, PenDabWalker, PenSmoother, type PenDab, type PenPoint, type StrokeCopy } from './engine';\nimport { rand01 } from './noise';\nimport { grainCatch, type PaperGrain } from './paper';\n\nexport interface ProceduralStrokeOptions {\n grain: PaperGrain | null;\n paperDepth: number;\n seed?: number;\n copies?: readonly StrokeCopy[];\n /** Gradient paint (resolved): each mark takes the colour of the pen dab that made it. */\n paint?: PaintGradientSource | null;\n}\n\n/** What a coverage-building stroke engine provides to the stroke session. */\nexport interface CoverageStroke {\n readonly coverage: CoverageMap;\n dabCount: number;\n push(points: readonly PenPoint[]): RasterRect[];\n finish(): RasterRect[];\n}\n\n/** Pixels of pen travel per simulation step. */\nconst STEP_PX = 1.5;\n\n/** Shared plumbing: smoothing, the dab walk per copy (for size, pressure, direction), grain, and stamping marks. */\nabstract class MarkStroke implements CoverageStroke {\n readonly coverage = new CoverageMap();\n dabCount = 0;\n protected readonly smoother: PenSmoother;\n protected readonly copies: readonly StrokeCopy[];\n protected readonly walkers: PenDabWalker[];\n protected readonly depth: number;\n private buf = new Float32Array(0);\n private lastRaw: PenPoint | null = null;\n private lastFed: PenPoint | null = null;\n protected readonly seed: number;\n private readonly sampler: PaintGradientSampler | null;\n private readonly tipTable: PaintGradientSample[] | null;\n /** The pen dab the marks being made belong to, and its gradient colour. */\n private pen: PenDab | null = null;\n private penColor: PaintGradientSample = { rgb: [0, 0, 0], alpha: 1 };\n\n constructor(\n readonly brush: PaintBrush,\n protected readonly options: ProceduralStrokeOptions\n ) {\n this.sampler = options.paint ? new PaintGradientSampler(options.paint, options.seed ?? 0) : null;\n this.tipTable = this.sampler?.acrossTip ? this.sampler.tipTable(TIP_GRADIENT_STEPS) : null;\n this.smoother = new PenSmoother(brush.tip.smoothing, brush.pressureSmoothing);\n this.copies = options.copies?.length ? options.copies : [IDENTITY_COPY];\n this.seed = options.seed ?? 0;\n // A fine walk (spacing a fraction of the tip): each walked dab is a simulation input.\n const fine: PaintBrush = { ...brush, tip: { ...brush.tip, spacing: Math.max(0.01, Math.min(0.25, STEP_PX / Math.max(1, brush.tip.size))) } };\n this.walkers = this.copies.map((c, i) => new PenDabWalker(fine, ((options.seed ?? 0) + i * 7919) | 0, c.linear));\n this.depth = options.grain && !options.grain.flat ? Math.min(1, Math.max(0, options.paperDepth * brush.grain)) : 0;\n }\n\n push(points: readonly PenPoint[]): RasterRect[] {\n const rects: RasterRect[] = [];\n for (const raw of points) {\n this.lastRaw = raw;\n const p = this.smoother.push(raw);\n this.lastFed = p;\n this.copies.forEach((c, i) => {\n const dabs: PenDab[] = [];\n this.walkers[i].push(c.map(p), dabs);\n for (const d of dabs) this.step(i, d, rects);\n });\n }\n return rects;\n }\n\n private step(copy: number, d: PenDab, rects: RasterRect[]): void {\n if (this.sampler) {\n this.pen = d;\n if (!this.tipTable) this.sampler.dab(d, this.penColor);\n }\n this.advance(copy, d, rects);\n }\n\n /** The colour of a mark at (x, y): its pen dab's, or across the tip by its offset from the pen. */\n private markColor(x: number, y: number): PaintGradientSample | null {\n if (!this.sampler || !this.pen) return null;\n if (!this.tipTable) return this.penColor;\n const d = this.pen;\n const u = ((x - d.x) * Math.sin(d.direction) + (y - d.y) * Math.cos(d.direction)) / Math.max(0.5, d.radius);\n const last = this.tipTable.length - 1;\n return this.tipTable[Math.min(last, Math.max(0, Math.round(((u + 1) / 2) * last)))];\n }\n\n finish(): RasterRect[] {\n const rects: RasterRect[] = [];\n const raw = this.lastRaw;\n const fed = this.lastFed;\n this.copies.forEach((c, i) => {\n const dabs: PenDab[] = [];\n if (raw && fed && (raw.x !== fed.x || raw.y !== fed.y)) this.walkers[i].push(c.map({ ...raw, pressure: fed.pressure }), dabs);\n this.walkers[i].finish(dabs);\n for (const d of dabs) this.step(i, d, rects);\n });\n return rects;\n }\n\n /** One simulation step of copy `copy` with the pen at dab `d`. */\n protected abstract advance(copy: number, d: PenDab, rects: RasterRect[]): void;\n\n /** Stamps one round mark of radius `r` at (x, y) with flow `alpha` towards `opacity`. */\n protected mark(x: number, y: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void {\n if (!(r > 0.05) || !(alpha > 0)) return;\n const dab: Dab = { x, y, radius: Math.max(0.5, r), alpha: Math.min(1, alpha), opacity: Math.min(1, opacity), angle: 0, roundness: 1 };\n const hardness = this.brush.tip.hardness;\n const rect = dabRect(dab, hardness);\n const n = rect.width * rect.height;\n if (n <= 0) return;\n if (this.buf.length < n) this.buf = new Float32Array(n);\n const vals = this.buf.subarray(0, n);\n rasterizeDab(dab, hardness, rect, vals);\n const grain = this.options.grain;\n if (this.depth > 0 && grain) {\n for (let yy = 0, k = 0; yy < rect.height; yy++)\n for (let xx = 0; xx < rect.width; xx++, k++) if (vals[k] > 0) vals[k] *= grainCatch(grain.at(rect.x + xx + 0.5, rect.y + yy + 0.5), this.depth, pressure);\n }\n const color = this.markColor(x, y);\n if (color && color.alpha < 1) for (let k = 0; k < n; k++) vals[k] *= color.alpha;\n this.coverage.accumulate(rect, vals, dab.opacity, color ? color.rgb : null);\n rects.push(rect);\n this.dabCount++;\n }\n\n /** Marks along a segment, spaced by a fraction of the radius. */\n protected segment(x0: number, y0: number, x1: number, y1: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void {\n const len = Math.hypot(x1 - x0, y1 - y0);\n const step = Math.max(0.35, r * 0.5);\n const n = Math.max(1, Math.ceil(len / step));\n for (let i = 1; i <= n; i++) this.mark(x0 + ((x1 - x0) * i) / n, y0 + ((y1 - y0) * i) / n, r, alpha, opacity, pressure, rects);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Particle brushes\n// ---------------------------------------------------------------------------\n\nexport type ParticleKind = 'string' | 'spring' | 'orbit' | 'flow';\nexport const PARTICLE_KINDS: readonly ParticleKind[] = ['string', 'spring', 'orbit', 'flow'];\nexport type ParticleRender = 'dot' | 'line' | 'sequence';\nexport const PARTICLE_RENDERS: readonly ParticleRender[] = ['dot', 'line', 'sequence'];\n\n/** Particle engine settings (each 0..1 unless noted). */\nexport interface ParticleSettings {\n kind: ParticleKind;\n render: ParticleRender;\n /** Particles, 1..64. */\n count: number;\n /** Mark size as a fraction of the tip size. */\n size: number;\n /** How far apart the particles start, as a fraction of the tip size. */\n spread: number;\n /** Spring and string stiffness (stiff follows closely; soft swings wide). */\n stiffness: number;\n /** How quickly motion dies down. */\n damping: number;\n /** Orbit and flow speed. */\n speed: number;\n /** Pull downwards (−1 up .. 1 down). */\n gravity: number;\n /** Flow particles' lifetime. */\n life: number;\n /** Sequence: spacing of the beads along each path. */\n interval: number;\n}\n\nexport const DEFAULT_PARTICLE: Readonly<ParticleSettings> = { kind: 'spring', render: 'line', count: 12, size: 0.08, spread: 0.5, stiffness: 0.4, damping: 0.25, speed: 0.5, gravity: 0, life: 0.5, interval: 0.3 };\n\nconst unit = (v: unknown, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d);\n\nexport function normalizeParticle(raw: Partial<ParticleSettings> = {}, base: ParticleSettings = DEFAULT_PARTICLE): ParticleSettings {\n return {\n kind: PARTICLE_KINDS.includes(raw.kind as ParticleKind) ? (raw.kind as ParticleKind) : base.kind,\n render: PARTICLE_RENDERS.includes(raw.render as ParticleRender) ? (raw.render as ParticleRender) : base.render,\n count: typeof raw.count === 'number' && Number.isFinite(raw.count) ? Math.min(64, Math.max(1, Math.round(raw.count))) : base.count,\n size: unit(raw.size, base.size),\n spread: unit(raw.spread, base.spread),\n stiffness: unit(raw.stiffness, base.stiffness),\n damping: unit(raw.damping, base.damping),\n speed: unit(raw.speed, base.speed),\n gravity: typeof raw.gravity === 'number' && Number.isFinite(raw.gravity) ? Math.min(1, Math.max(-1, raw.gravity)) : base.gravity,\n life: unit(raw.life, base.life),\n interval: unit(raw.interval, base.interval),\n };\n}\n\ninterface Particle {\n x: number;\n y: number;\n vx: number;\n vy: number;\n /** Rest offset from the pen (spring) or orbit radius and phase. */\n ox: number;\n oy: number;\n k: number;\n phase: number;\n age: number;\n /** Distance travelled since the last bead (sequence). */\n run: number;\n bead: number;\n alive: boolean;\n /** string: the masses of the strand, pen end first. */\n strand?: Array<{ x: number; y: number; vx: number; vy: number }>;\n}\n\n/** Curl of a value-noise field (a swirling, divergence-free flow), deterministic. */\nfunction curl(x: number, y: number, seed: number): [number, number] {\n const n = (u: number, v: number) => {\n const x0 = Math.floor(u);\n const y0 = Math.floor(v);\n const fx = u - x0;\n const fy = v - y0;\n const sx = fx * fx * (3 - 2 * fx);\n const sy = fy * fy * (3 - 2 * fy);\n const h = (a: number, b: number) => rand01(seed, a * 73856093 + b * 19349663, 41);\n const a = h(x0, y0);\n const b = h(x0 + 1, y0);\n const c = h(x0, y0 + 1);\n const d = h(x0 + 1, y0 + 1);\n return a + (b - a) * sx + (c - a) * sy + (a - b - c + d) * sx * sy;\n };\n const e = 0.01;\n return [(n(x, y + e) - n(x, y - e)) / (2 * e), -(n(x + e, y) - n(x - e, y)) / (2 * e)];\n}\n\n/** A particle-brush stroke. */\nexport class ParticleStroke extends MarkStroke {\n private readonly sets: Particle[][];\n private readonly s: ParticleSettings;\n private spawn = 0;\n\n constructor(brush: PaintBrush, options: ProceduralStrokeOptions) {\n super(brush, options);\n this.s = brush.particle;\n this.sets = this.copies.map(() => []);\n }\n\n private init(copy: number, d: PenDab): void {\n const s = this.s;\n const list = this.sets[copy];\n const size = Math.max(1, d.radius * 2);\n for (let i = 0; i < (s.kind === 'flow' ? 0 : s.count); i++) {\n const r = rand01(this.seed, i, 3 + copy) * s.spread * size * 0.5;\n const a = rand01(this.seed, i, 5 + copy) * Math.PI * 2;\n const ox = Math.cos(a) * r;\n const oy = Math.sin(a) * r;\n const p: Particle = { x: d.x + ox, y: d.y + oy, vx: 0, vy: 0, ox, oy, k: 0.6 + 0.8 * rand01(this.seed, i, 7), phase: a, age: 0, run: 0, bead: 0, alive: true };\n if (s.kind === 'string') p.strand = Array.from({ length: 6 }, () => ({ x: d.x + ox, y: d.y + oy, vx: 0, vy: 0 }));\n if (s.kind === 'orbit') {\n p.ox = Math.max(1, r + size * 0.15);\n p.oy = 0;\n }\n list.push(p);\n }\n }\n\n protected advance(copy: number, d: PenDab, rects: RasterRect[]): void {\n const s = this.s;\n const list = this.sets[copy];\n if (d.index === 0 && !list.length) this.init(copy, d);\n const size = Math.max(1, d.radius * 2);\n const markR = Math.max(0.5, (size * s.size) / 2);\n const k = 0.02 + 0.3 * s.stiffness;\n const damp = 0.6 + 0.38 * (1 - s.damping);\n const g = s.gravity * 0.15;\n const op = d.opacity;\n const al = Math.max(0.05, d.alpha);\n if (s.kind === 'flow') {\n // Throw off particles at the pen while it moves.\n this.spawn += s.count / 8;\n while (this.spawn >= 1) {\n this.spawn -= 1;\n const i = this.dabCount + list.length * 31 + Math.floor(d.index);\n const a = rand01(this.seed, i, 11 + copy) * Math.PI * 2;\n const r = rand01(this.seed, i, 13 + copy) * s.spread * size * 0.5;\n list.push({ x: d.x + Math.cos(a) * r, y: d.y + Math.sin(a) * r, vx: 0, vy: 0, ox: 0, oy: 0, k: 1, phase: a, age: 0, run: 0, bead: 0, alive: true });\n }\n }\n const lifeSteps = 8 + 120 * s.life;\n for (let i = 0; i < list.length; i++) {\n const p = list[i];\n if (!p.alive) continue;\n const px = p.x;\n const py = p.y;\n switch (s.kind) {\n case 'spring': {\n p.vx = (p.vx + (d.x + p.ox - p.x) * k * p.k) * damp;\n p.vy = (p.vy + (d.y + p.oy - p.y) * k * p.k + g) * damp;\n p.x += p.vx;\n p.y += p.vy;\n break;\n }\n case 'string': {\n // A strand of masses: the first tied to the pen, each to the one before.\n const strand = p.strand!;\n let ax = d.x + p.ox;\n let ay = d.y + p.oy;\n for (const m of strand) {\n m.vx = (m.vx + (ax - m.x) * k * p.k + 0) * damp;\n m.vy = (m.vy + (ay - m.y) * k * p.k + g) * damp;\n m.x += m.vx;\n m.y += m.vy;\n ax = m.x;\n ay = m.y;\n }\n p.x = strand[strand.length - 1].x;\n p.y = strand[strand.length - 1].y;\n break;\n }\n case 'orbit': {\n p.phase += (0.05 + 0.3 * s.speed) * (i % 2 ? -1 : 1) * (0.7 + 0.6 * rand01(this.seed, i, 17));\n p.x = d.x + Math.cos(p.phase) * p.ox;\n p.y = d.y + Math.sin(p.phase) * p.ox + g * p.ox;\n break;\n }\n case 'flow': {\n // The field's slope is about 1 per field cell; the push is a small fraction of the tip per step.\n const [fx, fy] = curl(p.x / Math.max(8, size * 1.5), p.y / Math.max(8, size * 1.5), this.seed);\n const push = size * 0.012 * (0.3 + 1.5 * s.speed);\n const fl = Math.hypot(fx, fy) || 1;\n p.vx = p.vx * 0.8 + (fx / fl) * push;\n p.vy = p.vy * 0.8 + (fy / fl) * push + g * 0.2;\n p.x += p.vx;\n p.y += p.vy;\n p.age++;\n if (p.age > lifeSteps) p.alive = false;\n break;\n }\n }\n const fade = s.kind === 'flow' ? 1 - p.age / lifeSteps : 1;\n const moved = Math.hypot(p.x - px, p.y - py);\n if (d.index === 0 && s.kind !== 'flow') continue;\n if (s.render === 'dot') this.mark(p.x, p.y, markR * fade, al * fade, op, d.pressure, rects);\n else if (s.render === 'line') this.segment(px, py, p.x, p.y, markR * fade, al * fade, op, d.pressure, rects);\n else {\n // Beads along the path, each a little larger in the middle of its run.\n p.run += moved;\n const gap = Math.max(markR * 2, size * (0.05 + s.interval));\n while (p.run >= gap) {\n p.run -= gap;\n p.bead++;\n const t = moved > 0 ? 1 - p.run / Math.max(moved, 1e-6) : 1;\n const bx = px + (p.x - px) * Math.min(1, Math.max(0, t));\n const by = py + (p.y - py) * Math.min(1, Math.max(0, t));\n this.mark(bx, by, markR * (0.7 + 0.6 * ((p.bead % 3) / 2)) * fade, al * fade, op, d.pressure, rects);\n }\n }\n }\n if (s.kind === 'flow' && list.length > 512) this.sets[copy] = list.filter((p) => p.alive);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Bristle brushes\n// ---------------------------------------------------------------------------\n\n/** Bristle engine settings (each 0..1 unless noted). */\nexport interface BristleSettings {\n /** Bristles in the tuft, 3..128. */\n count: number;\n /** Stiff bristles follow the tip; soft ones lag and bend into curves at turns. */\n stiffness: number;\n /** How far pressure spreads the tuft. */\n splay: number;\n /** Width of each bristle's line as a fraction of the tip size. */\n thickness: number;\n /** Paint per bristle: 1 never runs dry; lower, bristles run out along the stroke (dry brush). */\n load: number;\n /** Random variation between bristles (length, paint, position). */\n jitter: number;\n}\n\nexport const DEFAULT_BRISTLE: Readonly<BristleSettings> = { count: 32, stiffness: 0.5, splay: 0.5, thickness: 0.06, load: 0.6, jitter: 0.4 };\n\nexport function normalizeBristle(raw: Partial<BristleSettings> = {}, base: BristleSettings = DEFAULT_BRISTLE): BristleSettings {\n return {\n count: typeof raw.count === 'number' && Number.isFinite(raw.count) ? Math.min(128, Math.max(3, Math.round(raw.count))) : base.count,\n stiffness: unit(raw.stiffness, base.stiffness),\n splay: unit(raw.splay, base.splay),\n thickness: unit(raw.thickness, base.thickness),\n load: unit(raw.load, base.load),\n jitter: unit(raw.jitter, base.jitter),\n };\n}\n\ninterface Bristle {\n /** Place in the tuft: across (−1..1) and along (−1..1) the tip. */\n u: number;\n v: number;\n x: number;\n y: number;\n paint: number;\n /** How fast it runs dry. */\n thirst: number;\n /** Extra width. */\n w: number;\n started: boolean;\n}\n\n/** A bristle-brush stroke: every bristle draws its own line. */\nexport class BristleStroke extends MarkStroke {\n private readonly tufts: Bristle[][];\n private readonly s: BristleSettings;\n\n constructor(brush: PaintBrush, options: ProceduralStrokeOptions) {\n super(brush, options);\n this.s = brush.bristle;\n const s = this.s;\n this.tufts = this.copies.map((_, c) =>\n Array.from({ length: s.count }, (_, i) => {\n // Spread over an ellipse, denser in the middle.\n const a = rand01(this.seed, i, 21 + c) * Math.PI * 2;\n const r = Math.sqrt(rand01(this.seed, i, 23 + c));\n return {\n u: Math.cos(a) * r,\n v: Math.sin(a) * r,\n x: 0,\n y: 0,\n paint: 1 - s.jitter * 0.4 * rand01(this.seed, i, 25 + c),\n thirst: 1 + s.jitter * (rand01(this.seed, i, 27 + c) * 2 - 1),\n w: 1 + s.jitter * 0.6 * (rand01(this.seed, i, 29 + c) - 0.5),\n started: false,\n };\n })\n );\n }\n\n protected advance(copy: number, d: PenDab, rects: RasterRect[]): void {\n const s = this.s;\n const tuft = this.tufts[copy];\n // Pressure splays the tuft; the tip's roundness and angle (tilt, rotation) shape it.\n const spread = d.radius * (0.55 + 0.9 * s.splay * d.pressure);\n const ca = Math.cos(d.angle);\n const sa = Math.sin(d.angle);\n const ro = Math.max(0.15, d.roundness);\n // Direction of travel (dab directions are counter-clockwise with y up).\n const tx = Math.cos(d.direction);\n const ty = -Math.sin(d.direction);\n const follow = 0.15 + 0.85 * s.stiffness;\n const bend = d.radius * (1 - s.stiffness) * d.pressure * 0.8;\n const lineR = Math.max(0.5, d.radius * 2 * s.thickness * 0.5);\n const dryRate = 0.004 * (1 - s.load);\n for (const b of tuft) {\n // Where the bristle wants to be: its place in the tuft (rotated with the tip, flattened by\n // tilt), bent back against the direction of travel by pressure.\n const lu = b.u * spread;\n const lv = b.v * spread * ro;\n const ox = lu * ca - lv * sa;\n const oy = -(lu * sa + lv * ca);\n const lag = bend * (1 - 0.5 * b.v);\n const wx = d.x + ox - tx * lag;\n const wy = d.y + oy - ty * lag;\n if (!b.started) {\n b.x = wx;\n b.y = wy;\n b.started = true;\n continue;\n }\n const nx = b.x + (wx - b.x) * follow;\n const ny = b.y + (wy - b.y) * follow;\n const paint = Math.max(0, b.paint);\n if (paint > 0.02) this.segment(b.x, b.y, nx, ny, lineR * b.w * (0.6 + 0.4 * d.pressure), d.alpha * Math.min(1, paint * 1.4), d.opacity, d.pressure, rects);\n b.paint -= dryRate * b.thirst * Math.hypot(nx - b.x, ny - b.y);\n b.x = nx;\n b.y = ny;\n }\n }\n}\n","/**\n * Paint editor brushes: the shared engine's tip settings (`@pixerate/editor/paint`) plus what a\n * natural-media brush adds: paper grain response, pen dynamics (pressure, tilt, barrel rotation,\n * velocity), separate pressure smoothing, a rotation mode, jitter, and Mixer Brush settings for\n * the blending brushes. The built-in presets are our own settings; none come from another product.\n */\n\nimport { DEFAULT_BRUSH, MAX_BRUSH_SIZE, normalizeBrush, type BrushSettings } from '../paint/brush';\nimport { DEFAULT_BLENDER, DEFAULT_SMUDGE, normalizeBlender, normalizeSmudge, type BlenderSettings, type SmudgeSettings } from '../paint/blending';\nimport type { MixingModel } from '../paint/exchange';\nimport { readPaintSource, type PaintGradientSource, type PaintSource } from '../paint/gradient-paint';\nimport { DEFAULT_MIXER, normalizeMixer, type MixerSettings } from '../paint/mixer';\nimport { DEFAULT_STICKER, normalizeStickerSettings, type StickerSettings } from './stickers';\nimport { DEFAULT_BRISTLE, DEFAULT_PARTICLE, normalizeBristle, normalizeParticle, type BristleSettings, type ParticleSettings } from './procedural';\n\n/**\n * How a brush makes marks: `dab` (dabs into a stroke buffer, or dab by dab through the pick-up /\n * mix exchange when its behaviour asks for it), `eraser` (removes alpha), `mixer` (the Mixer\n * Brush), `blender` (mixes the colours under and near the tip) or `smudge` (drags paint along).\n */\nexport type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker';\n\nexport const PAINT_BRUSH_ENGINES: readonly PaintBrushEngine[] = ['dab', 'eraser', 'mixer', 'blender', 'smudge', 'wet', 'impasto', 'particle', 'bristle', 'sticker'];\n\nexport type PaintBrushCategory = 'pencil' | 'pastel' | 'charcoal' | 'airbrush' | 'marker' | 'ink' | 'paint' | 'eraser' | 'blender' | 'smudge' | 'mixer' | 'watercolor' | 'wet-tool' | 'oil' | 'impasto' | 'procedural' | 'bristle' | 'sticker' | 'custom';\n\nexport const PAINT_BRUSH_CATEGORIES: readonly PaintBrushCategory[] = ['pencil', 'pastel', 'charcoal', 'airbrush', 'marker', 'ink', 'paint', 'eraser', 'blender', 'smudge', 'mixer', 'watercolor', 'wet-tool', 'oil', 'impasto', 'procedural', 'bristle', 'sticker', 'custom'];\n\n/**\n * What a wet brush does to the wet layer: `paint` (water and pigment), `water` (clear water;\n * with `rewet` it lifts dried paint), `dry` (a hair dryer: takes water, the pigment settles),\n * `blow` (pushes the water along the stroke), `blend` (evens out the wet pigment under the tip),\n * `smudge` (drags wet paint along) or `blot` (a tissue: takes up wet paint).\n */\nexport type WetTool = 'paint' | 'water' | 'dry' | 'blow' | 'blend' | 'smudge' | 'blot';\n\nexport const WET_TOOLS: readonly WetTool[] = ['paint', 'water', 'dry', 'blow', 'blend', 'smudge', 'blot'];\n\n/**\n * The wet medium a wet brush paints: its layer takes the medium's wet settings the first time it\n * holds wet paint (`watercolor`: runny, dries in seconds, granulates and darkens at edges;\n * `gouache`: opaque, flatter; `oil`: thick, barely flows, stays wet for a long time and blends into\n * the wet paint it meets).\n */\nexport type WetMediumKind = 'watercolor' | 'gouache' | 'oil';\n\nexport const WET_MEDIA: readonly WetMediumKind[] = ['watercolor', 'gouache', 'oil'];\n\n/** Wet engine settings, each 0..1. */\nexport interface WetBrushSettings {\n tool: WetTool;\n /** Water the brush lays down (wetness): 0.2 a damp brush, 1 a dripping one. */\n water: number;\n /** Pigment concentration: 0 clear water .. 1 paint straight from the tube. */\n pigment: number;\n /** Body: 0 a transparent watercolour .. 1 opaque gouache that hides what is under it. */\n body: number;\n /** Strength of the dry, blow, blend, smudge and blot tools. */\n strength: number;\n /** How much dried paint the water lifts again (re-wetting): 0 none (staining) .. 1. */\n rewet: number;\n /** The medium (its layer's wet settings the first time it holds wet paint). */\n medium: WetMediumKind;\n /** Paint loading: 1 never runs out; lower, the brush runs dry along a long stroke (reload each stroke). */\n load: number;\n /** Thinner (water for watercolour, solvent for oil): thins the paint, so it is more transparent and runnier. */\n thinner: number;\n}\n\nexport const DEFAULT_WET_BRUSH: Readonly<WetBrushSettings> = { tool: 'paint', water: 0.5, pigment: 0.5, body: 0, strength: 0.5, rewet: 0, medium: 'watercolor', load: 1, thinner: 0 };\n\nexport function normalizeWetBrush(raw: Partial<WetBrushSettings> = {}, base: WetBrushSettings = DEFAULT_WET_BRUSH): WetBrushSettings {\n return {\n tool: WET_TOOLS.includes(raw.tool as WetTool) ? (raw.tool as WetTool) : base.tool,\n water: unit(raw.water, base.water),\n pigment: unit(raw.pigment, base.pigment),\n body: unit(raw.body, base.body),\n strength: unit(raw.strength, base.strength),\n rewet: unit(raw.rewet, base.rewet),\n medium: WET_MEDIA.includes(raw.medium as WetMediumKind) ? (raw.medium as WetMediumKind) : (base.medium ?? 'watercolor'),\n load: unit(raw.load, base.load ?? 1),\n thinner: unit(raw.thinner, base.thinner ?? 0),\n };\n}\n\n/**\n * What an impasto brush does on a thick-paint layer: `brush` (paint with body: colour and relief),\n * `tube` (squeezes blobs of paint straight from the tube), `knife` (a palette knife: scrapes the\n * relief flat and smears the paint along), `roller` (a flat, even band with a stipple), `gloop`\n * (a thick, glossy, rounded line).\n */\nexport type ImpastoTool = 'brush' | 'tube' | 'knife' | 'roller' | 'gloop';\n\nexport const IMPASTO_TOOLS: readonly ImpastoTool[] = ['brush', 'tube', 'knife', 'roller', 'gloop'];\n\n/** Impasto engine settings, each 0..1. */\nexport interface ImpastoSettings {\n tool: ImpastoTool;\n /** How thick the paint stands up (relief per stroke). */\n thickness: number;\n /** Shine of the paint when lit (0 matte .. 1 wet-looking gloss). */\n gloss: number;\n /** Metallic paint: highlights take the paint's colour (gold, copper, silver). */\n metallic: number;\n /** Paint loading: 1 never runs out; lower, the stroke thins and fades as the brush empties. */\n load: number;\n /** Thinner: flatter, more transparent paint that levels out. */\n thinner: number;\n /** Knife and brush: how much of the paint under the tool is dragged along (0..1). */\n drag: number;\n}\n\nexport const DEFAULT_IMPASTO: Readonly<ImpastoSettings> = { tool: 'brush', thickness: 0.6, gloss: 0.4, metallic: 0, load: 0.9, thinner: 0, drag: 0.4 };\n\nexport function normalizeImpasto(raw: Partial<ImpastoSettings> = {}, base: ImpastoSettings = DEFAULT_IMPASTO): ImpastoSettings {\n return {\n tool: IMPASTO_TOOLS.includes(raw.tool as ImpastoTool) ? (raw.tool as ImpastoTool) : base.tool,\n thickness: unit(raw.thickness, base.thickness),\n gloss: unit(raw.gloss, base.gloss),\n metallic: unit(raw.metallic, base.metallic),\n load: unit(raw.load, base.load),\n thinner: unit(raw.thinner, base.thinner),\n drag: unit(raw.drag, base.drag),\n };\n}\n\n/** Multi-coloured brush: `tip` lays the colours across the tip, `dab` changes colour from dab to dab. */\nexport type MultiColorMode = 'off' | 'tip' | 'dab';\n\nexport const MULTI_COLOR_MODES: readonly MultiColorMode[] = ['off', 'tip', 'dab'];\n\nexport interface MultiColorSettings {\n /** `off` (default), `tip` (the colours side by side across the tip, like a brush loaded with several paints; the stripes follow the stroke) or `dab` (the colour changes along the stroke). */\n mode: MultiColorMode;\n /** 2..8 colours #rrggbb. Fewer than 2: the paint colour and the secondary colour. */\n colors: string[];\n /** `dab` mode: `sequence` (default) runs through the colours in order, blending between them; `random` picks one per run of dabs (seeded, so replays match). */\n order: 'sequence' | 'random';\n /** `dab` mode: dabs per colour, 1..500 (default 12). */\n length: number;\n /** How softly neighbouring colours blend, 0 (hard stripes or steps) .. 1 (smooth gradient, default). */\n softness: number;\n}\n\nexport const DEFAULT_MULTI_COLOR: Readonly<MultiColorSettings> = { mode: 'off', colors: [], order: 'sequence', length: 12, softness: 1 };\n\n/**\n * How a brush handles paint on the canvas. The pick-up / mix ratios are the shared exchange's\n * (`@pixerate/editor/paint` `PaintExchange`); wet media will use the same ones. On a Mixer Brush\n * they are its `mixer.wet`, `mixer.mix`, `!mixer.cleanEachStroke` and `mixer.mixing`, kept in sync.\n */\nexport interface BrushBehavior {\n /** Pick-up ratio, 0..1: how much of the paint under each dab the brush lifts and carries (0: none, default). */\n pickup: number;\n /** Mix ratio, 0..1: how much of the carried paint goes into what the brush lays down, against its own colour (default 0.5). */\n mix: number;\n /** Dirty brush: keep the carried paint after the stroke, so the next stroke starts with the last colour the brush touched (default false). */\n dirty: boolean;\n /** How picked-up paint, multi-colour gradients and the deposit mix: `pigment` (default, Kubelka-Munk) or `rgb`. */\n mixing: MixingModel;\n /** Multi-coloured brush. */\n multicolor: MultiColorSettings;\n}\n\nexport const DEFAULT_BEHAVIOR: Readonly<BrushBehavior> = { pickup: 0, mix: 0.5, dirty: false, mixing: 'pigment', multicolor: DEFAULT_MULTI_COLOR };\n\n/** What turns the tip: a fixed angle, the direction of the stroke, or the pen's barrel rotation. */\nexport type BrushRotation = 'fixed' | 'stroke' | 'barrel';\n\nexport const BRUSH_ROTATIONS: readonly BrushRotation[] = ['fixed', 'stroke', 'barrel'];\n\n/** Pen dynamics and jitter. Every amount is 0 (off) .. 1 unless noted. */\nexport interface BrushDynamics {\n /** Size at zero pressure as a fraction of the full size, when pressure controls size (default 0). */\n minSize: number;\n /** How much pressure scales flow (default 0). */\n pressureFlow: number;\n /** Laying the pen down widens the tip, up to 2.5× (default 0). */\n tiltSize: number;\n /** Laying the pen down flattens the tip along the tilt direction (default 0). */\n tiltRoundness: number;\n /** Laying the pen down lightens the mark, as when shading with the side of a pencil (default 0). */\n tiltOpacity: number;\n /** -1..1: positive grows the tip when the pen moves fast, negative thins it (default 0). */\n velocitySize: number;\n /** -1..1: positive darkens fast marks, negative lightens them (default 0). */\n velocityOpacity: number;\n /** Random size change per dab (default 0). */\n sizeJitter: number;\n /** Random angle per dab, as a fraction of ±180° (default 0). */\n angleJitter: number;\n /** Random opacity drop per dab (default 0). */\n opacityJitter: number;\n /** Random offset across the stroke in diameters, 0..4 (default 0). */\n scatter: number;\n}\n\nexport const DEFAULT_DYNAMICS: Readonly<BrushDynamics> = {\n minSize: 0,\n pressureFlow: 0,\n tiltSize: 0,\n tiltRoundness: 0,\n tiltOpacity: 0,\n velocitySize: 0,\n velocityOpacity: 0,\n sizeJitter: 0,\n angleJitter: 0,\n opacityJitter: 0,\n scatter: 0,\n};\n\nexport interface PaintBrush {\n /** Library id (lowercase letters, digits and dashes). */\n id: string;\n name: string;\n category: PaintBrushCategory;\n engine: PaintBrushEngine;\n /** The shared engine's tip: size, hardness, spacing, angle, roundness, opacity, flow, position smoothing, pressure to size / opacity, blend. */\n tip: BrushSettings;\n /** How strongly the mark follows the paper grain, 0 (ignores it) .. 1 (catches only the peaks at light pressure). */\n grain: number;\n /** Pressure smoothing 0..0.95, separate from the tip's position smoothing (default 0). */\n pressureSmoothing: number;\n rotation: BrushRotation;\n dynamics: BrushDynamics;\n /** Mixer engine only: the Mixer Brush settings. */\n mixer: MixerSettings;\n /** Mixer engine only: load the current colour each stroke (false: a smudge or blender that only moves paint). */\n loadsColor: boolean;\n /** Pick-up and mix ratios, dirty brush and multi-colour (dab and mixer engines). */\n behavior: BrushBehavior;\n /** Blender engine only: strength, blend distance and mixing. */\n blender: BlenderSettings;\n /** Smudge engine only: strength, length and mixing. */\n smudge: SmudgeSettings;\n /** Wet engine only: the wet tool, water, pigment, body and strength. */\n wet: WetBrushSettings;\n /** Impasto engine only: the tool, thickness, gloss, metallic, loading, thinner and drag. */\n impasto: ImpastoSettings;\n /** Particle engine only: the particles' kind, how they are drawn, and their physics. */\n particle: ParticleSettings;\n /** Bristle engine only: the tuft. */\n bristle: BristleSettings;\n /** Sticker engine only: the stamps and how they are sprayed. */\n sticker: StickerSettings;\n /**\n * The brush's own gradient paint (`@pixerate/editor/paint` `PaintGradientSource`), used instead\n * of the editor's paint; `null` (default): the editor's paint. Stops may be `paint` / `secondary`\n * (the editor's two colours). This is what the multi-colour brush became.\n */\n paint: PaintGradientSource | null;\n /** True for the built-in presets (they cannot be removed or overwritten). */\n builtin?: boolean;\n}\n\nconst unit = (v: unknown, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d);\nconst range = (v: unknown, lo: number, hi: number, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d);\n\nexport function normalizeDynamics(raw: Partial<BrushDynamics> = {}, base: BrushDynamics = DEFAULT_DYNAMICS): BrushDynamics {\n return {\n minSize: unit(raw.minSize, base.minSize),\n pressureFlow: unit(raw.pressureFlow, base.pressureFlow),\n tiltSize: unit(raw.tiltSize, base.tiltSize),\n tiltRoundness: unit(raw.tiltRoundness, base.tiltRoundness),\n tiltOpacity: unit(raw.tiltOpacity, base.tiltOpacity),\n velocitySize: range(raw.velocitySize, -1, 1, base.velocitySize),\n velocityOpacity: range(raw.velocityOpacity, -1, 1, base.velocityOpacity),\n sizeJitter: unit(raw.sizeJitter, base.sizeJitter),\n angleJitter: unit(raw.angleJitter, base.angleJitter),\n opacityJitter: unit(raw.opacityJitter, base.opacityJitter),\n scatter: range(raw.scatter, 0, 4, base.scatter),\n };\n}\n\nexport const BRUSH_ID = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\nconst HEX = /^#[0-9a-f]{6}$/i;\n\nexport function normalizeMultiColor(raw: Partial<MultiColorSettings> = {}, base: MultiColorSettings = DEFAULT_MULTI_COLOR): MultiColorSettings {\n const colors = Array.isArray(raw.colors) ? raw.colors.filter((c): c is string => typeof c === 'string' && HEX.test(c.trim())).map((c) => c.trim().toLowerCase()).slice(0, 8) : base.colors;\n return {\n mode: MULTI_COLOR_MODES.includes(raw.mode as MultiColorMode) ? (raw.mode as MultiColorMode) : base.mode,\n colors: [...colors],\n order: raw.order === 'random' || raw.order === 'sequence' ? raw.order : base.order,\n length: typeof raw.length === 'number' && Number.isFinite(raw.length) ? Math.min(500, Math.max(1, Math.round(raw.length))) : base.length,\n softness: unit(raw.softness, base.softness),\n };\n}\n\n/** Behaviour input: any subset, with a partial multi-colour block. */\nexport type BrushBehaviorInput = Partial<Omit<BrushBehavior, 'multicolor'>> & { multicolor?: Partial<MultiColorSettings> };\n\nexport function normalizeBehavior(raw: BrushBehaviorInput = {}, base: BrushBehavior = DEFAULT_BEHAVIOR): BrushBehavior {\n return {\n pickup: unit(raw.pickup, base.pickup),\n mix: unit(raw.mix, base.mix),\n dirty: typeof raw.dirty === 'boolean' ? raw.dirty : base.dirty,\n mixing: raw.mixing === 'rgb' || raw.mixing === 'pigment' ? raw.mixing : base.mixing,\n multicolor: normalizeMultiColor(raw.multicolor ?? {}, base.multicolor),\n };\n}\n\n/** Brush settings to change or read: any subset of a brush and of its blocks. */\nexport type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint'>> & {\n /** A gradient (or `null` for the editor's paint); a plain colour source clears it. */\n paint?: PaintSource | null;\n tip?: Partial<BrushSettings>;\n dynamics?: Partial<BrushDynamics>;\n mixer?: Partial<MixerSettings>;\n behavior?: BrushBehaviorInput;\n blender?: Partial<BlenderSettings>;\n smudge?: Partial<SmudgeSettings>;\n wet?: Partial<WetBrushSettings>;\n impasto?: Partial<ImpastoSettings>;\n particle?: Partial<ParticleSettings>;\n bristle?: Partial<BristleSettings>;\n sticker?: Partial<StickerSettings>;\n};\n\n/** Whether a brush can pick paint up from the canvas (the pick-up / mix ratios apply): dab, mixer and wet brushes. */\nexport function isWetCapable(brush: Pick<PaintBrush, 'engine'>): boolean {\n return brush.engine === 'dab' || brush.engine === 'mixer' || brush.engine === 'wet' || brush.engine === 'impasto';\n}\n\n/** Whether a brush paints wet media (on the layer's wet layer). */\nexport function isWetBrush(brush: Pick<PaintBrush, 'engine'>): boolean {\n return brush.engine === 'wet';\n}\n\n/**\n * Whether a dab brush paints dab by dab through the exchange (it picks up paint or paints a\n * gradient) instead of building one coverage buffer of one colour.\n */\nexport function usesPaintExchange(brush: PaintBrush, gradient = brush.paint !== null): boolean {\n return brush.engine === 'dab' && (brush.behavior.pickup > 0 || gradient);\n}\n\n/** Whether strokes of a brush paint colour, so gradient paint applies (not erasers, blenders, smudges or the wet tools other than paint). */\nexport function brushTakesPaint(brush: Pick<PaintBrush, 'engine' | 'loadsColor' | 'wet'>): boolean {\n if (brush.engine === 'eraser' || brush.engine === 'blender' || brush.engine === 'smudge') return false;\n if (brush.engine === 'wet') return brush.wet.tool === 'paint';\n if (brush.engine === 'mixer') return brush.loadsColor;\n return true;\n}\n\n/**\n * The multi-colour settings a gradient paints the same as (the inverse of `multiColorToPaint`), or\n * `null` when the gradient has no multi-colour equivalent. Brushes report it as\n * `behavior.multicolor`, so older readers keep working.\n */\nexport function paintToMultiColor(g: PaintGradientSource | null): MultiColorSettings | null {\n if (!g || g.space === 'oklab' || g.stops.some((s) => s.opacity !== undefined || s.midpoint !== undefined)) return null;\n const colors = g.stops.map((s) => s.color);\n const own = (list: string[]) => (list.length === 2 && list[0] === 'paint' && list[1] === 'secondary' ? [] : list.some((c) => c === 'paint' || c === 'secondary') ? null : list);\n const uniform = (n: number) => g.stops.every((s, k) => s.offset === k / n);\n const softness = g.softness ?? 1;\n if (g.map.by === 'across-tip' && colors.length <= 8 && uniform(colors.length - 1)) {\n const c = own(colors);\n return c ? { mode: 'tip', colors: c, order: 'sequence', length: DEFAULT_MULTI_COLOR.length, softness } : null;\n }\n if (g.map.by === 'random' && colors.length % 2 === 0 && colors.length <= 16) {\n const n = colors.length / 2;\n const pairs = Array.from({ length: n }, (_, k) => colors[2 * k]);\n const hard = g.stops.every((s, i) => s.offset === (Math.floor(i / 2) + (i % 2)) / n && s.color === pairs[Math.floor(i / 2)]);\n const c = hard ? own(pairs) : null;\n return c ? { mode: 'dab', colors: c, order: 'random', length: g.map.every ?? 1, softness } : null;\n }\n if (g.map.by === 'distance' && g.map.unit === 'dabs' && g.map.repeat === 'repeat' && colors.length >= 3 && colors.length <= 9 && colors[0] === colors[colors.length - 1] && uniform(colors.length - 1)) {\n const n = colors.length - 1;\n const c = own(colors.slice(0, n));\n const length = g.map.length / n;\n return c && Number.isInteger(length) ? { mode: 'dab', colors: c, order: 'sequence', length, softness } : null;\n }\n return null;\n}\n\n/**\n * The gradient paint a multi-coloured brush (`behavior.multicolor`, before gradient paint) paints\n * the same pixels with: `tip` → `across-tip`; `dab` in sequence → `distance` in dabs, repeating\n * through the colours and back to the first; `dab` at random → `random` per run of dabs, with hard\n * stops. Without 2 colours of its own it uses the editor's paint and second colours.\n */\nexport function multiColorToPaint(mc: MultiColorSettings, mixing: MixingModel): PaintGradientSource | null {\n if (mc.mode === 'off') return null;\n const colors = mc.colors.length >= 2 ? mc.colors : ['paint', 'secondary'];\n const n = colors.length;\n const space = mixing === 'rgb' ? 'srgb' : 'pigment';\n const soft = mc.softness < 1 ? { softness: mc.softness } : {};\n if (mc.mode === 'tip') return { type: 'gradient', stops: colors.map((color, k) => ({ offset: k / (n - 1), color })), space, map: { by: 'across-tip' }, ...soft };\n if (mc.order === 'random') {\n const stops = colors.flatMap((color, k) => [\n { offset: k / n, color },\n { offset: (k + 1) / n, color },\n ]);\n return { type: 'gradient', stops, space, map: { by: 'random', every: mc.length } };\n }\n return { type: 'gradient', stops: [...colors, colors[0]].map((color, k) => ({ offset: k / n, color })), space, map: { by: 'distance', length: mc.length * n, repeat: 'repeat', unit: 'dabs' }, ...soft };\n}\n\n/** A brush with every field in range; missing fields come from `base` (default: a plain round dab brush). */\nexport function normalizePaintBrush(raw: PaintBrushInput = {}, base?: PaintBrush): PaintBrush {\n const b = base ?? BASE_BRUSH;\n const id = typeof raw.id === 'string' && BRUSH_ID.test(raw.id) ? raw.id : b.id;\n const engine = PAINT_BRUSH_ENGINES.includes(raw.engine as PaintBrushEngine) ? (raw.engine as PaintBrushEngine) : b.engine;\n // A Mixer Brush's pick-up / mix ratios, dirtiness and mixing are its mixer settings: behaviour\n // changes are written into the mixer, then the behaviour is read back from it.\n const rb = raw.behavior ?? {};\n const mixerIn: Partial<MixerSettings> = { ...b.mixer, ...(raw.mixer ?? {}) };\n if (engine === 'mixer') {\n if (rb.pickup !== undefined) mixerIn.wet = rb.pickup;\n if (rb.mix !== undefined) mixerIn.mix = rb.mix;\n if (rb.dirty !== undefined) mixerIn.cleanEachStroke = !rb.dirty;\n if (rb.mixing !== undefined) mixerIn.mixing = rb.mixing;\n }\n const mixer = normalizeMixer(mixerIn);\n let behavior = normalizeBehavior(rb, b.behavior);\n if (engine === 'mixer') behavior = { ...behavior, pickup: mixer.wet, mix: mixer.mix, dirty: !mixer.cleanEachStroke, mixing: mixer.mixing };\n // Gradient paint: given (a plain colour or null clears it), or the multi-colour settings of\n // older brushes and tools, merged into what the brush's gradient amounts to.\n let paint: PaintGradientSource | null = b.paint ?? null;\n if (raw.paint !== undefined) {\n const p = readPaintSource(raw.paint);\n paint = p && p.type === 'gradient' ? p : null;\n } else if (rb.multicolor !== undefined) {\n const mc = normalizeMultiColor(rb.multicolor, paintToMultiColor(paint) ?? DEFAULT_MULTI_COLOR);\n paint = mc.mode === 'off' ? (paintToMultiColor(paint) ? null : paint) : multiColorToPaint(mc, behavior.mixing);\n }\n // `behavior.multicolor` is a read-only view of the gradient, for older readers.\n behavior = { ...behavior, multicolor: paintToMultiColor(paint) ?? { ...DEFAULT_MULTI_COLOR, colors: [] } };\n return {\n id,\n name: typeof raw.name === 'string' && raw.name.trim() ? raw.name.trim().slice(0, 80) : b.name,\n category: PAINT_BRUSH_CATEGORIES.includes(raw.category as PaintBrushCategory) ? (raw.category as PaintBrushCategory) : b.category,\n engine,\n tip: normalizeBrush({ ...b.tip, ...(raw.tip ?? {}) }),\n grain: unit(raw.grain, b.grain),\n pressureSmoothing: range(raw.pressureSmoothing, 0, 0.95, b.pressureSmoothing),\n rotation: BRUSH_ROTATIONS.includes(raw.rotation as BrushRotation) ? (raw.rotation as BrushRotation) : b.rotation,\n dynamics: normalizeDynamics(raw.dynamics ?? {}, b.dynamics),\n mixer,\n loadsColor: typeof raw.loadsColor === 'boolean' ? raw.loadsColor : b.loadsColor,\n behavior,\n blender: normalizeBlender(raw.blender ?? {}, b.blender),\n smudge: normalizeSmudge(raw.smudge ?? {}, b.smudge),\n wet: normalizeWetBrush(raw.wet ?? {}, b.wet ?? DEFAULT_WET_BRUSH),\n impasto: normalizeImpasto(raw.impasto ?? {}, b.impasto ?? DEFAULT_IMPASTO),\n particle: normalizeParticle(raw.particle ?? {}, b.particle ?? DEFAULT_PARTICLE),\n bristle: normalizeBristle(raw.bristle ?? {}, b.bristle ?? DEFAULT_BRISTLE),\n sticker: normalizeStickerSettings(raw.sticker ?? {}, b.sticker ?? DEFAULT_STICKER),\n paint,\n ...(raw.builtin ? { builtin: true } : {}),\n };\n}\n\nconst BASE_BRUSH: PaintBrush = {\n id: 'round',\n name: 'Round',\n category: 'custom',\n engine: 'dab',\n tip: { ...DEFAULT_BRUSH },\n grain: 0,\n pressureSmoothing: 0,\n rotation: 'fixed',\n dynamics: { ...DEFAULT_DYNAMICS },\n mixer: { ...DEFAULT_MIXER },\n loadsColor: true,\n behavior: { ...DEFAULT_BEHAVIOR, multicolor: { ...DEFAULT_MULTI_COLOR, colors: [] } },\n blender: { ...DEFAULT_BLENDER },\n smudge: { ...DEFAULT_SMUDGE },\n wet: { ...DEFAULT_WET_BRUSH },\n impasto: { ...DEFAULT_IMPASTO },\n particle: { ...DEFAULT_PARTICLE },\n bristle: { ...DEFAULT_BRISTLE },\n sticker: { ...DEFAULT_STICKER, stamps: [...DEFAULT_STICKER.stamps] },\n paint: null,\n};\n\ntype BrushInit = PaintBrushInput & { id: string; name: string; category: PaintBrushCategory };\n\nconst builtin = (init: BrushInit): PaintBrush => ({ ...normalizePaintBrush(init), builtin: true });\n\n/** The built-in brush library. */\nexport const BUILTIN_BRUSHES: readonly PaintBrush[] = [\n builtin({\n id: 'pencil-hb', name: 'HB pencil', category: 'pencil',\n tip: { size: 4, hardness: 0.7, spacing: 0.08, opacity: 0.85, flow: 0.55, smoothing: 0.25, pressureSize: true, pressureOpacity: true },\n grain: 0.85, pressureSmoothing: 0.3,\n dynamics: { minSize: 0.55, tiltSize: 0.9, tiltRoundness: 0.7, tiltOpacity: 0.5 },\n }),\n builtin({\n id: 'pencil-6b', name: '6B pencil', category: 'pencil',\n tip: { size: 7, hardness: 0.55, spacing: 0.07, opacity: 1, flow: 0.75, smoothing: 0.2, pressureSize: true, pressureOpacity: true },\n grain: 0.7, pressureSmoothing: 0.3,\n dynamics: { minSize: 0.5, tiltSize: 1, tiltRoundness: 0.75, tiltOpacity: 0.35 },\n }),\n builtin({\n id: 'soft-pastel', name: 'Soft pastel', category: 'pastel', rotation: 'stroke',\n tip: { size: 32, hardness: 0.55, spacing: 0.05, angle: 90, roundness: 0.55, opacity: 1, flow: 0.7, smoothing: 0.15, pressureSize: false, pressureOpacity: true },\n grain: 1, pressureSmoothing: 0.25,\n dynamics: { sizeJitter: 0.06, angleJitter: 0.02 },\n }),\n builtin({\n id: 'oil-pastel', name: 'Oil pastel', category: 'pastel', rotation: 'stroke',\n tip: { size: 26, hardness: 0.8, spacing: 0.05, angle: 90, roundness: 0.7, opacity: 1, flow: 0.9, smoothing: 0.15, pressureSize: true, pressureOpacity: false, blend: 'pigment' },\n grain: 0.5, pressureSmoothing: 0.25,\n dynamics: { minSize: 0.6 },\n }),\n builtin({\n id: 'charcoal-stick', name: 'Charcoal stick', category: 'charcoal', rotation: 'stroke',\n tip: { size: 26, hardness: 0.4, spacing: 0.05, angle: 90, roundness: 0.35, opacity: 0.95, flow: 0.5, smoothing: 0.15, pressureSize: false, pressureOpacity: true },\n grain: 0.95, pressureSmoothing: 0.2,\n dynamics: { sizeJitter: 0.1, angleJitter: 0.03, tiltSize: 0.6 },\n }),\n builtin({\n id: 'vine-charcoal', name: 'Vine charcoal', category: 'charcoal',\n tip: { size: 10, hardness: 0.3, spacing: 0.06, opacity: 0.75, flow: 0.45, smoothing: 0.2, pressureSize: true, pressureOpacity: true },\n grain: 0.9, pressureSmoothing: 0.2,\n dynamics: { minSize: 0.4, tiltSize: 0.8, tiltRoundness: 0.5, tiltOpacity: 0.3, sizeJitter: 0.08 },\n }),\n builtin({\n id: 'airbrush', name: 'Airbrush', category: 'airbrush',\n tip: { size: 90, hardness: 0, spacing: 0.04, opacity: 1, flow: 0.06, smoothing: 0.3, pressureSize: false, pressureOpacity: false },\n grain: 0, pressureSmoothing: 0.3,\n dynamics: { pressureFlow: 1, tiltSize: 0.5, tiltRoundness: 0.6 },\n }),\n builtin({\n id: 'marker', name: 'Chisel marker', category: 'marker',\n tip: { size: 24, hardness: 0.85, spacing: 0.04, angle: 45, roundness: 0.35, opacity: 0.6, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: false, blend: 'multiply' },\n grain: 0.1,\n }),\n builtin({\n id: 'ink-pen', name: 'Ink pen', category: 'ink',\n tip: { size: 4, hardness: 1, spacing: 0.05, opacity: 1, flow: 1, smoothing: 0.5, pressureSize: true, pressureOpacity: false },\n pressureSmoothing: 0.4,\n dynamics: { minSize: 0.25, velocitySize: -0.45 },\n }),\n builtin({\n id: 'brush-pen', name: 'Brush pen', category: 'ink', rotation: 'stroke',\n tip: { size: 14, hardness: 0.9, spacing: 0.04, roundness: 0.8, opacity: 1, flow: 1, smoothing: 0.5, pressureSize: true, pressureOpacity: false },\n pressureSmoothing: 0.45,\n dynamics: { minSize: 0.05, velocitySize: -0.3 },\n }),\n builtin({\n id: 'eraser-soft', name: 'Soft eraser', category: 'eraser', engine: 'eraser',\n tip: { size: 40, hardness: 0.2, spacing: 0.08, opacity: 1, flow: 0.6, pressureSize: false, pressureOpacity: true },\n }),\n builtin({\n id: 'eraser-hard', name: 'Hard eraser', category: 'eraser', engine: 'eraser',\n tip: { size: 16, hardness: 0.9, spacing: 0.06, opacity: 1, flow: 1, pressureSize: true, pressureOpacity: false },\n grain: 0.3,\n dynamics: { minSize: 0.5 },\n }),\n builtin({\n id: 'blender', name: 'Blender', category: 'blender', engine: 'blender', loadsColor: false,\n tip: { size: 34, hardness: 0.4, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: false, pressureOpacity: true },\n blender: { strength: 0.5, distance: 0.35, mixing: 'pigment' },\n }),\n builtin({\n id: 'smudge', name: 'Smudge', category: 'smudge', engine: 'smudge', loadsColor: false,\n tip: { size: 26, hardness: 0.6, spacing: 0.06, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: false, pressureOpacity: true },\n smudge: { strength: 0.75, length: 0.85, mixing: 'rgb' },\n }),\n builtin({\n id: 'wet-smudge', name: 'Pigment smudge', category: 'smudge', engine: 'smudge', loadsColor: false,\n tip: { size: 30, hardness: 0.5, spacing: 0.06, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: true, pressureOpacity: true },\n smudge: { strength: 0.7, length: 0.9, mixing: 'pigment' },\n dynamics: { minSize: 0.6 },\n }),\n builtin({\n id: 'dirty-round', name: 'Dirty round', category: 'paint',\n tip: { size: 22, hardness: 0.65, spacing: 0.06, opacity: 1, flow: 0.7, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n behavior: { pickup: 0.55, mix: 0.6, dirty: true, mixing: 'pigment' },\n dynamics: { minSize: 0.5 },\n }),\n builtin({\n id: 'multicolor-flat', name: 'Multi-colour flat', category: 'paint', rotation: 'stroke',\n tip: { size: 30, hardness: 0.75, spacing: 0.05, angle: 90, roundness: 0.3, opacity: 1, flow: 0.85, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n behavior: { pickup: 0.15, mix: 0.4, mixing: 'pigment' },\n // The paint and second colours side by side across the tip.\n paint: { type: 'gradient', stops: [{ offset: 0, color: 'paint' }, { offset: 1, color: 'secondary' }], space: 'pigment', map: { by: 'across-tip' }, softness: 0.7 },\n dynamics: { minSize: 0.6 },\n }),\n builtin({\n id: 'palette-dabber', name: 'Palette dabber', category: 'paint',\n tip: { size: 18, hardness: 0.7, spacing: 0.35, opacity: 1, flow: 0.9, smoothing: 0.1, pressureSize: true, pressureOpacity: false },\n // From the paint colour to the second colour and back, every 6 dabs.\n paint: { type: 'gradient', stops: [{ offset: 0, color: 'paint' }, { offset: 0.5, color: 'secondary' }, { offset: 1, color: 'paint' }], space: 'pigment', map: { by: 'distance', length: 12, repeat: 'repeat', unit: 'dabs' }, softness: 0.4 },\n dynamics: { minSize: 0.5, sizeJitter: 0.15, scatter: 0.3 },\n }),\n builtin({\n id: 'gradient-round', name: 'Gradient round', category: 'paint',\n tip: { size: 24, hardness: 0.8, spacing: 0.05, opacity: 1, flow: 0.9, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n // Changes colour as it is dragged out: paint → second colour over 300 px, and back.\n paint: { type: 'gradient', stops: [{ offset: 0, color: 'paint' }, { offset: 1, color: 'secondary' }], space: 'pigment', map: { by: 'distance', length: 300, repeat: 'mirror' } },\n dynamics: { minSize: 0.5 },\n }),\n builtin({\n id: 'pressure-ombre', name: 'Pressure ombré', category: 'paint',\n tip: { size: 26, hardness: 0.6, spacing: 0.05, opacity: 1, flow: 0.8, smoothing: 0.2, pressureSize: false, pressureOpacity: false },\n // Light pressure lays the second colour, full pressure the paint colour.\n paint: { type: 'gradient', stops: [{ offset: 0, color: 'secondary' }, { offset: 1, color: 'paint' }], space: 'pigment', map: { by: 'pressure' } },\n }),\n builtin({\n id: 'rainbow-marker', name: 'Rainbow marker', category: 'marker', rotation: 'stroke',\n tip: { size: 18, hardness: 0.9, spacing: 0.04, angle: 90, roundness: 0.4, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: false, pressureOpacity: false },\n paint: {\n type: 'gradient',\n stops: [\n { offset: 0, color: '#e11d48' },\n { offset: 0.2, color: '#f59e0b' },\n { offset: 0.4, color: '#facc15' },\n { offset: 0.6, color: '#22c55e' },\n { offset: 0.8, color: '#3b82f6' },\n { offset: 1, color: '#8b5cf6' },\n ],\n space: 'oklab',\n map: { by: 'distance', length: 600, repeat: 'repeat' },\n },\n }),\n builtin({\n id: 'mixer-brush', name: 'Mixer Brush', category: 'mixer', engine: 'mixer',\n tip: { size: 30, hardness: 0.7, spacing: 0.1, opacity: 1, flow: 0.5, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n mixer: { wet: 0.5, load: 0.95, mix: 0.5, loadEachStroke: true, cleanEachStroke: true, mixing: 'pigment' },\n dynamics: { minSize: 0.5 },\n }),\n builtin({\n id: 'watercolor-round', name: 'Watercolour round', category: 'watercolor', engine: 'wet',\n tip: { size: 28, hardness: 0.6, spacing: 0.12, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: true },\n dynamics: { minSize: 0.35 },\n behavior: { pickup: 0.3, mix: 0.4, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.55, pigment: 0.5, body: 0 },\n }),\n builtin({\n id: 'watercolor-wash', name: 'Wash brush', category: 'watercolor', engine: 'wet', rotation: 'stroke',\n tip: { size: 90, hardness: 0.35, spacing: 0.1, angle: 90, roundness: 0.45, opacity: 1, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: true },\n behavior: { pickup: 0.2, mix: 0.3, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.8, pigment: 0.45, body: 0 },\n }),\n builtin({\n id: 'gradient-wash', name: 'Gradient wash', category: 'watercolor', engine: 'wet', rotation: 'stroke',\n tip: { size: 80, hardness: 0.35, spacing: 0.1, angle: 90, roundness: 0.5, opacity: 1, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: true },\n behavior: { pickup: 0.2, mix: 0.3, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.8, pigment: 0.45, body: 0 },\n // A graded wash: the paint colour runs into the second colour as the brush travels.\n paint: { type: 'gradient', stops: [{ offset: 0, color: 'paint' }, { offset: 1, color: 'secondary' }], space: 'pigment', map: { by: 'distance', length: 500, repeat: 'mirror' } },\n }),\n builtin({\n id: 'watercolor-detail', name: 'Watercolour rigger', category: 'watercolor', engine: 'wet',\n tip: { size: 7, hardness: 0.75, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.4, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.2 },\n wet: { tool: 'paint', water: 0.4, pigment: 0.7, body: 0 },\n }),\n builtin({\n id: 'gouache', name: 'Gouache', category: 'watercolor', engine: 'wet',\n tip: { size: 26, hardness: 0.7, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n behavior: { pickup: 0.35, mix: 0.5, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.35, pigment: 0.8, body: 1, medium: 'gouache' },\n }),\n builtin({\n id: 'oil-round', name: 'Wet oil round', category: 'oil', engine: 'wet',\n tip: { size: 24, hardness: 0.75, spacing: 0.08, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n behavior: { pickup: 0.6, mix: 0.55, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.4, pigment: 0.9, body: 1, medium: 'oil', load: 0.97 },\n }),\n builtin({\n id: 'oil-flat', name: 'Wet oil flat', category: 'oil', engine: 'wet', rotation: 'stroke',\n tip: { size: 40, hardness: 0.85, spacing: 0.06, angle: 90, roundness: 0.35, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.6 },\n behavior: { pickup: 0.65, mix: 0.6, mixing: 'pigment' },\n wet: { tool: 'paint', water: 0.45, pigment: 0.9, body: 1, medium: 'oil', load: 0.95 },\n }),\n builtin({\n id: 'impasto-brush', name: 'Impasto brush', category: 'impasto', engine: 'impasto', rotation: 'stroke',\n tip: { size: 36, hardness: 0.8, spacing: 0.06, angle: 90, roundness: 0.55, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.55 },\n behavior: { pickup: 0.4, mix: 0.5, mixing: 'pigment' },\n impasto: { tool: 'brush', thickness: 0.6, gloss: 0.45, load: 0.92, drag: 0.4 },\n }),\n builtin({\n id: 'paint-tube', name: 'Paint tube', category: 'impasto', engine: 'impasto',\n tip: { size: 22, hardness: 0.9, spacing: 0.05, opacity: 1, flow: 1, smoothing: 0.35, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.4 },\n impasto: { tool: 'tube', thickness: 0.9, gloss: 0.5, load: 1, drag: 0.1 },\n }),\n builtin({\n id: 'palette-knife', name: 'Palette knife', category: 'impasto', engine: 'impasto', rotation: 'stroke',\n tip: { size: 48, hardness: 1, spacing: 0.05, angle: 90, roundness: 0.18, opacity: 1, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: false },\n impasto: { tool: 'knife', thickness: 0.3, gloss: 0.55, load: 1, drag: 0.85 },\n }),\n builtin({\n id: 'paint-roller', name: 'Roller', category: 'impasto', engine: 'impasto', rotation: 'stroke',\n tip: { size: 70, hardness: 0.95, spacing: 0.04, angle: 90, roundness: 0.12, opacity: 1, flow: 1, smoothing: 0.4, pressureSize: false, pressureOpacity: false },\n impasto: { tool: 'roller', thickness: 0.25, gloss: 0.3, load: 0.9, drag: 0.15 },\n }),\n builtin({\n id: 'gloop-pen', name: 'Gloop pen', category: 'impasto', engine: 'impasto',\n tip: { size: 14, hardness: 0.9, spacing: 0.05, opacity: 1, flow: 1, smoothing: 0.5, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n impasto: { tool: 'gloop', thickness: 1, gloss: 0.9, load: 1, drag: 0 },\n }),\n builtin({\n id: 'metallic-paint', name: 'Metallic paint', category: 'impasto', engine: 'impasto', rotation: 'stroke',\n tip: { size: 30, hardness: 0.8, spacing: 0.06, angle: 90, roundness: 0.6, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n behavior: { pickup: 0.2, mix: 0.4, mixing: 'pigment' },\n impasto: { tool: 'brush', thickness: 0.45, gloss: 0.8, metallic: 1, load: 0.95, drag: 0.3 },\n }),\n builtin({\n id: 'hair-strands', name: 'Hair strands', category: 'procedural', engine: 'particle',\n tip: { size: 40, hardness: 0.8, opacity: 0.9, flow: 0.6, smoothing: 0.2, pressureSize: true, pressureOpacity: true },\n particle: { kind: 'string', render: 'line', count: 22, size: 0.025, spread: 1, stiffness: 0.08, damping: 0.3 },\n }),\n builtin({\n id: 'spring-ink', name: 'Spring ink', category: 'procedural', engine: 'particle',\n tip: { size: 30, hardness: 0.9, opacity: 1, flow: 0.8, smoothing: 0.1, pressureSize: true, pressureOpacity: false },\n particle: { kind: 'spring', render: 'line', count: 5, size: 0.08, spread: 0.6, stiffness: 0.2, damping: 0.1 },\n }),\n builtin({\n id: 'orbit-curls', name: 'Orbit curls', category: 'procedural', engine: 'particle',\n tip: { size: 36, hardness: 0.85, opacity: 0.9, flow: 0.7, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n particle: { kind: 'orbit', render: 'line', count: 4, size: 0.05, spread: 0.6, speed: 0.45 },\n }),\n builtin({\n id: 'flow-fur', name: 'Flow fur', category: 'procedural', engine: 'particle',\n tip: { size: 50, hardness: 0.7, opacity: 0.8, flow: 0.5, smoothing: 0.2, pressureSize: true, pressureOpacity: true },\n particle: { kind: 'flow', render: 'line', count: 10, size: 0.03, spread: 0.6, speed: 0.5, life: 0.25 },\n }),\n builtin({\n id: 'bead-trail', name: 'Bead trail', category: 'procedural', engine: 'particle',\n tip: { size: 34, hardness: 0.9, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n particle: { kind: 'spring', render: 'sequence', count: 3, size: 0.18, spread: 0.5, stiffness: 0.3, damping: 0.3, interval: 0.4 },\n }),\n builtin({\n id: 'sparkle-dust', name: 'Sparkle dust', category: 'procedural', engine: 'particle',\n tip: { size: 60, hardness: 0.6, opacity: 1, flow: 0.9, smoothing: 0.1, pressureSize: true, pressureOpacity: true },\n particle: { kind: 'flow', render: 'dot', count: 6, size: 0.05, spread: 0.9, speed: 0.7, life: 0.4 },\n }),\n builtin({\n id: 'bristle-round', name: 'Bristle round', category: 'bristle', engine: 'bristle', rotation: 'stroke',\n tip: { size: 30, hardness: 0.85, opacity: 1, flow: 0.9, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.4, tiltSize: 0.6, tiltRoundness: 0.6 },\n bristle: { count: 28, stiffness: 0.45, splay: 0.6, thickness: 0.035, load: 0.7, jitter: 0.5 },\n }),\n builtin({\n id: 'bristle-flat', name: 'Bristle flat', category: 'bristle', engine: 'bristle', rotation: 'stroke',\n tip: { size: 46, hardness: 0.85, angle: 90, roundness: 0.3, opacity: 1, flow: 0.9, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5, tiltSize: 0.5 },\n bristle: { count: 40, stiffness: 0.6, splay: 0.4, thickness: 0.025, load: 0.65, jitter: 0.45 },\n }),\n builtin({\n id: 'dry-brush', name: 'Dry brush', category: 'bristle', engine: 'bristle', rotation: 'stroke',\n tip: { size: 44, hardness: 0.9, angle: 90, roundness: 0.45, opacity: 1, flow: 0.8, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n grain: 0.6,\n bristle: { count: 48, stiffness: 0.35, splay: 0.7, thickness: 0.05, load: 0.15, jitter: 0.8 },\n }),\n builtin({\n id: 'sticker-stars', name: 'Star stickers', category: 'sticker', engine: 'sticker',\n tip: { size: 36, opacity: 1, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n sticker: { stamps: ['star', 'sparkle'], density: 0.35, sizeJitter: 0.5, rotationJitter: 1, scatter: 0.6, colorJitter: 0.3 },\n }),\n builtin({\n id: 'sticker-leaves', name: 'Leaf stickers', category: 'sticker', engine: 'sticker', rotation: 'stroke',\n tip: { size: 40, opacity: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },\n dynamics: { minSize: 0.5 },\n sticker: { stamps: ['leaf'], density: 0.5, sizeJitter: 0.4, rotationJitter: 0.35, scatter: 0.4, colorJitter: 0.35 },\n }),\n builtin({\n id: 'sticker-confetti', name: 'Confetti', category: 'sticker', engine: 'sticker',\n tip: { size: 22, opacity: 1, smoothing: 0.1, pressureSize: false, pressureOpacity: false },\n sticker: { stamps: ['confetti', 'dot', 'ring'], density: 0.7, sizeJitter: 0.5, rotationJitter: 1, scatter: 1.5, colorJitter: 1 },\n }),\n builtin({\n id: 'sticker-flowers', name: 'Flower stickers', category: 'sticker', engine: 'sticker',\n tip: { size: 44, opacity: 1, smoothing: 0.2, pressureSize: true, pressureOpacity: false },\n sticker: { stamps: ['flower', 'heart'], density: 0.3, sizeJitter: 0.5, rotationJitter: 1, scatter: 0.7, colorJitter: 0.4 },\n }),\n builtin({\n id: 'sticker-splats', name: 'Paint splats', category: 'sticker', engine: 'sticker',\n tip: { size: 50, opacity: 0.95, smoothing: 0.1, pressureSize: true, pressureOpacity: false },\n sticker: { stamps: ['splat'], density: 0.25, sizeJitter: 0.6, rotationJitter: 1, scatter: 0.8, colorJitter: 0.15 },\n }),\n builtin({\n id: 'add-water', name: 'Add water', category: 'wet-tool', engine: 'wet',\n tip: { size: 40, hardness: 0.4, spacing: 0.12, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: true },\n dynamics: { minSize: 0.5 },\n wet: { tool: 'water', water: 0.6, pigment: 0, rewet: 0.3 },\n }),\n builtin({\n id: 'hair-dryer', name: 'Dry', category: 'wet-tool', engine: 'wet',\n tip: { size: 80, hardness: 0.1, spacing: 0.15, opacity: 1, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: true },\n wet: { tool: 'dry', strength: 0.5 },\n }),\n builtin({\n id: 'blow', name: 'Blow', category: 'wet-tool', engine: 'wet',\n tip: { size: 50, hardness: 0.2, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.3, pressureSize: false, pressureOpacity: true },\n wet: { tool: 'blow', strength: 0.6 },\n }),\n builtin({\n id: 'wet-blend', name: 'Wet blend', category: 'wet-tool', engine: 'wet',\n tip: { size: 36, hardness: 0.3, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: false, pressureOpacity: true },\n wet: { tool: 'blend', strength: 0.4 },\n }),\n builtin({\n id: 'wet-drag', name: 'Wet smudge', category: 'wet-tool', engine: 'wet',\n tip: { size: 30, hardness: 0.5, spacing: 0.08, opacity: 1, flow: 1, smoothing: 0.25, pressureSize: false, pressureOpacity: true },\n wet: { tool: 'smudge', strength: 0.6 },\n }),\n builtin({\n id: 'blot', name: 'Blot (erase wet)', category: 'wet-tool', engine: 'wet',\n tip: { size: 40, hardness: 0.5, spacing: 0.12, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: false, pressureOpacity: true },\n wet: { tool: 'blot', strength: 0.7 },\n }),\n];\n\nexport const DEFAULT_BRUSH_ID = 'pencil-6b';\n\nexport { MAX_BRUSH_SIZE };\n\n/** A brush as plain JSON (for export, agents and saved libraries): no `builtin` flag. */\nexport function brushToJSON(brush: PaintBrush): Omit<PaintBrush, 'builtin'> {\n const { builtin: _b, ...rest } = brush;\n return JSON.parse(JSON.stringify(rest));\n}\n\n/** The JSON file a brush library exports to and imports from. */\nexport interface BrushLibraryFile {\n format: 'pixerate-brushes';\n version: 1;\n brushes: Array<Omit<PaintBrush, 'builtin'>>;\n}\n\n/**\n * Brushes read from a brush library file (or a bare array of brushes). Each is normalised; ones\n * without a valid id or name are reported in `problems` and skipped.\n */\nexport function parseBrushLibrary(raw: unknown, problems: string[] = []): PaintBrush[] {\n const list = Array.isArray(raw) ? raw : raw && typeof raw === 'object' && Array.isArray((raw as BrushLibraryFile).brushes) ? (raw as BrushLibraryFile).brushes : null;\n if (!list) throw new Error('Not a brush library: expected {\"format\":\"pixerate-brushes\",\"version\":1,\"brushes\":[...]} or an array of brushes.');\n const out: PaintBrush[] = [];\n list.forEach((item, i) => {\n if (!item || typeof item !== 'object') {\n problems.push(`brushes[${i}] is not an object; skipped.`);\n return;\n }\n const r = item as Record<string, unknown>;\n if (typeof r.id !== 'string' || !BRUSH_ID.test(r.id)) {\n problems.push(`brushes[${i}] has no valid id (lowercase letters, digits and dashes); skipped.`);\n return;\n }\n if (typeof r.name !== 'string' || !r.name.trim()) {\n problems.push(`brushes[${i}] (\"${r.id}\") has no name; skipped.`);\n return;\n }\n const { builtin: _b, ...rest } = r;\n out.push(normalizePaintBrush(rest as PaintBrushInput));\n });\n return out;\n}\n"],"mappings":"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","names":["unit","unit","a","b","_","unit","HEX"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-KEENUAFN.cjs","../src/canvas/brushstroke.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-KEENUAFN.cjs","sourcesContent":[null,"/**\n * Brushed freehand strokes: a path shape with a `brush` keeps its path (selection, editing, eraser\n * hit-testing, grouping and export work as for any path) and is drawn with the paint engine's\n * dry brushstroke renderer instead of an SVG stroke. The renderer, the paint presets and the colour\n * parser live in a separate chunk, loaded the first time a brushed stroke is drawn, so canvases\n * without brushes never load the paint engine.\n */\nimport { brushstrokeScaleBucket } from '../paint/brushstroke-scale.js';\nimport { parseSvgPath, type PathShape, type ShapeDescription, type ShapeSize } from './shapeGeometry.js';\nimport type { Point } from './types.js';\nimport type { CanvasBrush, CanvasBrushPaint, CanvasBrushPreset, CanvasBrushstroke } from './brushTypes.js';\n\nexport type { CanvasBrush, CanvasBrushPaint, CanvasBrushPaintMapping, CanvasBrushPaintStop, CanvasBrushPreset, CanvasBrushSettings, CanvasBrushstroke } from './brushTypes.js';\n\nexport { brushstrokeScaleBucket };\n\n/** A brushed stroke's image, placed in the path's coordinates (the shape's view box). */\nexport interface CanvasBrushstrokeImage {\n\t/** PNG data URL. */\n\thref: string;\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\t/** Image pixels per path unit. */\n\tscale: number;\n}\n\n/** A path shape with a brush. */\nexport type BrushedPathShape = PathShape & { brush: CanvasBrushstroke };\n\n/** Whether a shape is a brushed stroke. */\nexport function isBrushedShape(shape: ShapeDescription | null | undefined): shape is BrushedPathShape {\n\treturn !!shape && shape.kind === 'path' && !!shape.brush && typeof shape.brush === 'object' && shape.brush.brush != null;\n}\n\n/**\n * The open polyline of a path's first subpath, in path coordinates: lines kept, curves sampled\n * every `step` units or so. Brushed strokes are drawn along it.\n */\nexport function pathDataToPolyline(d: string, step = 2): Point[] {\n\tconst out: Point[] = [];\n\tlet x = 0;\n\tlet y = 0;\n\tlet started = false;\n\tconst push = (px: number, py: number) => {\n\t\tconst last = out[out.length - 1];\n\t\tif (!last || last[0] !== px || last[1] !== py) out.push([px, py]);\n\t};\n\tfor (const c of parseSvgPath(d)) {\n\t\tif (c.type === 'M') {\n\t\t\tif (started) break;\n\t\t\tstarted = true;\n\t\t\tx = c.x;\n\t\t\ty = c.y;\n\t\t\tpush(x, y);\n\t\t} else if (c.type === 'Z') {\n\t\t\tif (out.length) push(out[0][0], out[0][1]);\n\t\t\tbreak;\n\t\t} else if (c.type === 'C' || c.type === 'Q') {\n\t\t\tconst pts = c.type === 'C' ? [[x, y], [c.x1, c.y1], [c.x2, c.y2], [c.x, c.y]] : [[x, y], [c.x1, c.y1], [c.x, c.y]];\n\t\t\tlet hull = 0;\n\t\t\tfor (let i = 1; i < pts.length; i++) hull += Math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1]);\n\t\t\tconst n = Math.max(1, Math.min(256, Math.ceil(hull / Math.max(0.25, step))));\n\t\t\tfor (let k = 1; k <= n; k++) {\n\t\t\t\tconst t = k / n;\n\t\t\t\tconst u = 1 - t;\n\t\t\t\tif (c.type === 'C') {\n\t\t\t\t\tpush(\n\t\t\t\t\t\tu * u * u * x + 3 * u * u * t * c.x1 + 3 * u * t * t * c.x2 + t * t * t * c.x,\n\t\t\t\t\t\tu * u * u * y + 3 * u * u * t * c.y1 + 3 * u * t * t * c.y2 + t * t * t * c.y\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tpush(u * u * x + 2 * u * t * c.x1 + t * t * c.x, u * u * y + 2 * u * t * c.y1 + t * t * c.y);\n\t\t\t\t}\n\t\t\t}\n\t\t\tx = c.x;\n\t\t\ty = c.y;\n\t\t} else {\n\t\t\t// Lines, and arcs as their chords (freehand paths have none).\n\t\t\tx = c.x;\n\t\t\ty = c.y;\n\t\t\tpush(x, y);\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * Resamples per-point values into `count` values spread evenly along the polyline's length (the\n * profile a brushed stroke stores). Values are rounded to three decimals.\n */\nexport function profileAlongPolyline(points: readonly Point[], values: readonly number[], count = 32): number[] {\n\tconst n = Math.min(points.length, values.length);\n\tif (n === 0) return [];\n\tif (n === 1) return [round3(values[0])];\n\tconst lengths = [0];\n\tfor (let i = 1; i < n; i++) lengths.push(lengths[i - 1] + Math.hypot(points[i][0] - points[i - 1][0], points[i][1] - points[i - 1][1]));\n\tconst total = lengths[n - 1];\n\tconst m = Math.max(2, Math.min(count, n));\n\tconst out: number[] = [];\n\tlet j = 0;\n\tfor (let k = 0; k < m; k++) {\n\t\tconst at = total > 0 ? (total * k) / (m - 1) : 0;\n\t\twhile (j < n - 2 && lengths[j + 1] < at) j++;\n\t\tconst span = lengths[j + 1] - lengths[j];\n\t\tconst f = span > 0 ? Math.min(1, Math.max(0, (at - lengths[j]) / span)) : 0;\n\t\tout.push(round3(values[j] + (values[j + 1] - values[j]) * f));\n\t}\n\treturn out;\n}\n\nconst round3 = (v: number) => Math.round(v * 1000) / 1000;\n\n// ---------------------------------------------------------------------------\n// The lazily loaded renderer\n// ---------------------------------------------------------------------------\n\n/** The renderer chunk (`./brushstrokeRender.ts`). */\nexport interface CanvasBrushstrokeRenderer {\n\tlistCanvasBrushes(): CanvasBrushPreset[];\n\t/** Throws for an unknown or non-dry brush; the result is the paint engine's brush. */\n\tresolveCanvasBrush(brush: CanvasBrush, width: number): unknown;\n\t/** Throws for paint that is not a colour or gradient paint a canvas stroke can use; the result is the paint engine's `PaintSource`. */\n\tresolveCanvasPaint(paint: unknown): unknown;\n\trenderShapeBrushstrokeNow(shape: BrushedPathShape, scale: number): CanvasBrushstrokeImage | null;\n\tbrushedShapeSvgNow(shape: BrushedPathShape, size: ShapeSize, scale: number): string;\n}\n\nlet loading: Promise<CanvasBrushstrokeRenderer> | null = null;\n\n/**\n * Loads the brushstroke renderer (the paint engine's dry brushes, the paint presets and a CSS\n * colour parser). Called for you by the functions below; call it early to warm up.\n */\nexport function loadCanvasBrushstrokeRenderer(): Promise<CanvasBrushstrokeRenderer> {\n\tloading ??= (import('./brushstrokeRender.js') as Promise<CanvasBrushstrokeRenderer>).catch((error) => {\n\t\tloading = null;\n\t\tthrow error;\n\t});\n\treturn loading;\n}\n\n/** The dry paint presets a freehand stroke can use (wet, mixer, blender, smudge and eraser presets are left out). */\nexport async function listCanvasBrushes(): Promise<CanvasBrushPreset[]> {\n\treturn (await loadCanvasBrushstrokeRenderer()).listCanvasBrushes();\n}\n\n/**\n * Checks a brush: an unknown preset id, a wet (or other non-dry) preset, or settings that are not\n * an object throw an error saying which presets can be used.\n */\nexport async function validateCanvasBrush(brush: CanvasBrush): Promise<void> {\n\t(await loadCanvasBrushstrokeRenderer()).resolveCanvasBrush(brush, 1);\n}\n\n/**\n * Checks a brushed stroke's `paint` (a colour or gradient paint): bad stops, an unknown mapping,\n * or a mapping that needs timed samples (`velocity`, `time`) throw an error saying what to use.\n */\nexport async function validateCanvasBrushPaint(paint: CanvasBrushPaint): Promise<void> {\n\t(await loadCanvasBrushstrokeRenderer()).resolveCanvasPaint(paint);\n}\n\nexport interface RenderShapeBrushstrokeOptions {\n\t/** Image pixels per path unit; pass `brushstrokeScaleBucket(zoom × node scale, devicePixelRatio)` (default 1). */\n\tscale?: number;\n}\n\n/**\n * Renders a brushed path shape to a cached PNG placed in path coordinates, or null for a shape\n * without a brush or an empty path. Throws for an unknown or non-dry brush.\n */\nexport async function renderShapeBrushstroke(shape: ShapeDescription, options: RenderShapeBrushstrokeOptions = {}): Promise<CanvasBrushstrokeImage | null> {\n\tif (!isBrushedShape(shape)) return null;\n\treturn (await loadCanvasBrushstrokeRenderer()).renderShapeBrushstrokeNow(shape, options.scale ?? 1);\n}\n\n/**\n * The brushed stroke as a standalone SVG document of `size` (the node box), with the image\n * embedded as a PNG data URL: what an SVG export writes for the node. Shapes without a brush give\n * null (export them as paths).\n */\nexport async function getBrushedShapeSvg(shape: ShapeDescription, size: ShapeSize, options: RenderShapeBrushstrokeOptions = {}): Promise<string | null> {\n\tif (!isBrushedShape(shape)) return null;\n\treturn (await loadCanvasBrushstrokeRenderer()).brushedShapeSvgNow(shape, size, options.scale ?? 2);\n}\n"]}
|