@pixerate/editor 0.91.0 → 0.93.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.91.0",
3
+ "version": "0.93.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -186,13 +186,13 @@
186
186
  "@tiptap/pm": "^2.11.5",
187
187
  "@types/dagre": "^0.7.54",
188
188
  "@types/markdown-it": "^14.2.0",
189
- "@types/node": "^24.0.0",
189
+ "@types/node": "^26.6.5",
190
190
  "fast-check": "^3.23.2",
191
191
  "mermaid": "12.0.0",
192
192
  "tiptap-markdown": "^0.8.10",
193
193
  "tsup": "^8.4.0",
194
194
  "typescript": "^5.7.3",
195
- "vitest": "^4.1.11"
195
+ "vitest": "^5.0.5"
196
196
  },
197
197
  "peerDependencies": {
198
198
  "@dagrejs/dagre": "^1.1.8",
@@ -79,6 +79,11 @@ batching.
79
79
  4. **Limit paint with a selection** (select first, then `paint_stroke` / `fill_pixels`), or lock
80
80
  transparency (`set_layer_properties` `locks.transparency`) to paint only where the layer
81
81
  already has pixels.
82
+ 5. **Mix paint colours with `mix_colors`** when the user names paints and amounts ("two parts
83
+ ultramarine to one part yellow", "a tint of red"). It mixes like pigment, so blue and yellow
84
+ make green and white makes a tint, where averaging RGB gives grey or a dull pastel. Pass its
85
+ `mixed` hex as the `color` of `paint_stroke` or `fill_pixels`. Give a strong dark paint a
86
+ `strength` above 1 when a little of it should tint a lot of white.
82
87
 
83
88
  ### Photoshop files
84
89
 
@@ -195,6 +200,7 @@ batching.
195
200
  | `remove_layer_filter` | Remove a filter. Returns the remaining filters. |
196
201
  | `paint_stroke` | Paint (`tool` brush) or erase (`tool` eraser) along `points` in document px (optional `pressure` 0..1) on a pixel layer or its mask (`channel`); `color` #rrggbb (on a mask: black hides, white reveals); `brush` `{size, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend}`. The selection limits the paint. One undo step per call. Returns the layer, channel, changed `bounds` and dab count. |
197
202
  | `fill_pixels` | Fill the selection (or the canvas without one / with `useSelection: false`) on pixels or a mask with `color`, `opacity`, `blend`. Returns the changed bounds. |
203
+ | `mix_colors` | Read-only. Mix 1 to 16 `colors` (`{color: #rrggbb, weight, strength?}`) like paint (Kubelka-Munk over reflectance spectra). Returns `mixed` (#rrggbb), `rgbLerp` (the plain RGB average, for comparison) and the normalised `weights`. Call it before `paint_stroke` / `fill_pixels` to pick a paint colour. |
198
204
  | `clear_pixels` | Remove the selected pixels (alpha to 0; a transparency-locked layer or a mask gets the background colour). Returns the changed bounds. |
199
205
  | `import_psd` | Open a PSD / PSB (`data` base64, a `data:` URL is fine) as the document, replacing the layers, crop and rotation (one undo step). Returns the new `layers` tree with ids, `layerIds`, size and `warnings` naming the affected layers. Call `inspect_psd` first when losses matter. |
200
206
  | `apply_selection_as_mask` | Mask a layer with the current selection: pass `layerId` to mask an existing layer, or `kind` (plus optional `params`) to create a new masked layer in one step. `density` 0..1 and `feather` px soften the mask non-destructively. Returns `layerId`, kind, mask info and the selection summary. |
@@ -211,6 +217,8 @@ batching.
211
217
  - `paint_stroke`, `fill_pixels` and `clear_pixels` need a visible pixel layer (or a layer with a
212
218
  raster mask and `channel: "mask"`); adjustment, group and annotation layers can only be
213
219
  painted through their masks. A layer with `locks.pixels` refuses paint.
220
+ - `mix_colors` predicts a mix; it does not paint, and strokes still lay paint down with normal
221
+ blending (there is no pigment blend mode or mixer brush yet).
214
222
  - `export_psd` is in the source frame: a crop or rotation is not in the file (the warnings say
215
223
  so). Crop with `set_crop` only for PNG / JPEG output, or flatten the look you need first.
216
224
  - PSD opacity, fill and mask density come in as whole percents (Photoshop stores bytes), so a
@@ -13,6 +13,13 @@ timeline; a media clip also has an `in` point into its asset, `speed`, `volume`,
13
13
  every clip can have `fadeIn`, `fadeOut`, `opacity`, `fit` and `transform`, and a
14
14
  `transition` from the clip that ends where it starts on the same track.
15
15
 
16
+ A project may also hold nested **sequences** (`{ id, name, tracks }`, their own timeline from 0).
17
+ A **compound clip** (`type: "sequence"`, `sequence`, `in`) plays a stretch of one as a single
18
+ picture and a single sound: its opacity, transform, blend, grade, LUT, fades, transitions and
19
+ animations apply to the sequence's composite, and its `volume`, `muted` and fades to the
20
+ sequence's mix. Compound clips play at normal speed (no `speed` or ramp), and the clips inside a
21
+ sequence can be read (`list_video_sequences`) but not edited yet.
22
+
16
23
  All times are milliseconds on the timeline (or into the source for `in`). Ids: tracks look
17
24
  like `v1` / `a1`, clips like `c1`, markers `m1`; you may set your own ids when adding. Read
18
25
  them from `get_video_project`; never invent them.
@@ -22,7 +29,8 @@ For errors, namespaced tool names and undo conventions, see `pixerate-agent-tool
22
29
  ## Working method
23
30
 
24
31
  1. **Read.** `get_video_project` for settings, assets, tracks, clips (with end and source
25
- range), markers and issues. Set frame size and `fps` first with `set_video_settings` if
32
+ range), a summary of each nested sequence, markers and issues. When there are compound
33
+ clips, `list_video_sequences` shows what they contain. Set frame size and `fps` first with `set_video_settings` if
26
34
  the project is new; changing them later shifts frame-based limits.
27
35
  2. **Bring in media.** `add_video_asset` for each file with `kind`, `src` and the source
28
36
  `duration` (without it trims cannot be checked and `check_video_project` warns
@@ -156,8 +164,9 @@ For errors, namespaced tool names and undo conventions, see `pixerate-agent-tool
156
164
 
157
165
  | Tool | Use it to |
158
166
  | --- | --- |
159
- | `get_video_project` | Start here. Returns frame size, fps, length (ms), assets (id, kind, src, duration), tracks top to bottom with each clip in time order (id, type, start, duration, end, source in/out, fades, transition), markers, playhead, selection, issues and whether it can be edited. |
160
- | `get_video_frame` | Inspect a `time` (ms) as data: pictures back to front (clip, track, asset, source time, opacity, placement rect, rotation, wipe) and sounds (clip, source time, gain after volumes, fades and transitions). Use to verify a cut, layer order or J/L cut without images. |
167
+ | `get_video_project` | Start here. Returns frame size, fps, length (ms), assets (id, kind, src, duration), tracks top to bottom with each clip in time order (id, type, start, duration, end, source in/out, fades, transition), a summary of each nested sequence (`sequences`: id, length, clip count, `nests`, `usedBy`), markers, playhead, selection, issues and whether it can be edited. |
168
+ | `list_video_sequences` | Read the nested sequences compound clips play (or one `sequence`): length, the sequences each nests, `usedBy` (the compound clips that play it, with timeline start / end and the stretch of the sequence as `source`), any `cycle`, and its tracks and clips in the `get_video_project` shape. Call it before trimming, slipping or grading a compound clip, to know what it holds. |
169
+ | `get_video_frame` | Inspect a `time` (ms) as data: pictures back to front (clip, track, asset, source time, opacity, placement rect, rotation, wipe) and sounds (clip, source time, gain after volumes, fades and transitions). A compound clip is one picture whose `layers` are its sequence's, with `sourceTime` in sequence time; its sounds carry clip paths like `comp/inner`. Use to verify a cut, layer order or J/L cut without images. |
161
170
  | `get_video_transcript` | Read what the timeline says on one `track` (default: the first audio track with transcribed media): the text, and each word with its timeline `start` / `end` ms and `clip`. `from` / `to` narrow it; `limit` (default 1000) with `more`. Words cut out of the edit are not listed. |
162
171
  | `find_video_transcript_text` | Find every place a word or phrase (`query`, case and punctuation ignored) is said, as `{ from, to, text }` timeline ranges for `remove_video_ranges`, `split_video_at` or `seek_video`. |
163
172
  | `find_video_fillers` | Find filler words (um, uh, erm, you know, I mean…; or your own `fillers`) as timeline ranges, longest phrase first, with their `total` ms. Review before cutting. |
@@ -255,6 +264,16 @@ For errors, namespaced tool names and undo conventions, see `pixerate-agent-tool
255
264
  affect picture and sound together. Fade curves shape only the sound (media clips); the picture
256
265
  always fades linearly. Splitting keeps the fade-in curve on the left part and the fade-out
257
266
  curve on the right.
267
+ - **Compound clips are one picture.** A grade, blend or opacity on a compound changes the
268
+ sequence's composite, not each clip in it, so a multiply on a compound multiplies the whole
269
+ nested frame over what is beneath (and leaves its transparent parts untouched). Trimming,
270
+ splitting and slipping a compound move its `in` through the sequence; it can never play past
271
+ the sequence's end (`source-overrun`), a transition into it needs sequence time either side of
272
+ the cut like media handles, and `speed` or a ramp on it is refused. A compound whose sequence
273
+ is missing (`missing-sequence`) or contains itself (`sequence-cycle`) plays nothing.
274
+ - **Clips inside sequences are read-only for now.** Write tools refuse a clip id inside a
275
+ sequence with a message naming it; change the compound clip instead. The EDL lists a compound
276
+ as a black event with a `* COMPOUND CLIP` comment (CMX 3600 has no nesting).
258
277
  - **Locked tracks** refuse edits to their clips; unlock with `update_video_track` only if the user
259
278
  wants that track changed.
260
279
  - **Read-only**: when `get_video_project` says the project cannot be edited, write tools are
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-PDCITYBT.cjs","../src/paint/brush.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-PDCITYBT.cjs","sourcesContent":[null,"// 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, 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 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"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/paint/brush.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, 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 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"],"mappings":"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","names":[]}