@pixerate/editor 0.109.0 → 0.111.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.
Files changed (66) hide show
  1. package/THIRD_PARTY_NOTICES.md +3 -0
  2. package/dist/blending-DXl06NSx.d.ts +486 -0
  3. package/dist/blending-aOE6Y3UE.d.cts +486 -0
  4. package/dist/chunk-7VOHOPLW.cjs +1136 -0
  5. package/dist/chunk-7VOHOPLW.cjs.map +1 -0
  6. package/dist/chunk-FTBZPI77.cjs +1 -0
  7. package/dist/chunk-FTBZPI77.cjs.map +1 -0
  8. package/dist/{chunk-RE77QYUF.js → chunk-HHZ6ZJTW.js} +880 -86
  9. package/dist/chunk-HHZ6ZJTW.js.map +1 -0
  10. package/dist/{chunk-WMBIJCHA.js → chunk-HNS7UHCM.js} +5 -1
  11. package/dist/{chunk-WMBIJCHA.js.map → chunk-HNS7UHCM.js.map} +1 -1
  12. package/dist/{chunk-CFMWALBM.js → chunk-LQEEDHOP.js} +2 -2
  13. package/dist/{chunk-D37BX2ZA.cjs → chunk-PHUMLSCW.cjs} +1141 -347
  14. package/dist/chunk-PHUMLSCW.cjs.map +1 -0
  15. package/dist/{chunk-AZTZRLDI.cjs → chunk-POGBUYWE.cjs} +92 -92
  16. package/dist/{chunk-AZTZRLDI.cjs.map → chunk-POGBUYWE.cjs.map} +1 -1
  17. package/dist/chunk-VKK5VS2T.js +1 -0
  18. package/dist/{chunk-SZ6KMZNM.cjs → chunk-XIOMMGPD.cjs} +6 -2
  19. package/dist/chunk-XIOMMGPD.cjs.map +1 -0
  20. package/dist/{chunk-3PHA3UKI.js → chunk-Z4BC6M74.js} +523 -121
  21. package/dist/chunk-Z4BC6M74.js.map +1 -0
  22. package/dist/{export-BLPLaE6Z.d.ts → export-DBNVwb6h.d.ts} +521 -12
  23. package/dist/{export-DSUc4fQD.d.cts → export-DoDhCszr.d.cts} +521 -12
  24. package/dist/image-editor/index.cjs +1630 -900
  25. package/dist/image-editor/index.cjs.map +1 -1
  26. package/dist/image-editor/index.d.cts +104 -16
  27. package/dist/image-editor/index.d.ts +104 -16
  28. package/dist/image-editor/index.js +776 -46
  29. package/dist/image-editor/index.js.map +1 -1
  30. package/dist/paint/index.cjs +28 -4
  31. package/dist/paint/index.cjs.map +1 -1
  32. package/dist/paint/index.d.cts +3 -89
  33. package/dist/paint/index.d.ts +3 -89
  34. package/dist/paint/index.js +27 -3
  35. package/dist/paint-editor/index.cjs +1052 -286
  36. package/dist/paint-editor/index.cjs.map +1 -1
  37. package/dist/paint-editor/index.d.cts +302 -23
  38. package/dist/paint-editor/index.d.ts +302 -23
  39. package/dist/paint-editor/index.js +848 -82
  40. package/dist/paint-editor/index.js.map +1 -1
  41. package/dist/raster/index.cjs +5 -3
  42. package/dist/raster/index.cjs.map +1 -1
  43. package/dist/raster/index.d.cts +2 -2
  44. package/dist/raster/index.d.ts +2 -2
  45. package/dist/raster/index.js +4 -2
  46. package/dist/{render-C-fO_mes.d.cts → render-BEriFuqK.d.cts} +1 -1
  47. package/dist/{render-OLIMk_v0.d.ts → render-tjzKaik-.d.ts} +1 -1
  48. package/dist/{surface-CkKOHGPm.d.cts → surface-C8RRg_Bh.d.cts} +109 -1
  49. package/dist/{surface-CkKOHGPm.d.ts → surface-C8RRg_Bh.d.ts} +109 -1
  50. package/package.json +1 -1
  51. package/skills/pixerate-image-editor/SKILL.md +27 -30
  52. package/skills/pixerate-image-editor/references/shapes-and-type.md +60 -0
  53. package/skills/pixerate-paint-editor/SKILL.md +49 -13
  54. package/dist/chunk-3PHA3UKI.js.map +0 -1
  55. package/dist/chunk-6BU5WU4R.cjs +0 -1
  56. package/dist/chunk-6BU5WU4R.cjs.map +0 -1
  57. package/dist/chunk-D37BX2ZA.cjs.map +0 -1
  58. package/dist/chunk-HUFQD4CB.cjs +0 -734
  59. package/dist/chunk-HUFQD4CB.cjs.map +0 -1
  60. package/dist/chunk-RE77QYUF.js.map +0 -1
  61. package/dist/chunk-SZ6KMZNM.cjs.map +0 -1
  62. package/dist/chunk-XYBJKUAU.js +0 -1
  63. package/dist/mixer-5ziHU8OS.d.cts +0 -282
  64. package/dist/mixer-DNqiYXYQ.d.ts +0 -282
  65. /package/dist/{chunk-CFMWALBM.js.map → chunk-LQEEDHOP.js.map} +0 -0
  66. /package/dist/{chunk-XYBJKUAU.js.map → chunk-VKK5VS2T.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixerate-paint-editor
3
- description: How to make a picture in the Pixerate paint editor (natural media in the spirit of Painter and Rebelle) through its agent tools - canvas and paper (generated grain, depth, colour, families from cold pressed watercolour to canvas and gesso), layers, dry-media brushes (pencil, pastel, charcoal, airbrush, marker, ink, erasers, blender, smudge, Mixer Brush) with pressure, tilt, barrel rotation and velocity, the brush library, strokes as data that replay and vary, mirror and kaleidoscope painting, perspective guides, tracing and reference images, colour harmonies, swatches, a mixing pad and pigment mixing, previews and PNG, JPEG, WebP, PSD and JSON output. Use when asked to paint, sketch, draw, shade, block in, texture with paper grain, mix colours, paint symmetric or in perspective, trace an image, or when paint_stroke, set_paper, replay_strokes, set_symmetry or mix_colors are available.
3
+ description: How to make a picture in the Pixerate paint editor (natural media in the spirit of Painter, Rebelle and ArtRage) through its agent tools - canvas and paper (generated grain, depth, families from cold pressed watercolour to canvas), layers with painterly blend modes (watercolor, tint, highlight, shadow), dry-media brushes (pencil, pastel, charcoal, airbrush, marker, ink, erasers) with pressure, tilt, barrel rotation and velocity, blending tools (blender, smudge, Mixer Brush), brush behaviours (pick-up and mix ratios, dirty and multi-coloured brushes), the brush library, strokes that replay and vary, symmetry and perspective guides, tracing and reference images, harmonies, swatches, a mixing pad and pigment mixing, and PNG, JPEG, WebP, PSD and JSON output. Use when asked to paint, sketch, shade, blend, smudge, glaze, mix colours, paint symmetric or in perspective, trace an image, or when paint_stroke, set_paper, replay_strokes or mix_colors are available.
4
4
  ---
5
5
 
6
6
  # Paint editor
@@ -14,8 +14,15 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
14
14
  - **Brushes** are library presets (`list_brushes`): a tip from the shared engine (size,
15
15
  hardness, spacing, angle, roundness, opacity, flow, blend), a **grain** response, pen dynamics
16
16
  (pressure, tilt, velocity, jitter), a **rotation** mode (`fixed`, `stroke`, `barrel`) and an
17
- engine: `dab` (most media), `eraser`, or `mixer` (Mixer Brush, blender, smudge: they pick up and
18
- move paint already on the layer).
17
+ engine: `dab` (most media), `eraser`, `mixer` (the Mixer Brush: a reservoir of paint plus paint
18
+ it picks up), `blender` (mixes the colours under and near the tip) or `smudge` (drags paint
19
+ along the stroke).
20
+ - **Behaviour** (`behavior`, dab and mixer brushes) is how a brush treats paint already on the
21
+ canvas: a **pick-up ratio** (how much paint each dab lifts and carries), a **mix ratio** (how
22
+ much of the carried paint goes into what it lays down), **dirty** (keep the carried colour into
23
+ the next stroke) and **multi-colour** (`tip`: several colours side by side across the tip;
24
+ `dab`: the colour changes along the stroke). A Mixer Brush's `mixer.wet` / `mixer.mix` are the
25
+ same two ratios. `get_mixer_brush` reads what the brush carries; `clean_mixer_brush` wipes it.
19
26
  - **Grain**: a brush's grain response times the paper's `depth` decides how much light pressure
20
27
  skips the valleys. Pencil, pastel and charcoal are grainy; airbrush, marker and ink are not.
21
28
  - **Strokes are data.** Every stroke is recorded (brush, colour, raw points, seed, symmetry
@@ -46,8 +53,13 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
46
53
  greys); the mixing pad (`mixing_pad_stroke`, `pick_mixing_pad_color`) mixes by hand with a
47
54
  palette knife. Keep chosen colours as swatches (`add_swatch`). Use the result as the stroke
48
55
  `color`; `set_color` makes it the default.
49
- 5. **Refine** with smaller brushes on new layers: pencil and ink for line, charcoal for value,
50
- blender or smudge to soften edges, the Mixer Brush to blend wet into wet.
56
+ 5. **Refine** with smaller brushes on new layers: pencil and ink for line, charcoal for value.
57
+ **Blend** on the layer that holds the paint: `blender` to melt neighbouring colours together
58
+ (pigment mixing, so blue next to yellow goes green), `smudge` / `wet-smudge` to drag paint
59
+ into soft edges and streaks, `mixer-brush` to paint wet into wet, `dirty-round` to paint with
60
+ a brush that picks up and carries colour, `multicolor-flat` for strokes loaded with several
61
+ colours. Glaze with a `watercolor` layer, warm or cool with `tint`, light with `highlight`,
62
+ shade with `shadow`.
51
63
  6. **Let the guides multiply your marks.** `set_symmetry` (mirror for faces and vases,
52
64
  kaleidoscope for mandalas and ornaments) paints every copy from one stroke;
53
65
  `set_perspective_guide` plus `paint_stroke` with `snapToPerspective` lays converging lines for
@@ -76,8 +88,21 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
76
88
  between them. Long smooth curves need more points than straight lines.
77
89
  - **Use `rotation: "stroke"`** for flat tips (pastel, charcoal, chisel marker) so the mark turns
78
90
  with the path; `fixed` for calligraphic nibs.
79
- - **Blend with flow, not opacity**: blender and smudge work best at flow 0.3..0.6; at full flow
80
- the Mixer Brush paints only its own colour.
91
+ - **Blending tools**:
92
+ - `blender`: `strength` 0.3..0.6 for soft transitions, `distance` 0.2..0.5 (fraction of the
93
+ tip) for how far colours travel. Keep `mixing: "pigment"` for painterly blends; `rgb`
94
+ blends like a soft blur. Work along an edge in short strokes rather than over everything.
95
+ - `smudge`: `length` near 0.9 drags paint far (long streaks), 0.5 short pushes; `strength`
96
+ 0.5..0.8. `mixing: "pigment"` (the `wet-smudge` preset) smears colours into each other like
97
+ wet paint.
98
+ - Mixer Brush: blend with flow 0.3..0.6; at full flow it paints only its own colour.
99
+ - **Pick-up and mix ratios**: `pickup` 0.3..0.7 with `mix` 0.4..0.7 gives a brush that drags
100
+ the colours it crosses into its own; `dirty: true` keeps them for the next stroke (wipe with
101
+ `clean_mixer_brush`). Keep `pickup` 0 for clean, predictable colour.
102
+ - **Multi-colour**: give 2..8 `colors` (or none for the paint and secondary colours). `tip` mode
103
+ with a flat tip and `rotation: "stroke"` paints ribbons; `softness` 0.3..0.7 keeps the stripes
104
+ readable. `dab` mode with `order: "sequence"` and `length` 5..20 walks through a palette;
105
+ `random` for foliage and confetti.
81
106
  - **Pigment for paint, multiply for markers**: tip `blend: "pigment"` mixes subtractively on the
82
107
  canvas; `multiply` darkens where marker strokes overlap. Pigment layers are written as Normal
83
108
  to PSD (the export warns).
@@ -130,9 +155,9 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
130
155
 
131
156
  | Tool | Use |
132
157
  | --- | --- |
133
- | `list_brushes` | Read the library (built-in and saved): id, name, category, engine, size, grain response, rotation, `builtin`; plus the active brush id and whether it is edited. |
158
+ | `list_brushes` | Read the library (built-in and saved): id, name, category, engine, size, grain response, rotation, `wetCapable`, `pickup`, `dirty`, `multicolor` mode, `builtin`; plus the active brush id and whether it is edited. |
134
159
  | `get_brush` | Read every setting of a brush, or of the active brush as edited (no `id`). Read before changing a brush you did not build. |
135
- | `set_brush` | Choose the active brush (`id`) and / or change it: `tip` (size px, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend), `grain`, `pressureSmoothing`, `rotation`, `dynamics` (minSize, pressureFlow, tiltSize, tiltRoundness, tiltOpacity, velocitySize, velocityOpacity, jitters, scatter), `mixer`, `loadsColor`. Editor state. Returns the brush. |
160
+ | `set_brush` | Choose the active brush (`id`) and / or change it: `tip` (size px, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend), `grain`, `pressureSmoothing`, `rotation`, `dynamics` (minSize, pressureFlow, tiltSize, tiltRoundness, tiltOpacity, velocitySize, velocityOpacity, jitters, scatter), `engine`, `mixer`, `loadsColor`, `behavior` (pickup, mix, dirty, mixing, multicolor: mode, colors, order, length, softness), `blender` (strength, distance, mixing), `smudge` (strength, length, mixing). Editor state. Returns the brush. |
136
161
  | `save_brush` | Store the active brush in the user library under `id` (lowercase, digits, dashes) and `name`. Built-in ids are refused. |
137
162
  | `remove_brush` | Delete a user brush. Built-in brushes cannot be removed. |
138
163
  | `export_brushes` | Get a brush library file (JSON) of `ids`, or of every user brush. |
@@ -143,12 +168,12 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
143
168
 
144
169
  | Tool | Use |
145
170
  | --- | --- |
146
- | `mix_colors` | Predict a paint mix: `colors` with `weight` parts (and optional tinting `strength`). Returns `mixed` (#rrggbb, Kubelka-Munk) and the plain RGB average for comparison. Changes nothing. Use it to choose stroke colours. |
171
+ | `mix_colors` | Predict a mix: `colors` with `weight` parts (and optional tinting `strength`), `model` `pigment` (default, Kubelka-Munk: what pigment blends, the Mixer Brush, pigment blending tools and the pad do) or `rgb` (what normal blending and rgb mixing do). Returns `mixed` by the model plus `pigment` and `rgbLerp` for comparison. Changes nothing. Use it to choose stroke colours. |
147
172
  | `set_color` | Set the default paint `color` (and `secondaryColor`). |
148
173
  | `pick_color` | Read the colour at `x`, `y`: of the painting with its paper, or of one layer (with alpha). |
149
- | `get_mixer_brush` | Read what the Mixer Brush carries: `reservoir`, `amount` left, `pickup`. |
174
+ | `get_mixer_brush` | Read what the brush carries: the Mixer Brush `reservoir` and `amount` left, and `pickup` (paint picked up, kept by dirty brushes). |
150
175
  | `load_mixer_brush` | Fill the Mixer Brush reservoir with a colour (keeps its pickup). |
151
- | `clean_mixer_brush` | Empty the pickup well (and with `emptyReservoir` the paint). |
176
+ | `clean_mixer_brush` | Wipe the brush: drop the picked-up paint a dirty brush or the Mixer Brush carries (and with `emptyReservoir` the Mixer Brush paint). |
152
177
  | `color_harmony` | Get a harmony (`kind`: complementary, split-complementary, analogous, triadic, tetradic, square, monochromatic) around `color` (default the paint colour), on the `ryb` painter's wheel (default; red ↔ green) or the `rgb` wheel (red ↔ cyan), `spread` degrees for analogous and split. Changes nothing. |
153
178
  | `list_swatches` | Read the swatches (index, colour, name). |
154
179
  | `add_swatch` | Keep a colour as a swatch (saved with the document). |
@@ -156,13 +181,18 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
156
181
  | `mixing_pad_stroke` | Paint on the 360 × 220 mixing pad (pad px): `tool` paint lays `color` with a pigment Mixer Brush, `knife` smears what is there and mixes it as paint. Scratch space, not the painting, no undo. |
157
182
  | `pick_mixing_pad_color` | Read the mix on the pad at `x`, `y` (averaged over `radius`, default 3); `setColor` makes it the paint colour. Null where the pad is bare. |
158
183
  | `clear_mixing_pad` | Wipe the pad. |
184
+ | `mix_on_pad` | Mix `paints` (`color`, `parts`) on the pad in one call: blobs by parts, knife passes, and a fully mixed Kubelka-Munk core. Optional pile `x`, `y`, `radius`, `passes`, `clear`; `setColor` makes the mix the paint colour. Returns `color` and the pile `bounds`. The quickest way to get a paint colour from named paints. |
185
+ | `save_mixing_pad` | Keep the pad as it is under a `name` (saved with the document). Refused when the pad is empty. Returns the id. |
186
+ | `list_mixing_pads` | Read the kept pads (`id`, `name`). |
187
+ | `load_mixing_pad` | Put a kept pad back (replaces what is on the pad). |
188
+ | `remove_mixing_pad` | Forget a kept pad. |
159
189
  | `render_mixing_pad` | See the pad as a PNG. |
160
190
 
161
191
  ### Painting and strokes
162
192
 
163
193
  | Tool | Use |
164
194
  | --- | --- |
165
- | `paint_stroke` | Paint one stroke through `points` (document px; `pressure` 0..1, `t` ms, `tiltX` / `tiltY` or `altitude` / `azimuth`, `twist`) with `brushId` (default the active brush), optional per-stroke `brush` changes, `color`, `layerId`, `seed`, `snapToPerspective`. The symmetry guide adds its copies; a sampling tracing image supplies the colour when `color` is missing. Returns `layerId`, `bounds`, `dabs`, `strokeId` and for the mixer engine its `mixerLoad`. Refused on locked, hidden or group layers, with the fix in the message. |
195
+ | `paint_stroke` | Paint one stroke through `points` (document px; `pressure` 0..1, `t` ms, `tiltX` / `tiltY` or `altitude` / `azimuth`, `twist`) with `brushId` (default the active brush), optional per-stroke `brush` changes, `color`, `layerId`, `seed`, `snapToPerspective`. The symmetry guide adds its copies; a sampling tracing image supplies the colour when `color` is missing. Returns `layerId`, `bounds`, `dabs`, `strokeId` and, for brushes that pick up paint, `mixerLoad` (what the brush carries now). Refused on locked, hidden or group layers, with the fix in the message. |
166
196
  | `list_strokes` | Read the recorded strokes, oldest first (default the last 100): id, layer, brush, colour, point count, seed, bounds. With `ids`, their points too. |
167
197
  | `replay_strokes` | Paint recorded `strokeIds` again: exactly, or varied by `dx` / `dy` (px), `rotate` (degrees clockwise), `scale` (brush size follows), `flipX`, `origin`, `pressureScale`, `color`, `brushId`, `layerId`, `repeat` (each copy applies the variation again). One undo step. Returns the new stroke ids, bounds and layers. |
168
198
  | `undo_paint` | Undo the last step. Returns what was undone and what is next. |
@@ -206,6 +236,12 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
206
236
  has depth 0.
207
237
  - **Grain is fixed to the document**, not to the layer: moving content does not move the grain,
208
238
  and two strokes on the same spot catch the same peaks.
239
+ - **Blending tools need paint to blend.** Blender and smudge only move what is on the target
240
+ layer: blend on the layer you painted, not on an empty one above it.
241
+ - **A dirty brush stays dirty** across strokes and colour changes until `clean_mixer_brush`.
242
+ Pick-up lifts only paint on the target layer: the paper and other layers lift nothing.
243
+ - **Replays use the recorded load**: a replayed pick-up stroke starts with what the brush carried
244
+ when it was painted, not with the current load.
209
245
  - **Big soft brushes at full flow look flat.** Lower `flow` (airbrush 0.05..0.15) and build up.
210
246
  - **JPEG and WebP need a browser**; in Node use PNG. Exports never upscale (`scale` ≤ 1).
211
247
  - **Symmetry stays on until you turn it off.** Set `mode: "off"` after the symmetric part, or
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/paint/brush.ts","../src/paint/mixer.ts","../src/paint/pigment-tools.ts"],"sourcesContent":["// Portions ported from photocraft/crates/paint/src/lib.rs, dynamics.rs and render.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * The brush engine (a subset of photocraft's `crates/paint`): a computed round tip with size,\n * hardness, angle, roundness and spacing; pressure to size and opacity; smoothing; and Photoshop's\n * opacity-versus-flow build-up. Strokes are data, so one replays the same way for undo, agents\n * and tests.\n *\n * - Points are walked into dabs at `spacing × diameter` (`walkDabs`).\n * - Each dab's coverage (`dabCoverage`, photocraft's measured Photoshop profile) builds up in a\n * stroke coverage map with flow towards the dab's opacity ceiling: `c ← c + v·(ceil − c)`.\n * - The stroke composites once at the stroke opacity over the layer as it was before the stroke,\n * so overlapping dabs never exceed the opacity.\n */\n\nimport { blendPixel, mixPigment8, type BlendMode } from '../raster/blend';\nimport type { RasterRect as CropBox } from '../raster/surface';\nimport { TILE, tileKey, tileCoord, type TileKey } from '../raster/surface';\n\n/** One input sample. Missing pressure is a mouse (1). */\nexport interface StrokePoint {\n x: number;\n y: number;\n /** 0..1 (default 1). */\n pressure?: number;\n /** Milliseconds (optional; kept for replays). */\n t?: number;\n}\n\nexport interface BrushSettings {\n /** Diameter in pixels (1..2500, default 20). */\n size: number;\n /** 0 (soft) .. 1 (hard, default). */\n hardness: number;\n /** Dab spacing as a fraction of the diameter (0.01..10, default 0.1). */\n spacing: number;\n /** Tip angle in degrees (default 0). */\n angle: number;\n /** Tip roundness 0.01..1 (default 1). */\n roundness: number;\n /** Stroke opacity ceiling 0..1 (default 1). */\n opacity: number;\n /** Build-up per dab 0..1 (default 1). */\n flow: number;\n /** Input smoothing 0..0.95 (default 0). */\n smoothing: number;\n /** Pressure controls size (default true). */\n pressureSize: boolean;\n /** Pressure controls opacity (default false). */\n pressureOpacity: boolean;\n /** How the stroke paints onto the layer (default normal). */\n blend: BlendMode;\n}\n\nexport const DEFAULT_BRUSH: Readonly<BrushSettings> = {\n size: 20,\n hardness: 1,\n spacing: 0.1,\n angle: 0,\n roundness: 1,\n opacity: 1,\n flow: 1,\n smoothing: 0,\n pressureSize: true,\n pressureOpacity: false,\n blend: 'normal',\n};\n\nexport const MAX_BRUSH_SIZE = 2500;\n\n/** A brush with every field in range (missing fields from `DEFAULT_BRUSH`). */\nexport function normalizeBrush(raw: Partial<BrushSettings> = {}): BrushSettings {\n const num = (v: unknown, lo: number, hi: number, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d);\n return {\n size: num(raw.size, 1, MAX_BRUSH_SIZE, DEFAULT_BRUSH.size),\n hardness: num(raw.hardness, 0, 1, DEFAULT_BRUSH.hardness),\n spacing: num(raw.spacing, 0.01, 10, DEFAULT_BRUSH.spacing),\n angle: num(raw.angle, -360, 360, DEFAULT_BRUSH.angle),\n roundness: num(raw.roundness, 0.01, 1, DEFAULT_BRUSH.roundness),\n opacity: num(raw.opacity, 0, 1, DEFAULT_BRUSH.opacity),\n flow: num(raw.flow, 0, 1, DEFAULT_BRUSH.flow),\n smoothing: num(raw.smoothing, 0, 0.95, DEFAULT_BRUSH.smoothing),\n pressureSize: typeof raw.pressureSize === 'boolean' ? raw.pressureSize : DEFAULT_BRUSH.pressureSize,\n pressureOpacity: typeof raw.pressureOpacity === 'boolean' ? raw.pressureOpacity : DEFAULT_BRUSH.pressureOpacity,\n blend: raw.blend ?? 'normal',\n };\n}\n\n// ---------------------------------------------------------------------------\n// The round tip (photocraft's measured Photoshop profile)\n// ---------------------------------------------------------------------------\n\n/**\n * Photoshop's round tip, measured by photocraft: a solid core of radius `r0 · R`, then a Gaussian\n * shoulder `exp(-((d − r0) / s)²)` of width `s · R`, both by hardness (0, 0.1, … 1).\n */\nconst TIP_SHAPE: ReadonlyArray<[number, number]> = [\n [0.0, 0.664], [0.14, 0.58], [0.28, 0.5], [0.4, 0.44], [0.52, 0.36], [0.63, 0.29],\n [0.7, 0.24], [0.78, 0.19], [0.84, 0.15], [0.89, 0.11], [1.0, 0.0],\n];\n/** The anti-aliased edge: the shoulder never narrows below this many pixels. */\nconst TIP_EDGE_PX = 1.2;\nconst SMALL_TIP_RADIUS = 3;\nconst SUBPIXEL = [-0.375, -0.125, 0.125, 0.375];\n\n/** The core radius and shoulder width (pixels) of a round tip of `radius` and `hardness`. */\nexport function tipShape(radius: number, hardness: number): [number, number] {\n const h = (Number.isNaN(hardness) ? 0 : Math.min(1, Math.max(0, hardness))) * 10;\n const i = Math.min(9, Math.floor(h));\n const t = h - i;\n const a = TIP_SHAPE[i];\n const b = TIP_SHAPE[i + 1];\n const r0 = a[0] + (b[0] - a[0]) * t;\n const s = a[1] + (b[1] - a[1]) * t;\n const r = Number.isFinite(radius) ? Math.max(0, radius) : 0;\n const edge = Math.max(0.25, Math.min(TIP_EDGE_PX, 0.3 * r));\n return [Math.max(0, Math.min(r0 * r, r - edge)), Math.max(1e-3, s * r, edge)];\n}\n\n/** `exp(-u)` as `(1 − u/64)^64` by six squarings: exactly 0 from u = 64. */\nfunction softExp(u: number): number {\n let g = Math.min(1, Math.max(0, 1 - u / 64));\n for (let k = 0; k < 6; k++) g *= g;\n return g;\n}\n\n/** Opacity of a round tip at distance `d` from its centre. */\nexport function tipFalloff(d: number, radius: number, hardness: number): number {\n const [r0, s] = tipShape(radius, hardness);\n if (d <= r0) return 1;\n const x = (d - r0) / s;\n return softExp(x * x);\n}\n\n/** How far from its centre a round tip still paints. */\nexport function tipReach(radius: number, hardness: number): number {\n const [r0, s] = tipShape(radius, hardness);\n return r0 + 2.6 * s;\n}\n\n/** Coverage of a round dab at distance `d` from its centre. */\nexport function dabCoverage(d: number, radius: number, hardness: number): number {\n if (Number.isNaN(d) || d >= tipReach(radius, hardness) + 0.5) return 0;\n return tipFalloff(d, radius, hardness);\n}\n\n// ---------------------------------------------------------------------------\n// Points → dabs\n// ---------------------------------------------------------------------------\n\nexport interface Dab {\n x: number;\n y: number;\n radius: number;\n /** Flow (per-dab build-up). */\n alpha: number;\n /** Opacity ceiling this dab builds up to. */\n opacity: number;\n /** Radians. */\n angle: number;\n roundness: number;\n}\n\n/** Exponential smoothing of input points; the first and last point are kept. */\nexport function smoothPoints(points: readonly StrokePoint[], amount: number): StrokePoint[] {\n const a = 1 - Math.min(0.95, Math.max(0, amount));\n if (a >= 1 || points.length < 3) return points.slice();\n const out: StrokePoint[] = [];\n let cur: StrokePoint | null = null;\n for (const p of points) {\n const n: StrokePoint = cur ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;\n out.push(n);\n cur = n;\n }\n out[out.length - 1] = points[points.length - 1];\n return out;\n}\n\nconst pressureOf = (p: StrokePoint) => (typeof p.pressure === 'number' && Number.isFinite(p.pressure) ? Math.min(1, Math.max(0, p.pressure)) : 1);\n\n/**\n * Walks points into dabs (incrementally: feed points in any chunks and get the same dabs). The\n * first point is a dab; then one every `spacing × diameter` along the path.\n */\nexport class DabWalker {\n private last: StrokePoint | null = null;\n private nextAt = 0;\n private pendingFirst: StrokePoint | null = null;\n\n constructor(readonly brush: BrushSettings) {}\n\n private diameter(p: StrokePoint): number {\n return this.brush.pressureSize ? this.brush.size * pressureOf(p) : this.brush.size;\n }\n\n private stepLen(p: StrokePoint): number {\n return Math.max(0.5, Math.max(1, this.diameter(p)) * Math.max(0.01, this.brush.spacing));\n }\n\n private dab(p: StrokePoint): Dab {\n const b = this.brush;\n return {\n x: p.x,\n y: p.y,\n radius: Math.max(0.5, this.diameter(p) / 2),\n alpha: Math.min(1, Math.max(0, b.flow)),\n opacity: b.pressureOpacity ? pressureOf(p) : 1,\n angle: (b.angle * Math.PI) / 180,\n roundness: Math.min(1, Math.max(0.01, b.roundness)),\n };\n }\n\n push(p: StrokePoint, out: Dab[]): void {\n const a = this.last;\n if (!a) {\n this.last = p;\n this.pendingFirst = p;\n this.nextAt = this.stepLen(p);\n return;\n }\n if (this.pendingFirst) {\n out.push(this.dab(this.pendingFirst));\n this.pendingFirst = null;\n }\n const dx = p.x - a.x;\n const dy = p.y - a.y;\n const len = Math.hypot(dx, dy);\n if (len > 1e-9) {\n while (this.nextAt <= len + 1e-9) {\n const f = Math.min(1, this.nextAt / len);\n const q: StrokePoint = {\n x: a.x + dx * f,\n y: a.y + dy * f,\n pressure: pressureOf(a) + (pressureOf(p) - pressureOf(a)) * f,\n };\n out.push(this.dab(q));\n this.nextAt += this.stepLen(q);\n }\n this.nextAt -= len;\n }\n this.last = p;\n }\n\n finish(out: Dab[]): void {\n if (this.pendingFirst) {\n out.push(this.dab(this.pendingFirst));\n this.pendingFirst = null;\n }\n }\n}\n\n/** All dabs of a point list (smoothing applied). */\nexport function walkDabs(points: readonly StrokePoint[], brush: BrushSettings): Dab[] {\n const w = new DabWalker(brush);\n const out: Dab[] = [];\n for (const p of smoothPoints(points, brush.smoothing)) w.push(p, out);\n w.finish(out);\n return out;\n}\n\n/** The pixel rectangle a dab can touch. */\nexport function dabRect(d: Dab, hardness: number): CropBox {\n // As `rasterizeDab`: the tip reaches `reach` across its minor axis and `reach / roundness` along it.\n const ro = Math.min(1, Math.max(0.5 / d.radius, d.roundness));\n const rm = Math.max(0.5, d.radius * ro);\n const r = Math.max(rm, tipReach(rm, hardness)) / ro + 1.5;\n const x0 = Math.floor(d.x - r);\n const y0 = Math.floor(d.y - r);\n return { x: x0, y: y0, width: Math.ceil(d.x + r) - x0, height: Math.ceil(d.y + r) - y0 };\n}\n\n/**\n * Rasterizes one dab over `rect` into `out` (rect.width × rect.height values, coverage × flow).\n * Small tips (radius below 3 px) take each pixel's covered area from a 4×4 grid.\n */\nexport function rasterizeDab(d: Dab, hardness: number, rect: CropBox, out: Float32Array): void {\n const w = rect.width;\n const h = rect.height;\n out.fill(0, 0, w * h);\n const r = d.radius;\n const ro = Math.min(1, Math.max(0.5 / r, d.roundness));\n const rm = Math.max(0.5, r * ro);\n const reach = Math.max(rm, tipReach(rm, hardness));\n const sn = Math.sin(d.angle);\n const cs = Math.cos(d.angle);\n const toTip = (dx: number, dy: number): [number, number] => {\n const ux = dx;\n const uy = -dy;\n return [ux * cs + uy * sn, -ux * sn + uy * cs];\n };\n const small = rm < SMALL_TIP_RADIUS;\n const reach2 = (reach + (small ? 0.75 : 0.5)) ** 2;\n for (let yy = 0; yy < h; yy++) {\n const dy = rect.y + yy + 0.5 - d.y;\n for (let xx = 0; xx < w; xx++) {\n const dx = rect.x + xx + 0.5 - d.x;\n const [u, v] = toTip(dx, dy);\n const d2 = (u * ro) ** 2 + v * v;\n if (d2 >= reach2) continue;\n let val: number;\n if (small) {\n let sum = 0;\n for (const sy of SUBPIXEL) {\n for (const sx of SUBPIXEL) {\n const [su, sv] = toTip(dx + sx, dy + sy);\n sum += tipFalloff(Math.sqrt((su * ro) ** 2 + sv * sv), rm, hardness);\n }\n }\n val = sum / 16;\n } else {\n val = dabCoverage(Math.sqrt(d2), rm, hardness);\n }\n if (val > 0) out[yy * w + xx] = val * d.alpha;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Stroke coverage\n// ---------------------------------------------------------------------------\n\nconst TILE_PIXELS = TILE * TILE;\n\n/** A stroke's accumulated coverage, in 256 px tiles over document space. */\nexport class CoverageMap {\n readonly tiles = new Map<TileKey, Float32Array>();\n bounds: CropBox | null = null;\n private dirty = new Set<TileKey>();\n\n get(x: number, y: number): number {\n const tx = Math.floor(x / TILE);\n const ty = Math.floor(y / TILE);\n const t = this.tiles.get(tileKey(tx, ty));\n return t ? t[(y - ty * TILE) * TILE + (x - tx * TILE)] : 0;\n }\n\n /** Builds up `vals` (over `rect`) with flow towards `ceil`: `c ← c + v·(ceil − c)`. */\n accumulate(rect: CropBox, vals: Float32Array, ceil: number): void {\n if (rect.width <= 0 || rect.height <= 0) return;\n const w = rect.width;\n const tx0 = Math.floor(rect.x / TILE);\n const ty0 = Math.floor(rect.y / TILE);\n const tx1 = Math.floor((rect.x + rect.width - 1) / TILE);\n const ty1 = Math.floor((rect.y + rect.height - 1) / TILE);\n let touched = false;\n for (let ty = ty0; ty <= ty1; ty++) {\n for (let tx = tx0; tx <= tx1; tx++) {\n const x0 = Math.max(rect.x, tx * TILE);\n const y0 = Math.max(rect.y, ty * TILE);\n const x1 = Math.min(rect.x + rect.width, tx * TILE + TILE);\n const y1 = Math.min(rect.y + rect.height, ty * TILE + TILE);\n let tile: Float32Array | undefined;\n for (let y = y0; y < y1; y++) {\n const row = (y - rect.y) * w;\n const trow = (y - ty * TILE) * TILE;\n for (let x = x0; x < x1; x++) {\n const v = vals[row + (x - rect.x)];\n if (v <= 0) continue;\n if (!tile) {\n const key = tileKey(tx, ty);\n tile = this.tiles.get(key);\n if (!tile) {\n tile = new Float32Array(TILE_PIXELS);\n this.tiles.set(key, tile);\n }\n this.dirty.add(key);\n touched = true;\n }\n const ti = trow + (x - tx * TILE);\n const c = tile[ti];\n if (ceil > c) tile[ti] = c + v * (ceil - c);\n }\n }\n }\n }\n if (touched) this.bounds = unionRect(this.bounds, rect);\n }\n\n /** Tiles changed since the last call. */\n takeDirty(): TileKey[] {\n const out = [...this.dirty];\n this.dirty.clear();\n return out;\n }\n}\n\nfunction unionRect(a: CropBox | null, b: CropBox): CropBox {\n if (!a) return { ...b };\n const x = Math.min(a.x, b.x);\n const y = Math.min(a.y, b.y);\n return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };\n}\n\n/** Paints a stroke's dabs into a coverage map, incrementally. */\nexport class StrokeCoverage {\n readonly coverage = new CoverageMap();\n private walker: DabWalker;\n private smoothing: number;\n private smoothPos: StrokePoint | null = null;\n private buf = new Float32Array(0);\n dabCount = 0;\n\n constructor(readonly brush: BrushSettings) {\n this.walker = new DabWalker(brush);\n this.smoothing = brush.smoothing;\n }\n\n /** Feeds input points; returns the document rectangles the new dabs touched. */\n push(points: readonly StrokePoint[]): CropBox[] {\n const dabs: Dab[] = [];\n for (const p of points) this.walker.push(this.smooth(p), dabs);\n return this.paint(dabs);\n }\n\n /** Ends the stroke (a single click still paints one dab). */\n finish(last?: StrokePoint): CropBox[] {\n const dabs: Dab[] = [];\n if (last && this.smoothPos && (this.smoothPos.x !== last.x || this.smoothPos.y !== last.y)) this.walker.push(last, dabs);\n this.walker.finish(dabs);\n return this.paint(dabs);\n }\n\n private smooth(p: StrokePoint): StrokePoint {\n const a = 1 - Math.min(0.95, Math.max(0, this.smoothing));\n const cur = this.smoothPos;\n const n = cur && a < 1 ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;\n this.smoothPos = n;\n return n;\n }\n\n private paint(dabs: Dab[]): CropBox[] {\n const rects: CropBox[] = [];\n for (const d of dabs) {\n const rect = dabRect(d, this.brush.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, this.brush.hardness, rect, vals);\n this.coverage.accumulate(rect, vals, d.opacity);\n rects.push(rect);\n this.dabCount++;\n }\n return rects;\n }\n}\n\n/** How a stroke changes pixels. */\nexport interface StrokeApply {\n /** `paint` puts colour down; `erase` removes alpha (or, with transparency locked, paints `background`). */\n mode: 'paint' | 'erase';\n /** RGBA 0..255 (paint colour, or the mask grey in `r`). */\n color: readonly [number, number, number, number];\n /** RGBA 0..255 the eraser paints on a transparency-locked layer (and on masks). */\n background: readonly [number, number, number, number];\n opacity: number;\n blend: BlendMode;\n lockTransparency: boolean;\n /** Selection coverage (document space, canvas-sized), or `null`. */\n selection: { width: number; height: number; data: ArrayLike<number> } | null;\n /** Layer offset (target pixels are in layer space). */\n offset: { x: number; y: number };\n}\n\n/**\n * Composites the stroke's coverage over `tileData` (the target's tile (tx, ty) as it was before\n * the stroke, in layer space; RGBA or one byte for masks) and returns the new tile data. With\n * `into` (the tile's previous result) and `region` (document space), only `region` is recomputed\n * and the rest of `into` is kept.\n */\nexport function applyStrokeToTile(\n coverage: CoverageMap,\n tileData: Uint8ClampedArray,\n channels: 1 | 4,\n tx: number,\n ty: number,\n s: StrokeApply,\n options: { into?: Uint8ClampedArray; region?: CropBox } = {}\n): Uint8ClampedArray {\n const out = options.into ? new Uint8ClampedArray(options.into) : new Uint8ClampedArray(tileData);\n const ox = tx * TILE + s.offset.x;\n const oy = ty * TILE + s.offset.y;\n let x0 = 0;\n let y0 = 0;\n let x1 = TILE;\n let y1 = TILE;\n if (options.region) {\n const r = options.region;\n x0 = Math.max(0, Math.floor(r.x) - ox);\n y0 = Math.max(0, Math.floor(r.y) - oy);\n x1 = Math.min(TILE, Math.ceil(r.x + r.width) - ox);\n y1 = Math.min(TILE, Math.ceil(r.y + r.height) - oy);\n if (x1 <= x0 || y1 <= y0) return out;\n // Start the region from the pre-stroke pixels: coverage is cumulative.\n if (options.into) {\n for (let y = y0; y < y1; y++) out.set(tileData.subarray((y * TILE + x0) * channels, (y * TILE + x1) * channels), (y * TILE + x0) * channels);\n }\n }\n const sel = s.selection;\n const cb = [0, 0, 0, 0];\n const cs = [s.color[0] / 255, s.color[1] / 255, s.color[2] / 255, s.color[3] / 255];\n const bg = [s.background[0] / 255, s.background[1] / 255, s.background[2] / 255, s.background[3] / 255];\n // With a tile-aligned offset the layer tile is one coverage tile: read it directly.\n const aligned = s.offset.x % TILE === 0 && s.offset.y % TILE === 0;\n const covTile = aligned ? coverage.tiles.get(tileKey(Math.floor(ox / TILE), Math.floor(oy / TILE))) : undefined;\n if (aligned && !covTile) return out;\n for (let y = y0; y < y1; y++) {\n const dy = oy + y;\n for (let x = x0; x < x1; x++) {\n const dx = ox + x;\n const c = covTile ? covTile[y * TILE + x] : coverage.get(dx, dy);\n if (c <= 0) continue;\n let k = c * s.opacity;\n if (sel) {\n if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;\n k *= sel.data[dy * sel.width + dx] / 255;\n }\n if (k > 1) k = 1;\n if (k <= 0) continue;\n const p = y * TILE + x;\n if (channels === 1) {\n const target = s.mode === 'erase' ? s.background[0] : s.color[0];\n out[p] = Math.round(out[p] + (target - out[p]) * k);\n continue;\n }\n const i = p * 4;\n if (s.mode === 'erase' && !s.lockTransparency) {\n out[i + 3] = Math.round(out[i + 3] * (1 - k));\n continue;\n }\n if (s.lockTransparency && out[i + 3] === 0) continue;\n const src = s.mode === 'erase' ? bg : cs;\n if (s.blend === 'pigment') {\n // `blendPixel`'s paint mix on the 8-bit colours, with their spectra cached.\n const bytes = s.mode === 'erase' ? s.background : s.color;\n const as = src[3] * k;\n if (!(as > 0)) continue;\n const ao = as + (out[i + 3] / 255) * (1 - as);\n mixPigment8(out[i], out[i + 1], out[i + 2], bytes[0], bytes[1], bytes[2], as / ao, cb);\n out[i] = Math.round(cb[0] * 255);\n out[i + 1] = Math.round(cb[1] * 255);\n out[i + 2] = Math.round(cb[2] * 255);\n if (!s.lockTransparency) out[i + 3] = Math.round(ao * 255);\n continue;\n }\n for (let ch = 0; ch < 4; ch++) cb[ch] = out[i + ch] / 255;\n const o = blendPixel(s.blend, cb, src, k);\n out[i] = Math.round(o[0] * 255);\n out[i + 1] = Math.round(o[1] * 255);\n out[i + 2] = Math.round(o[2] * 255);\n if (!s.lockTransparency) out[i + 3] = Math.round(o[3] * 255);\n }\n }\n return out;\n}\n\n/** Tile coordinates of coverage tile keys (for callers that track dirty tiles). */\nexport function coverageTileCoord(key: TileKey): { tx: number; ty: number } {\n return tileCoord(key);\n}\n","// Portions ported from photocraft/crates/paint/src/mixer.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * The Mixer Brush: a reservoir of loaded paint plus a pickup well that takes up colour from the\n * canvas under each dab (photocraft's behavioural model):\n *\n * - Each dab samples the canvas under its footprint (coverage- and alpha-weighted). The pickup\n * colour `P` moves towards that sample by `PICKUP_RATE × wet` (scaled by the sample's coverage).\n * - The dab's paint mixes the reservoir `R` (weight `amount × (1 − mix·wet)`) with the pickup\n * (weight `mix·wet`) and lands at `flow × opacity` times the total weight, over the pixels as\n * they are now, so earlier dabs of the same stroke are picked up again (smearing).\n * - The reservoir drains per dab unless `load` is 1, so low-load strokes run dry. A dry brush\n * (`wet` 0) paints only reservoir colour; an empty, wet brush smears canvas colour.\n *\n * `mixing: 'pigment'` does all three mixes (pickup, paint and deposit) with the Kubelka-Munk model\n * of `./pigment`, so a blue brush dragged through yellow makes green instead of grey. Everything\n * is data in, pixels out: the same canvas, points, settings and load replay identically.\n */\n\nimport { DabWalker, dabRect, rasterizeDab, type BrushSettings, type Dab, type StrokePoint } from './brush';\nimport { createPigment, lerpPigmentInto, setPigmentColor, type Pigment } from './pigment';\nimport type { RasterRect as CropBox } from '../raster/surface';\nimport { TILE } from '../raster/surface';\n\n/** How the Mixer Brush mixes colours: straight sRGB averages, or like paint (Kubelka-Munk). */\nexport type MixingModel = 'rgb' | 'pigment';\n\nexport const MIXING_MODELS: readonly MixingModel[] = ['rgb', 'pigment'];\n\n/** Mixer Brush options. */\nexport interface MixerSettings {\n /** How much colour the brush picks up from the canvas, 0 (dry) .. 1 (default 0.5). */\n wet: number;\n /** How much paint the reservoir holds, 0 .. 1 (default 0.5): below 1 it drains per dab and the stroke runs dry. */\n load: number;\n /** How far each dab's paint moves from the reservoir towards the picked-up colour, 0 .. 1 (default 0.5). */\n mix: number;\n /** Refill the reservoir with the paint colour at the start of each stroke (default true). */\n loadEachStroke: boolean;\n /** Empty the pickup well after each stroke (default true); off keeps the brush dirty for the next stroke. */\n cleanEachStroke: boolean;\n /** `rgb` (default) or `pigment` (blue and yellow make green). */\n mixing: MixingModel;\n}\n\nexport const DEFAULT_MIXER: Readonly<MixerSettings> = {\n wet: 0.5,\n load: 0.5,\n mix: 0.5,\n loadEachStroke: true,\n cleanEachStroke: true,\n mixing: 'rgb',\n};\n\n/** Fraction of the way the pickup colour moves towards the canvas per dab at 100 % wet. */\nexport const MIXER_PICKUP_RATE = 0.25;\n/** Fraction of the reservoir that drains per dab at 0 % load. */\nexport const MIXER_DRAIN = 0.08;\n\n/** Mixer settings with every field in range (missing fields from `DEFAULT_MIXER`). */\nexport function normalizeMixer(raw: Partial<MixerSettings> = {}): MixerSettings {\n const unit = (v: unknown, d: number) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d);\n const bool = (v: unknown, d: boolean) => (typeof v === 'boolean' ? v : d);\n return {\n wet: unit(raw.wet, DEFAULT_MIXER.wet),\n load: unit(raw.load, DEFAULT_MIXER.load),\n mix: unit(raw.mix, DEFAULT_MIXER.mix),\n loadEachStroke: bool(raw.loadEachStroke, DEFAULT_MIXER.loadEachStroke),\n cleanEachStroke: bool(raw.cleanEachStroke, DEFAULT_MIXER.cleanEachStroke),\n mixing: raw.mixing === 'pigment' ? 'pigment' : 'rgb',\n };\n}\n\n/** What the brush carries between strokes. Colours are straight sRGB, 0..1. */\nexport interface MixerLoad {\n /** Loaded paint, or `null` when the brush is unloaded. */\n readonly reservoir: readonly [number, number, number] | null;\n /** Reservoir left, 0..1. */\n readonly amount: number;\n /** Colour picked up from the canvas, or `null` when the brush is clean. */\n readonly pickup: readonly [number, number, number] | null;\n}\n\nexport const EMPTY_MIXER_LOAD: MixerLoad = { reservoir: null, amount: 0, pickup: null };\n\n/** The brush loaded full with `color` (sRGB 0..1); the pickup well is kept. */\nexport function loadMixer(load: MixerLoad, color: readonly [number, number, number]): MixerLoad {\n const c = (v: number) => Math.min(1, Math.max(0, Number.isFinite(v) ? v : 0));\n return { reservoir: [c(color[0]), c(color[1]), c(color[2])], amount: 1, pickup: load.pickup };\n}\n\n/** The brush with its pickup well emptied; the reservoir is kept. */\nexport function cleanMixer(load: MixerLoad): MixerLoad {\n return { reservoir: load.reservoir, amount: load.amount, pickup: null };\n}\n\n/** The pixels a mixer stroke reads and writes (RGBA tiles in layer space). */\nexport interface MixerTarget {\n /** The tile (TILE × TILE × 4) at (tx, ty) as it is now, or `null` when it is fully transparent. */\n readTile(tx: number, ty: number): Uint8ClampedArray | null;\n /** A writable tile at (tx, ty), returned by `readTile` from then on. */\n writeTile(tx: number, ty: number): Uint8ClampedArray;\n /** Layer offset: layer pixel = document pixel − offset. */\n offset: { x: number; y: number };\n /** Keep alpha and paint only where the layer has pixels. */\n lockTransparency: boolean;\n /** Selection coverage (document space, canvas-sized), or `null`. */\n selection: { width: number; height: number; data: ArrayLike<number> } | null;\n}\n\ntype Rgb = [number, number, number];\n\n/**\n * One Mixer Brush stroke. Feed points with `push` (any chunks give the same dabs), end with\n * `finish`; `load` is the brush load after the dabs so far. Each call returns the document\n * rectangles it touched.\n */\nexport class MixerStroke {\n dabCount = 0;\n bounds: CropBox | null = null;\n private walker: DabWalker;\n private smoothPos: StrokePoint | null = null;\n private buf = new Float32Array(0);\n private readonly settings: MixerSettings;\n private readonly reservoir: Rgb | null;\n private amount: number;\n private pickup: Rgb | null;\n private readonly pig: { res: Pigment; pick: Pigment; paint: Pigment; canvas: Pigment } | null;\n private readonly out: Rgb = [0, 0, 0];\n\n constructor(\n readonly brush: BrushSettings,\n settings: Partial<MixerSettings>,\n load: MixerLoad,\n private readonly target: MixerTarget\n ) {\n this.settings = normalizeMixer(settings);\n this.walker = new DabWalker(brush);\n this.reservoir = load.reservoir ? [load.reservoir[0], load.reservoir[1], load.reservoir[2]] : null;\n this.amount = this.reservoir ? Math.min(1, Math.max(0, load.amount)) : 0;\n this.pickup = load.pickup ? [load.pickup[0], load.pickup[1], load.pickup[2]] : null;\n this.pig =\n this.settings.mixing === 'pigment'\n ? { res: createPigment(this.reservoir ?? [0, 0, 0]), pick: createPigment(this.pickup ?? [0, 0, 0]), paint: createPigment([0, 0, 0]), canvas: createPigment([0, 0, 0]) }\n : null;\n }\n\n /** The brush load after the dabs so far. */\n get load(): MixerLoad {\n return { reservoir: this.reservoir ? [...this.reservoir] : null, amount: this.amount, pickup: this.pickup ? [...this.pickup] : null };\n }\n\n push(points: readonly StrokePoint[]): CropBox[] {\n const dabs: Dab[] = [];\n for (const p of points) this.walker.push(this.smooth(p), dabs);\n return this.paint(dabs);\n }\n\n finish(last?: StrokePoint): CropBox[] {\n const dabs: Dab[] = [];\n if (last && this.smoothPos && (this.smoothPos.x !== last.x || this.smoothPos.y !== last.y)) this.walker.push(last, dabs);\n this.walker.finish(dabs);\n return this.paint(dabs);\n }\n\n private smooth(p: StrokePoint): StrokePoint {\n const a = 1 - Math.min(0.95, Math.max(0, this.brush.smoothing));\n const cur = this.smoothPos;\n const n = cur && a < 1 ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;\n this.smoothPos = n;\n return n;\n }\n\n /** `a` mixed `t` of the way to `b` into `this.out`, by the mixing model. */\n private mix(a: Rgb, pa: Pigment | null, b: Rgb, pb: Pigment | null, t: number): Rgb {\n const o = this.out;\n if (pa && pb) lerpPigmentInto(pa, pb, t, o, 0);\n else for (let c = 0; c < 3; c++) o[c] = a[c] + (b[c] - a[c]) * t;\n return o;\n }\n\n private paint(dabs: Dab[]): CropBox[] {\n const rects: CropBox[] = [];\n for (const d of dabs) {\n const rect = dabRect(d, this.brush.hardness);\n const n = rect.width * rect.height;\n if (this.buf.length < n) this.buf = new Float32Array(n);\n const cov = this.buf.subarray(0, n);\n // Pure tip coverage: flow scales the deposit, not the sampling weights.\n rasterizeDab({ ...d, alpha: 1 }, this.brush.hardness, rect, cov);\n this.dab(d, rect, cov);\n rects.push(rect);\n this.bounds = union(this.bounds, rect);\n this.dabCount++;\n }\n return rects;\n }\n\n // The tile last looked up by `locate` (and whether it came from `writeTile`).\n private tx = NaN;\n private ty = NaN;\n private tile: Uint8ClampedArray | null = null;\n private writable = false;\n\n /** Index of document pixel (dx, dy) in `this.tile`, or -1 when reading an empty tile. */\n private locate(dx: number, dy: number, write: boolean): number {\n const t = this.target;\n const lx = dx - t.offset.x;\n const ly = dy - t.offset.y;\n const tx = Math.floor(lx / TILE);\n const ty = Math.floor(ly / TILE);\n if (tx !== this.tx || ty !== this.ty || (write && !this.writable)) {\n this.tx = tx;\n this.ty = ty;\n this.tile = write ? t.writeTile(tx, ty) : t.readTile(tx, ty);\n this.writable = write;\n }\n return this.tile ? ((ly - ty * TILE) * TILE + (lx - tx * TILE)) * 4 : -1;\n }\n\n private dab(d: Dab, rect: CropBox, cov: Float32Array): void {\n const { wet, mix, load } = this.settings;\n const pig = this.pig;\n const w = rect.width;\n this.tx = NaN;\n\n // 1. Sample the canvas under the dab.\n let ar = 0;\n let ag = 0;\n let ab = 0;\n let wsum = 0;\n let asum = 0;\n for (let yy = 0; yy < rect.height; yy++) {\n for (let xx = 0; xx < w; xx++) {\n const k = cov[yy * w + xx];\n if (k <= 0) continue;\n wsum += k;\n const i = this.locate(rect.x + xx, rect.y + yy, false);\n if (i < 0) continue;\n const px = this.tile!;\n const al = px[i + 3] / 255;\n if (al <= 0) continue;\n const ka = k * al;\n ar += (px[i] / 255) * ka;\n ag += (px[i + 1] / 255) * ka;\n ab += (px[i + 2] / 255) * ka;\n asum += ka;\n }\n }\n if (asum > 1e-6 && wet > 0) {\n const canvas: Rgb = [ar / asum, ag / asum, ab / asum];\n if (!this.pickup) this.pickup = canvas;\n else {\n if (pig) setPigmentColor(pig.canvas, canvas[0], canvas[1], canvas[2]);\n const o = this.mix(this.pickup, pig?.pick ?? null, canvas, pig?.canvas ?? null, MIXER_PICKUP_RATE * wet * (asum / Math.max(1e-6, wsum)));\n this.pickup = [o[0], o[1], o[2]];\n }\n if (pig) setPigmentColor(pig.pick, this.pickup[0], this.pickup[1], this.pickup[2]);\n }\n\n // 2. The dab's paint: the reservoir mixed with the pickup.\n const res = this.reservoir;\n const wr = res ? this.amount * (1 - mix * wet) : 0;\n const wp = this.pickup ? mix * wet : 0;\n const total = wr + wp;\n if (total > 1e-6) {\n const paint: Rgb = res && this.pickup ? [...this.mix(res, pig?.res ?? null, this.pickup, pig?.pick ?? null, wp / total)] : [...(res ?? this.pickup!)];\n if (pig) setPigmentColor(pig.paint, paint[0], paint[1], paint[2]);\n const dep = Math.min(1, total) * this.brush.flow * this.brush.opacity * d.opacity;\n if (dep > 0) this.deposit(rect, cov, paint, dep);\n }\n\n // 3. The reservoir drains unless the load is full.\n this.amount *= 1 - MIXER_DRAIN * (1 - load);\n }\n\n /** Lays `paint` over the pixels under the dab at `dep` × coverage (× selection). */\n private deposit(rect: CropBox, cov: Float32Array, paint: Rgb, dep: number): void {\n const t = this.target;\n const sel = t.selection;\n const pig = this.pig;\n const w = rect.width;\n const o = this.out;\n // Pigment mode keeps the last canvas colour's spectrum: runs of equal pixels are common.\n let lastKey = -1;\n for (let yy = 0; yy < rect.height; yy++) {\n const dy = rect.y + yy;\n for (let xx = 0; xx < w; xx++) {\n let k = cov[yy * w + xx] * dep;\n if (k <= 0) continue;\n const dx = rect.x + xx;\n if (sel) {\n if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;\n k *= sel.data[dy * sel.width + dx] / 255;\n if (k <= 0) continue;\n }\n if (k > 1) k = 1;\n // A locked layer keeps its transparent pixels (and leaves their tiles unwritten).\n if (t.lockTransparency) {\n const ri = this.locate(dx, dy, false);\n if (ri < 0 || this.tile![ri + 3] === 0) continue;\n }\n const i = this.locate(dx, dy, true);\n const px = this.tile!;\n const a = px[i + 3] / 255;\n const na = t.lockTransparency ? a : a + (1 - a) * k;\n // The new paint's share of the result (source-over); a locked layer mixes by `k` alone.\n const share = t.lockTransparency ? k : na > 0 ? k / na : 1;\n if (a <= 0 || share >= 1) {\n o[0] = paint[0];\n o[1] = paint[1];\n o[2] = paint[2];\n } else if (pig) {\n const key = (px[i] << 16) | (px[i + 1] << 8) | px[i + 2];\n if (key !== lastKey) {\n setPigmentColor(pig.canvas, px[i] / 255, px[i + 1] / 255, px[i + 2] / 255);\n lastKey = key;\n }\n lerpPigmentInto(pig.canvas, pig.paint, share, o, 0);\n } else {\n for (let c = 0; c < 3; c++) o[c] = px[i + c] / 255 + (paint[c] - px[i + c] / 255) * share;\n }\n px[i] = Math.round(o[0] * 255);\n px[i + 1] = Math.round(o[1] * 255);\n px[i + 2] = Math.round(o[2] * 255);\n px[i + 3] = Math.round(na * 255);\n }\n }\n }\n}\n\nfunction union(a: CropBox | null, b: CropBox): CropBox {\n if (!a) return { ...b };\n const x = Math.min(a.x, b.x);\n const y = Math.min(a.y, b.y);\n return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };\n}\n","import type { AgentTool } from '../tools/registry.js';\nimport { createPigment, mixPigments, type Pigment } from './pigment';\n\nconst HEX = /^#?([0-9a-f]{6})$/i;\n\nfunction parseHex(value: unknown, index: number): [number, number, number] {\n const m = typeof value === 'string' ? HEX.exec(value.trim()) : null;\n if (!m) throw new Error(`colors[${index}].color is ${JSON.stringify(value)}; use #rrggbb, e.g. \"#1e40af\".`);\n const n = parseInt(m[1], 16);\n return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255];\n}\n\nfunction toHex(rgb: readonly number[]): string {\n return '#' + rgb.map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Agent tools for pigment mixing (`@pixerate/editor/paint`). `mix_colors` is read-only: it\n * predicts what paints mixed in given amounts look like, for choosing a brush or fill colour.\n */\nexport function createPigmentTools(): AgentTool[] {\n const mixColors: AgentTool = {\n name: 'mix_colors',\n title: 'Mix colours like paint',\n description:\n 'Mixes colours as paint would (Kubelka-Munk pigment mixing over reflectance spectra), so blue and yellow make green and white lightens a colour into a tint instead of greying it. Changes nothing. Returns the mixed colour as #rrggbb, the plain RGB average (rgbLerp) for comparison, and the normalised weights.',\n inputSchema: {\n type: 'object',\n properties: {\n colors: {\n type: 'array',\n minItems: 1,\n maxItems: 16,\n description: 'The paints to mix (1 to 16).',\n items: {\n type: 'object',\n properties: {\n color: { type: 'string', description: 'Paint colour #rrggbb.' },\n weight: { type: 'number', minimum: 0, description: 'Parts of this paint, any scale (e.g. 1 and 3 for a 1:3 mix). At least one weight must be above 0.' },\n strength: {\n type: 'number',\n exclusiveMinimum: 0,\n maximum: 100,\n description: 'Tinting strength (default 1): each part counts as this many, so a strong dark paint (e.g. 4) tints a lot of white.',\n },\n },\n required: ['color', 'weight'],\n additionalProperties: false,\n },\n },\n },\n required: ['colors'],\n additionalProperties: false,\n },\n annotations: { title: 'Mix colours like paint', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n handler: (args) => {\n const items = args.colors as { color: string; weight: number; strength?: number }[];\n const rgbs = items.map((item, i) => parseHex(item.color, i));\n const total = items.reduce((sum, item) => sum + item.weight, 0);\n if (!(total > 0)) throw new Error('Every weight is 0; give at least one colour a weight above 0.');\n const pigments: Pigment[] = rgbs.map((rgb, i) => createPigment(rgb, { strength: items[i].strength }));\n const mixed = mixPigments(pigments, items.map((item) => item.weight));\n const lerp = [0, 1, 2].map((c) => rgbs.reduce((sum, rgb, i) => sum + rgb[c] * items[i].weight, 0) / total);\n return {\n mixed: toHex(mixed),\n rgbLerp: toHex(lerp),\n weights: items.map((item) => item.weight / total),\n model: 'kubelka-munk',\n };\n },\n };\n return [mixColors];\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- "use strict";//# sourceMappingURL=chunk-6BU5WU4R.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-6BU5WU4R.cjs"],"names":[],"mappings":"AAAA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-6BU5WU4R.cjs"}