@pixerate/editor 0.115.0 → 0.117.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 (127) hide show
  1. package/THIRD_PARTY_NOTICES.md +3 -0
  2. package/dist/animation-editor/index.cjs +54 -54
  3. package/dist/animation-editor/index.d.cts +2 -2
  4. package/dist/animation-editor/index.d.ts +2 -2
  5. package/dist/animation-editor/index.js +2 -2
  6. package/dist/{chunk-I7FQBWMQ.cjs → chunk-2J3LS7JZ.cjs} +333 -333
  7. package/dist/{chunk-I7FQBWMQ.cjs.map → chunk-2J3LS7JZ.cjs.map} +1 -1
  8. package/dist/{chunk-TFOPHZ3U.cjs → chunk-7ISPWEJA.cjs} +302 -5
  9. package/dist/chunk-7ISPWEJA.cjs.map +1 -0
  10. package/dist/{chunk-VXR7XWMF.js → chunk-7LNZAWSJ.js} +437 -41
  11. package/dist/chunk-7LNZAWSJ.js.map +1 -0
  12. package/dist/{chunk-DFQEX3AM.cjs → chunk-BYAWOAST.cjs} +223 -30
  13. package/dist/chunk-BYAWOAST.cjs.map +1 -0
  14. package/dist/chunk-COAMRKVI.cjs +159 -0
  15. package/dist/chunk-COAMRKVI.cjs.map +1 -0
  16. package/dist/{chunk-ST7E3NEE.cjs → chunk-EBSYZRSW.cjs} +230 -732
  17. package/dist/chunk-EBSYZRSW.cjs.map +1 -0
  18. package/dist/chunk-EJVDBITD.cjs +501 -0
  19. package/dist/chunk-EJVDBITD.cjs.map +1 -0
  20. package/dist/{chunk-LPLCWZTM.cjs → chunk-FODKPD44.cjs} +555 -159
  21. package/dist/chunk-FODKPD44.cjs.map +1 -0
  22. package/dist/{chunk-XK5LZKBD.js → chunk-HKDTM6VC.js} +298 -1
  23. package/dist/chunk-HKDTM6VC.js.map +1 -0
  24. package/dist/chunk-IPFRWILU.js +1908 -0
  25. package/dist/chunk-IPFRWILU.js.map +1 -0
  26. package/dist/chunk-IVSNUXW7.js +3339 -0
  27. package/dist/chunk-IVSNUXW7.js.map +1 -0
  28. package/dist/{chunk-LKCYANMW.js → chunk-JHXMNOMF.js} +198 -5
  29. package/dist/chunk-JHXMNOMF.js.map +1 -0
  30. package/dist/{chunk-FV5AXTSF.cjs → chunk-JSSBHMMU.cjs} +36 -188
  31. package/dist/chunk-JSSBHMMU.cjs.map +1 -0
  32. package/dist/chunk-L2T6EJ5S.cjs +3339 -0
  33. package/dist/chunk-L2T6EJ5S.cjs.map +1 -0
  34. package/dist/chunk-LF4WOZXZ.js +159 -0
  35. package/dist/chunk-LF4WOZXZ.js.map +1 -0
  36. package/dist/{chunk-26PGXHY7.cjs → chunk-M7O4BJRH.cjs} +36 -36
  37. package/dist/{chunk-26PGXHY7.cjs.map → chunk-M7O4BJRH.cjs.map} +1 -1
  38. package/dist/chunk-N3467VD6.js +501 -0
  39. package/dist/chunk-N3467VD6.js.map +1 -0
  40. package/dist/{chunk-XICA4PVO.js → chunk-R2JE6SA7.js} +17 -17
  41. package/dist/chunk-SMJGE7HM.cjs +1908 -0
  42. package/dist/chunk-SMJGE7HM.cjs.map +1 -0
  43. package/dist/{chunk-MMVHBKMM.js → chunk-T2P5TIZ6.js} +2 -2
  44. package/dist/{chunk-C6C5PDKU.js → chunk-VD2UDVF7.js} +102 -604
  45. package/dist/chunk-VD2UDVF7.js.map +1 -0
  46. package/dist/{chunk-FGW5OWJ4.js → chunk-VJUML33I.js} +4 -156
  47. package/dist/chunk-VJUML33I.js.map +1 -0
  48. package/dist/export/index.cjs +4 -2
  49. package/dist/export/index.cjs.map +1 -1
  50. package/dist/export/index.js +5 -3
  51. package/dist/{export-BJE8T0YA.d.cts → export-DMOuzgZZ.d.cts} +9 -4
  52. package/dist/{export-Con3UKkm.d.ts → export-Dul1SbPv.d.ts} +9 -4
  53. package/dist/export-Dv0-ZVrV.d.cts +501 -0
  54. package/dist/export-Dv0-ZVrV.d.ts +501 -0
  55. package/dist/{retouch-Bxkuc0KH.d.cts → flow-4-OC-UkQ.d.cts} +582 -2
  56. package/dist/{retouch-Do6tBs2H.d.ts → flow-Cb7lkPm8.d.ts} +582 -2
  57. package/dist/image-editor/index.cjs +1345 -1095
  58. package/dist/image-editor/index.cjs.map +1 -1
  59. package/dist/image-editor/index.d.cts +8 -8
  60. package/dist/image-editor/index.d.ts +8 -8
  61. package/dist/image-editor/index.js +300 -50
  62. package/dist/image-editor/index.js.map +1 -1
  63. package/dist/index.cjs +4 -2
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.js +5 -3
  66. package/dist/index.js.map +1 -1
  67. package/dist/kernel-wasm-WYCGNZR4.js +10 -0
  68. package/dist/kernel-wasm-WYCGNZR4.js.map +1 -0
  69. package/dist/kernel-wasm-YPVAEMVN.cjs +10 -0
  70. package/dist/kernel-wasm-YPVAEMVN.cjs.map +1 -0
  71. package/dist/paint/index.cjs +170 -4
  72. package/dist/paint/index.cjs.map +1 -1
  73. package/dist/paint/index.d.cts +225 -3
  74. package/dist/paint/index.d.ts +225 -3
  75. package/dist/paint/index.js +171 -5
  76. package/dist/paint-editor/index.cjs +4735 -890
  77. package/dist/paint-editor/index.cjs.map +1 -1
  78. package/dist/paint-editor/index.d.cts +1526 -278
  79. package/dist/paint-editor/index.d.ts +1526 -278
  80. package/dist/paint-editor/index.js +4561 -716
  81. package/dist/paint-editor/index.js.map +1 -1
  82. package/dist/raster/index.cjs +7 -4
  83. package/dist/raster/index.cjs.map +1 -1
  84. package/dist/raster/index.d.cts +2 -2
  85. package/dist/raster/index.d.ts +2 -2
  86. package/dist/raster/index.js +36 -33
  87. package/dist/{render-CrmHOgpo.d.ts → render-B05K68_h.d.ts} +9 -1
  88. package/dist/{render-B1K_OoLy.d.cts → render-DnAbIKcs.d.cts} +9 -1
  89. package/dist/{svg-BnRj0q8i.d.cts → svg-CVdFc80-.d.cts} +2 -2
  90. package/dist/{svg-CmmBFfGT.d.ts → svg-DlEuhwoX.d.ts} +2 -2
  91. package/dist/{types-1SUQKDAw.d.ts → types-CDLGhAZp.d.ts} +40 -2
  92. package/dist/{types-yINF17Ta.d.cts → types-Tfly4Aya.d.cts} +40 -2
  93. package/dist/vector/index.cjs +6536 -4525
  94. package/dist/vector/index.cjs.map +1 -1
  95. package/dist/vector/index.d.cts +426 -32
  96. package/dist/vector/index.d.ts +426 -32
  97. package/dist/vector/index.js +11397 -9386
  98. package/dist/vector/index.js.map +1 -1
  99. package/dist/video-editor/index.cjs +502 -2165
  100. package/dist/video-editor/index.cjs.map +1 -1
  101. package/dist/video-editor/index.d.cts +3 -501
  102. package/dist/video-editor/index.d.ts +3 -501
  103. package/dist/video-editor/index.js +151 -1814
  104. package/dist/video-editor/index.js.map +1 -1
  105. package/package.json +1 -1
  106. package/skills/pixerate-image-editor/references/photoshop-files.md +7 -3
  107. package/skills/pixerate-vector/SKILL.md +3 -0
  108. package/dist/chunk-C6C5PDKU.js.map +0 -1
  109. package/dist/chunk-DFQEX3AM.cjs.map +0 -1
  110. package/dist/chunk-FGW5OWJ4.js.map +0 -1
  111. package/dist/chunk-FV5AXTSF.cjs.map +0 -1
  112. package/dist/chunk-GX332W2C.js +0 -181
  113. package/dist/chunk-GX332W2C.js.map +0 -1
  114. package/dist/chunk-LKCYANMW.js.map +0 -1
  115. package/dist/chunk-LPLCWZTM.cjs.map +0 -1
  116. package/dist/chunk-MUUXNRU4.cjs +0 -181
  117. package/dist/chunk-MUUXNRU4.cjs.map +0 -1
  118. package/dist/chunk-ST7E3NEE.cjs.map +0 -1
  119. package/dist/chunk-TCKIXI46.cjs +0 -1136
  120. package/dist/chunk-TCKIXI46.cjs.map +0 -1
  121. package/dist/chunk-TFOPHZ3U.cjs.map +0 -1
  122. package/dist/chunk-UBIXVXPR.js +0 -1136
  123. package/dist/chunk-UBIXVXPR.js.map +0 -1
  124. package/dist/chunk-VXR7XWMF.js.map +0 -1
  125. package/dist/chunk-XK5LZKBD.js.map +0 -1
  126. /package/dist/{chunk-XICA4PVO.js.map → chunk-R2JE6SA7.js.map} +0 -0
  127. /package/dist/{chunk-MMVHBKMM.js.map → chunk-T2P5TIZ6.js.map} +0 -0
@@ -1,5 +1,7 @@
1
- export { m as BlenderScratch, b as BlenderSettings, B as BrushSettings, C as CoverageMap, n as DEFAULT_BLENDER, o as DEFAULT_BRUSH, p as DEFAULT_MIXER, q as DEFAULT_RETOUCH, r as DEFAULT_SMUDGE, D as Dab, s as DabWalker, E as EMPTY_MIXER_LOAD, t as ExchangeRates, e as MAX_BRUSH_SIZE, u as MIXER_DRAIN, v as MIXER_PICKUP_RATE, w as MIXING_MODELS, d as MixerLoad, M as MixerSettings, i as MixerStroke, h as MixerTarget, a as MixingModel, x as PaintExchange, y as PaintMedium, z as PaintSample, P as PaintTileTarget, A as PixelSource, F as RETOUCH_SAMPLES, G as RegionPixelSource, j as RetouchApply, H as RetouchDabEffect, I as RetouchDabStroke, k as RetouchPaint, J as RetouchSample, f as RetouchSettings, R as RgbTriple, K as SPOT_HEAL_TYPES, L as SmudgeDab, S as SmudgeSettings, N as SmudgeTip, O as SpotHealType, l as StrokeApply, g as StrokeCoverage, c as StrokePoint, T as TONE_RANGES, Q as TileMedium, U as TileMediumOptions, V as TilePixelSource, W as ToneRange, X as applyRetouchToTile, Y as applyStrokeToTile, Z as blendRadius, _ as blenderDab, $ as cleanMixer, a0 as coverageTileCoord, a1 as createBlenderScratch, a2 as dabCoverage, a3 as dabRect, a4 as dodgeBurn, a5 as dodgeBurnCurve, a6 as exchangeRates, a7 as healPixels, a8 as loadMixer, a9 as luma, aa as mixerRates, ab as normalizeBlender, ac as normalizeBrush, ad as normalizeMixer, ae as normalizeRetouch, af as normalizeSmudge, ag as perDabStrength, ah as rasterizeDab, ai as readSourceRegion, aj as rgbaViewOfGrey, ak as saturationOf, al as smoothPoints, am as smudgeEffect, an as sponge, ao as spongeEffect, ap as spotHealPixels, aq as spotHealWindow, ar as tipFalloff, as as tipReach, at as tipShape, au as toneOf, av as walkDabs } from '../retouch-Bxkuc0KH.cjs';
2
- export { Z as PIGMENT_BANDS, _ as PIGMENT_LAMBDA_MIN, $ as PIGMENT_LAMBDA_STEP, a0 as PIGMENT_WAVELENGTHS, Y as Pigment, a1 as PigmentOptions, a2 as PigmentRgb, a3 as createPigment, a4 as lerpPigment, a5 as lerpPigmentInto, a6 as mixPigments, a7 as reflectanceToRgb, a8 as rgbToReflectance, a9 as setPigmentColor } from '../surface-Cn30xIV6.cjs';
1
+ import { at as PaintMedium, W as WetWorld, au as PaintSample, n as RgbTriple, B as BrushSettings, C as CoverageMap, D as Dab } from '../flow-4-OC-UkQ.cjs';
2
+ export { F as BlenderScratch, i as BlenderSettings, G as DEFAULT_BLENDER, H as DEFAULT_BRUSH, s as DEFAULT_FLOW, I as DEFAULT_MIXER, J as DEFAULT_RETOUCH, K as DEFAULT_SMUDGE, L as DEFAULT_WET_PAPER, t as DEFAULT_WET_PARAMS, N as DRY_EPS, O as DabWalker, Q as EMPTY_MIXER_LOAD, U as EX, V as EY, X as ExchangeRates, Y as FLAG_ALIVE, Z as FLAG_BOTTOM, _ as FLAG_LEFT, $ as FLAG_RIGHT, a0 as FLAG_TOP, a1 as FLAG_WET, a2 as FLAT, a3 as FREE_INTERVAL, a4 as MAX_BATCH, u as MAX_BRUSH_SIZE, a5 as MAX_TILT_ACCEL, a6 as MAX_WET_LANES, a7 as MAX_WET_SLOTS, a8 as MIXER_DRAIN, a9 as MIXER_PICKUP_RATE, aa as MIXING_MODELS, a as MixerLoad, M as MixerSettings, c as MixerStroke, b as MixerTarget, h as MixingModel, ab as OPP, ac as PAPER_CAPACITY, ad as PARAM, ae as PARAM_FLOATS, af as PIGMENT_CHANNELS, ag as PLANE, ah as PLANE_BYTES, ai as P_D0, aj as P_EDGE, ak as P_FX, al as P_FY, am as P_H, an as P_P0, ao as P_RHO, ap as P_SW, aq as P_UX, ar as P_UY, as as PaintExchange, P as PaintTileTarget, av as PixelSource, aw as RETOUCH_SAMPLES, ax as RegionPixelSource, d as RetouchApply, ay as RetouchDabEffect, az as RetouchDabStroke, f as RetouchPaint, aA as RetouchSample, R as RetouchSettings, aB as SET_PLANES, aC as SLOT_BYTES, aD as SLOT_PLANES, aE as SLOT_SIDE, aF as SPOT_HEAL_TYPES, aG as STRIP, aH as SmudgeDab, j as SmudgeSettings, aI as SmudgeTip, aJ as SpotHealType, g as StrokeApply, S as StrokeCoverage, e as StrokePoint, aK as TONE_RANGES, T as TileMedium, aL as TileMediumOptions, aM as TilePixelSource, aN as ToneRange, aO as U_MAX, aP as W9, v as WET_FLOW_KINDS, w as WET_PARAM_KEYS, aQ as WET_TILE, p as WetBackendInfo, aR as WetFlowField, x as WetFlowKind, m as WetFlowSpec, aS as WetKernelKind, aT as WetLaneOptions, aU as WetLaneStats, aV as WetPaper, r as WetPaperInput, l as WetParams, q as WetSnapshot, y as WetSupport, k as WetTilt, aW as WetWorkerLayout, aX as WetWorkerPool, aY as WetWorldError, o as WetWorldOptions, aZ as applyRetouchToTile, a_ as applyStrokeToDeepTile, a$ as applyStrokeToTile, b0 as applyToneToDeepTile, b1 as blendRadius, b2 as blenderDab, b3 as canShareMemory, b4 as cleanMixer, b5 as coverageTileCoord, b6 as createBlenderScratch, b7 as dabCoverage, b8 as dabRect, b9 as dodgeBurn, ba as dodgeBurnCurve, bb as dsincos, bc as edgeBits, bd as exchangeRates, be as flowField, bf as healPixels, bg as latticeViscosity, bh as loadMixer, bi as loadWetKernel, bj as luma, bk as mixerRates, bl as normalizeBlender, bm as normalizeBrush, z as normalizeFlow, bn as normalizeMixer, bo as normalizeRetouch, bp as normalizeSmudge, bq as normalizeTilt, A as normalizeWetParams, br as packWetParams, bs as perDabStrength, bt as rasterizeDab, bu as readSourceRegion, bv as rgbaViewOfGrey, bw as saturationOf, bx as smoothPoints, by as smudgeEffect, bz as sponge, bA as spongeEffect, bB as spotHealPixels, bC as spotHealWindow, bD as tipFalloff, bE as tipReach, bF as tipShape, bG as toneOf, bH as walkDabs, bI as wetSimdSupported, E as wetSupport } from '../flow-4-OC-UkQ.cjs';
3
+ import { R as RasterRect, Y as Pigment, a as BlendMode, j as TiledSurface } from '../surface-Cn30xIV6.cjs';
4
+ export { Z as PIGMENT_BANDS, _ as PIGMENT_LAMBDA_MIN, $ as PIGMENT_LAMBDA_STEP, a0 as PIGMENT_WAVELENGTHS, a1 as PigmentOptions, a2 as PigmentRgb, a3 as createPigment, a4 as lerpPigment, a5 as lerpPigmentInto, a6 as mixPigments, a7 as reflectanceToRgb, a8 as rgbToReflectance, a9 as setPigmentColor } from '../surface-Cn30xIV6.cjs';
3
5
  import { A as AgentTool } from '../registry-BqA1AZt0.cjs';
4
6
  import '../schema-Di0CS6Pe.cjs';
5
7
 
@@ -36,4 +38,224 @@ declare function maskBounds(w: number, h: number, mask: ArrayLike<boolean | numb
36
38
  */
37
39
  declare function bestOffset(w: number, h: number, ch: number, img: ArrayLike<number>, hole: ArrayLike<boolean | number>, ring: number, maxRadius: number): [number, number] | null;
38
40
 
39
- export { bestOffset, createPigmentTools, dilateMask, maskBounds, membraneFill, seamlessClone, solveMembrane };
41
+ /**
42
+ * How wet-layer pigment looks, and how it bakes into 8-bit pixels.
43
+ *
44
+ * A cell carries pigment as Kubelka-Munk absorption `K` per channel (linear R, G, B) and one
45
+ * scattering `S`, in mass units where `PIGMENT_UNIT` of a colour's pigment is a full-strength wash.
46
+ * Over what is below it (`below`, linear), the film reflects
47
+ *
48
+ * film = hide·R∞ + (1 − hide)·T·below, T = e^(−2K), hide = 1 − e^(−HIDE·S),
49
+ * R∞ = 1 + K/S − √((K/S)² + 2·K/S) (the shipped pigment model's two-flux formula)
50
+ *
51
+ * so transparent washes (S ≈ 0) multiply like glazes and opaque paint (gouache, oil) hides.
52
+ *
53
+ * The bake is a pure function of the f32 state and the 8-bit pixels, computed with deterministic
54
+ * maths only (`dexp`, `dlog`, `sqrt`, + − × ÷ in f64; never `Math.exp` / `Math.pow`, whose last
55
+ * bits differ between JavaScript engines), so "dry on save" gives the same pixels everywhere.
56
+ * The layer pixel is the film expressed as colour plus alpha over the paper colour (exact over the
57
+ * paper, a normal-blend approximation over other layers), with alpha never below the pixel's own.
58
+ */
59
+ /** Pigment mass of a full-strength wash of a colour. */
60
+ declare const PIGMENT_UNIT = 0.25;
61
+ /** Hiding per unit of scattering. */
62
+ declare const HIDE = 1.5;
63
+ /** Scattering of fully opaque paint (`body` 1), per `PIGMENT_UNIT` of mass. */
64
+ declare const BODY_SCATTER = 3;
65
+ /**
66
+ * e^x with + − × ÷ only: x = k·ln2 + r with |r| ≤ ln2/2, then a degree-11 Taylor polynomial
67
+ * (error below 1e-15). The same bits in every JavaScript engine.
68
+ */
69
+ declare function dexp(x: number): number;
70
+ /** ln x for x > 0 with + − × ÷ only: x = m·2^e, ln m by the atanh series. */
71
+ declare function dlog(x: number): number;
72
+ /** x^y for x ≥ 0, deterministically. */
73
+ declare function dpow(x: number, y: number): number;
74
+ /** sRGB byte → linear. */
75
+ declare const SRGB_TO_LINEAR: Float64Array<ArrayBuffer>;
76
+ /** sRGB value 0..255 (not necessarily whole) → linear, interpolating the byte table. */
77
+ declare function srgbByteToLinear(v: number): number;
78
+ /** Linear 0..1 → sRGB byte (16384-step table). */
79
+ declare function linearToSrgb8(v: number): number;
80
+ /**
81
+ * The pigment (K r, g, b, S per unit of mass) of an sRGB colour (0..1) at `body` 0 (a transparent
82
+ * watercolour: K = −ln R / 2 so a full wash over white shows the colour) .. 1 (opaque paint:
83
+ * `K/S = (1 − R)² / 2R` at `BODY_SCATTER`).
84
+ */
85
+ declare function pigmentOf(rgb: readonly [number, number, number] | readonly number[], body: number, out?: Float64Array | number[]): Float64Array | number[];
86
+ /** e^(−x) for x ≥ 0 (deterministic: a table built with `dexp`, interpolated with + − ×). */
87
+ declare function expNeg(x: number): number;
88
+ /** Linear reflectance of a film of pigment `k` (3) and `s` over `below` (linear) into `out`. */
89
+ declare function filmReflectance(k0: number, k1: number, k2: number, s: number, b0: number, b1: number, b2: number, out: Float64Array | number[]): void;
90
+ /** The sRGB colour (0..1) of pigment `k`, `s` over white: what a brush picking it up sees. */
91
+ declare function pigmentColor(k0: number, k1: number, k2: number, s: number, out?: number[]): number[];
92
+ /**
93
+ * Bakes one pixel: pigment `k0..k2`, `s` laid over layer pixel `px[i..i+3]` (straight sRGB) on paper
94
+ * `paper` (sRGB bytes). `wet` (0..1) darkens wet paper slightly (display only; 0 for a bake).
95
+ * Writes the new layer pixel into `out[o..o+3]`.
96
+ */
97
+ declare function filmPixel(k0: number, k1: number, k2: number, s: number, px: ArrayLike<number>, i: number, paper: ArrayLike<number>, wet: number, out: Uint8ClampedArray, o: number): void;
98
+ /**
99
+ * The pigment a layer pixel holds over the paper, as a transparent film (`K = −ln(below/paper)/2`,
100
+ * `S` 0): what re-wetting lifts back into the water. Writes K r, g, b, S into `out`.
101
+ */
102
+ declare function pixelPigment(px: ArrayLike<number>, i: number, paper: ArrayLike<number>, out: Float64Array | number[]): void;
103
+ /**
104
+ * `filmPixel` over a whole tile, specialised for speed (same results, pixel for pixel). Reads the
105
+ * slot's planes from `f`: settled pigment at `d` (4 planes, `plane` floats apart), suspended pigment
106
+ * at `p` (or −1 to leave it out), surface and paper water at `rho` / `sw` (or −1: no wet darkening).
107
+ * Cell (x, y) of the tile is at offset `(y + 1)·side + x + 1` of each plane. `src` is the base tile
108
+ * (or `null` for transparent); writes `out` (a copy of `src` where nothing changes). Returns
109
+ * whether any pixel was shaded.
110
+ */
111
+ declare function shadeTile(f: Float32Array, plane: number, side: number, d: number, p: number, rho: number, sw: number, src: Uint8ClampedArray | null, out: Uint8ClampedArray, w: number, h: number, paper: Uint8Array): boolean;
112
+
113
+ /**
114
+ * One wet-media step for the 256 × 256 interior of a tile slot, in plain TypeScript: the
115
+ * specification of the model. Every intermediate is rounded to f32 (`F`) in the same order as the
116
+ * WebAssembly SIMD kernel (`assembly/wet.ts`), so the two give identical bits: computing an f32
117
+ * `+ − × ÷ √` in f64 and rounding once is exactly the f32 operation. Keep the two in step; the
118
+ * kernel test compares them bit for bit.
119
+ *
120
+ * A slot is `SLOT_PLANES` planes of 258 × 258 f32 (the tile plus a one-cell halo, filled from the
121
+ * neighbouring slots after each step). The step reads set `parity` (and the single planes) and
122
+ * writes the interior of the other set, the deposit planes in place, and returns the tile's flags.
123
+ *
124
+ * Per cell x:
125
+ * 1. Streaming with partial bounce-back: for each direction i, the source is n = x − eᵢ and the
126
+ * blocking is b = max(κ(x), κ(n)), κ = blockScale·h. b = 1 off the canvas (h < 0) and where the
127
+ * front is pinned: one side dry and the other shallower than the pin threshold
128
+ * (pinT + rough·h)·(1 − paperWater/capacity) of the dry side, so damp paper does not pin.
129
+ * Off-canvas cells (h < 0, in the halo or past a canvas edge inside a tile) only bounce back.
130
+ * Symmetric in x and n, so water is conserved: fᵢ(x) = (1 − b)·f*ᵢ(n) + b·f*ₒₚₚ₍ᵢ₎(x).
131
+ * 2. Depth and velocity; tilt plus the flow map shift the velocity (u += τ·g), capped at U_MAX.
132
+ * 3. Absorption into the paper until it holds its capacity, and evaporation (faster in the edge
133
+ * band); the collided populations are scaled by the depth ratio.
134
+ * 4. BGK collision towards the D2Q9 equilibrium.
135
+ * 5. Pigment (4 channels): upwind flux through the 4 faces with the previous step's velocities,
136
+ * plus bleed (diffusion) between wet cells; never below 0.
137
+ * 6. Deposition (more in valleys and in the edge band) and pickup (more where water arrives);
138
+ * where a cell dries, all its suspended pigment settles.
139
+ * 7. The edge field: max(dry neighbours / 4, 0.99 × the mean of the 4 neighbours' edge), at most
140
+ * 1, and 0 where the cell is dry.
141
+ */
142
+ /**
143
+ * Steps one slot. `f` views the whole memory; `base` is the slot's first float; `prm` is the
144
+ * lane's packed parameters (`packWetParams`). Returns the tile's flag bits.
145
+ */
146
+ declare function stepSlotTs(f: Float32Array, base: number, parity: number, prm: Float32Array): number;
147
+
148
+ /**
149
+ * The wet layer as a `PaintMedium`: the canvas side of the shared pick-up / mix exchange
150
+ * (`PaintExchange`), so wet brushes pick up and mix paint the same way the Mixer Brush and the
151
+ * phase 2 dab brushes do.
152
+ *
153
+ * - `sample` sees only wet paint (pigment still suspended in surface water): what a brush can
154
+ * lift. Its colour is the suspended pigment's hue at full strength; contact is how much of the
155
+ * footprint is wet with pigment in it.
156
+ * - `deposit` lays water and pigment: the colour becomes Kubelka-Munk pigment (`pigmentOf` at the
157
+ * brush's body), at `mass` per unit of coverage, with `water` depth.
158
+ */
159
+
160
+ interface WetMediumOptions {
161
+ /** Water depth laid per unit of coverage (at deposit weight 1). */
162
+ water: number;
163
+ /** Pigment mass laid per unit of coverage (at deposit weight 1). */
164
+ mass: number;
165
+ /** 0 transparent watercolour .. 1 opaque gouache. */
166
+ body: number;
167
+ }
168
+ declare class WetMedium implements PaintMedium {
169
+ readonly world: WetWorld;
170
+ readonly laneId: string;
171
+ options: WetMediumOptions;
172
+ private readonly pig;
173
+ constructor(world: WetWorld, laneId: string, options: WetMediumOptions);
174
+ sample(rect: RasterRect, cov: ArrayLike<number>): PaintSample | null;
175
+ deposit(rect: RasterRect, cov: ArrayLike<number>, dep: number, paint: Readonly<RgbTriple>, _pigment: Pigment | null, field?: Float32Array | null): void;
176
+ }
177
+
178
+ /**
179
+ * A brush stroke along a path: polyline samples, each with an optional pressure and pen tilt, are
180
+ * walked at the brush's spacing (pressure and tilt interpolated between samples) into dabs, built
181
+ * up in a coverage map and composited onto a layer. This is what a vector editor calls to draw a
182
+ * path with a natural-media brush ("brushstrokes on vector paths"): the path is the data, the
183
+ * pixels are rendered from it.
184
+ *
185
+ * - Pressure scales size and / or opacity as the brush says.
186
+ * - Tilt (`tiltX` / `tiltY` in degrees, or `altitude` / `azimuth` in radians, as Pointer Events give
187
+ * them) widens the tip (`tilt.size`), flattens it along the lean (`tilt.roundness`), and with
188
+ * `tilt.followAzimuth` turns the tip to the lean, as a pen laid on its side does.
189
+ * - With `followPath` the tip turns with the path (a calligraphic nib along a curve).
190
+ *
191
+ * Deterministic and DOM-free: the same samples and brush give the same pixels everywhere.
192
+ */
193
+
194
+ /** One sample of the path (document pixels). */
195
+ interface PathSample {
196
+ x: number;
197
+ y: number;
198
+ /** 0..1 (default 1). */
199
+ pressure?: number;
200
+ /** Pointer Events tilt in degrees (−90..90). */
201
+ tiltX?: number;
202
+ tiltY?: number;
203
+ /** Radians above the surface (π/2 upright); overrides tiltX / tiltY. */
204
+ altitude?: number;
205
+ /** Radians clockwise from +x: where the pen leans (with altitude). */
206
+ azimuth?: number;
207
+ }
208
+ interface PathStrokeOptions {
209
+ brush: Partial<BrushSettings>;
210
+ /** How tilt shapes the tip (each 0..1; default none). */
211
+ tilt?: {
212
+ size?: number;
213
+ roundness?: number;
214
+ followAzimuth?: boolean;
215
+ };
216
+ /** Turn the tip with the direction of the path (added to the brush angle). */
217
+ followPath?: boolean;
218
+ /** Size at zero pressure as a fraction of the full size, when pressure controls size (default 0). */
219
+ minSize?: number;
220
+ /** Join the last sample back to the first. */
221
+ closed?: boolean;
222
+ }
223
+ /** The dabs of a brush stroke along `samples`, with pressure and tilt interpolated between them. */
224
+ declare function pathStrokeDabs(samples: readonly PathSample[], options: PathStrokeOptions): Dab[];
225
+ /** The coverage of a brush stroke along `samples` (build-up towards each dab's opacity) and its bounds. */
226
+ declare function pathStrokeCoverage(samples: readonly PathSample[], options: PathStrokeOptions): {
227
+ coverage: CoverageMap;
228
+ bounds: RasterRect | null;
229
+ dabs: number;
230
+ };
231
+ interface PaintPathOptions extends PathStrokeOptions {
232
+ /** RGBA 0..255 of the paint. */
233
+ color: readonly [number, number, number, number];
234
+ /** `erase` removes paint instead (default `paint`). */
235
+ mode?: 'paint' | 'erase';
236
+ /** Blend mode (default the brush's). */
237
+ blend?: BlendMode;
238
+ /** Layer offset: layer pixel = document pixel − offset (default 0, 0). */
239
+ offset?: {
240
+ x: number;
241
+ y: number;
242
+ };
243
+ lockTransparency?: boolean;
244
+ /** Where paint may land (canvas-sized coverage 0..255), or none. */
245
+ selection?: {
246
+ width: number;
247
+ height: number;
248
+ data: ArrayLike<number>;
249
+ } | null;
250
+ }
251
+ /**
252
+ * Paints a brush stroke along `samples` onto an RGBA layer surface and returns the new surface
253
+ * (the input is not changed; untouched tiles are shared) with the bounds it touched.
254
+ */
255
+ declare function paintPathStroke(surface: TiledSurface, samples: readonly PathSample[], options: PaintPathOptions): {
256
+ surface: TiledSurface;
257
+ bounds: RasterRect | null;
258
+ dabs: number;
259
+ };
260
+
261
+ export { BODY_SCATTER, BrushSettings, CoverageMap, Dab, HIDE, PIGMENT_UNIT, PaintMedium, type PaintPathOptions, PaintSample, type PathSample, type PathStrokeOptions, Pigment, RgbTriple, SRGB_TO_LINEAR, WetMedium, type WetMediumOptions, WetWorld, bestOffset, createPigmentTools, dexp, dilateMask, dlog, dpow, expNeg, filmPixel, filmReflectance, linearToSrgb8, maskBounds, membraneFill, paintPathStroke, pathStrokeCoverage, pathStrokeDabs, pigmentColor, pigmentOf, pixelPigment, seamlessClone, shadeTile, solveMembrane, srgbByteToLinear, stepSlotTs };
@@ -1,5 +1,7 @@
1
- export { m as BlenderScratch, b as BlenderSettings, B as BrushSettings, C as CoverageMap, n as DEFAULT_BLENDER, o as DEFAULT_BRUSH, p as DEFAULT_MIXER, q as DEFAULT_RETOUCH, r as DEFAULT_SMUDGE, D as Dab, s as DabWalker, E as EMPTY_MIXER_LOAD, t as ExchangeRates, e as MAX_BRUSH_SIZE, u as MIXER_DRAIN, v as MIXER_PICKUP_RATE, w as MIXING_MODELS, d as MixerLoad, M as MixerSettings, i as MixerStroke, h as MixerTarget, a as MixingModel, x as PaintExchange, y as PaintMedium, z as PaintSample, P as PaintTileTarget, A as PixelSource, F as RETOUCH_SAMPLES, G as RegionPixelSource, j as RetouchApply, H as RetouchDabEffect, I as RetouchDabStroke, k as RetouchPaint, J as RetouchSample, f as RetouchSettings, R as RgbTriple, K as SPOT_HEAL_TYPES, L as SmudgeDab, S as SmudgeSettings, N as SmudgeTip, O as SpotHealType, l as StrokeApply, g as StrokeCoverage, c as StrokePoint, T as TONE_RANGES, Q as TileMedium, U as TileMediumOptions, V as TilePixelSource, W as ToneRange, X as applyRetouchToTile, Y as applyStrokeToTile, Z as blendRadius, _ as blenderDab, $ as cleanMixer, a0 as coverageTileCoord, a1 as createBlenderScratch, a2 as dabCoverage, a3 as dabRect, a4 as dodgeBurn, a5 as dodgeBurnCurve, a6 as exchangeRates, a7 as healPixels, a8 as loadMixer, a9 as luma, aa as mixerRates, ab as normalizeBlender, ac as normalizeBrush, ad as normalizeMixer, ae as normalizeRetouch, af as normalizeSmudge, ag as perDabStrength, ah as rasterizeDab, ai as readSourceRegion, aj as rgbaViewOfGrey, ak as saturationOf, al as smoothPoints, am as smudgeEffect, an as sponge, ao as spongeEffect, ap as spotHealPixels, aq as spotHealWindow, ar as tipFalloff, as as tipReach, at as tipShape, au as toneOf, av as walkDabs } from '../retouch-Do6tBs2H.js';
2
- export { Z as PIGMENT_BANDS, _ as PIGMENT_LAMBDA_MIN, $ as PIGMENT_LAMBDA_STEP, a0 as PIGMENT_WAVELENGTHS, Y as Pigment, a1 as PigmentOptions, a2 as PigmentRgb, a3 as createPigment, a4 as lerpPigment, a5 as lerpPigmentInto, a6 as mixPigments, a7 as reflectanceToRgb, a8 as rgbToReflectance, a9 as setPigmentColor } from '../surface-Cn30xIV6.js';
1
+ import { at as PaintMedium, W as WetWorld, au as PaintSample, n as RgbTriple, B as BrushSettings, C as CoverageMap, D as Dab } from '../flow-Cb7lkPm8.js';
2
+ export { F as BlenderScratch, i as BlenderSettings, G as DEFAULT_BLENDER, H as DEFAULT_BRUSH, s as DEFAULT_FLOW, I as DEFAULT_MIXER, J as DEFAULT_RETOUCH, K as DEFAULT_SMUDGE, L as DEFAULT_WET_PAPER, t as DEFAULT_WET_PARAMS, N as DRY_EPS, O as DabWalker, Q as EMPTY_MIXER_LOAD, U as EX, V as EY, X as ExchangeRates, Y as FLAG_ALIVE, Z as FLAG_BOTTOM, _ as FLAG_LEFT, $ as FLAG_RIGHT, a0 as FLAG_TOP, a1 as FLAG_WET, a2 as FLAT, a3 as FREE_INTERVAL, a4 as MAX_BATCH, u as MAX_BRUSH_SIZE, a5 as MAX_TILT_ACCEL, a6 as MAX_WET_LANES, a7 as MAX_WET_SLOTS, a8 as MIXER_DRAIN, a9 as MIXER_PICKUP_RATE, aa as MIXING_MODELS, a as MixerLoad, M as MixerSettings, c as MixerStroke, b as MixerTarget, h as MixingModel, ab as OPP, ac as PAPER_CAPACITY, ad as PARAM, ae as PARAM_FLOATS, af as PIGMENT_CHANNELS, ag as PLANE, ah as PLANE_BYTES, ai as P_D0, aj as P_EDGE, ak as P_FX, al as P_FY, am as P_H, an as P_P0, ao as P_RHO, ap as P_SW, aq as P_UX, ar as P_UY, as as PaintExchange, P as PaintTileTarget, av as PixelSource, aw as RETOUCH_SAMPLES, ax as RegionPixelSource, d as RetouchApply, ay as RetouchDabEffect, az as RetouchDabStroke, f as RetouchPaint, aA as RetouchSample, R as RetouchSettings, aB as SET_PLANES, aC as SLOT_BYTES, aD as SLOT_PLANES, aE as SLOT_SIDE, aF as SPOT_HEAL_TYPES, aG as STRIP, aH as SmudgeDab, j as SmudgeSettings, aI as SmudgeTip, aJ as SpotHealType, g as StrokeApply, S as StrokeCoverage, e as StrokePoint, aK as TONE_RANGES, T as TileMedium, aL as TileMediumOptions, aM as TilePixelSource, aN as ToneRange, aO as U_MAX, aP as W9, v as WET_FLOW_KINDS, w as WET_PARAM_KEYS, aQ as WET_TILE, p as WetBackendInfo, aR as WetFlowField, x as WetFlowKind, m as WetFlowSpec, aS as WetKernelKind, aT as WetLaneOptions, aU as WetLaneStats, aV as WetPaper, r as WetPaperInput, l as WetParams, q as WetSnapshot, y as WetSupport, k as WetTilt, aW as WetWorkerLayout, aX as WetWorkerPool, aY as WetWorldError, o as WetWorldOptions, aZ as applyRetouchToTile, a_ as applyStrokeToDeepTile, a$ as applyStrokeToTile, b0 as applyToneToDeepTile, b1 as blendRadius, b2 as blenderDab, b3 as canShareMemory, b4 as cleanMixer, b5 as coverageTileCoord, b6 as createBlenderScratch, b7 as dabCoverage, b8 as dabRect, b9 as dodgeBurn, ba as dodgeBurnCurve, bb as dsincos, bc as edgeBits, bd as exchangeRates, be as flowField, bf as healPixels, bg as latticeViscosity, bh as loadMixer, bi as loadWetKernel, bj as luma, bk as mixerRates, bl as normalizeBlender, bm as normalizeBrush, z as normalizeFlow, bn as normalizeMixer, bo as normalizeRetouch, bp as normalizeSmudge, bq as normalizeTilt, A as normalizeWetParams, br as packWetParams, bs as perDabStrength, bt as rasterizeDab, bu as readSourceRegion, bv as rgbaViewOfGrey, bw as saturationOf, bx as smoothPoints, by as smudgeEffect, bz as sponge, bA as spongeEffect, bB as spotHealPixels, bC as spotHealWindow, bD as tipFalloff, bE as tipReach, bF as tipShape, bG as toneOf, bH as walkDabs, bI as wetSimdSupported, E as wetSupport } from '../flow-Cb7lkPm8.js';
3
+ import { R as RasterRect, Y as Pigment, a as BlendMode, j as TiledSurface } from '../surface-Cn30xIV6.js';
4
+ export { Z as PIGMENT_BANDS, _ as PIGMENT_LAMBDA_MIN, $ as PIGMENT_LAMBDA_STEP, a0 as PIGMENT_WAVELENGTHS, a1 as PigmentOptions, a2 as PigmentRgb, a3 as createPigment, a4 as lerpPigment, a5 as lerpPigmentInto, a6 as mixPigments, a7 as reflectanceToRgb, a8 as rgbToReflectance, a9 as setPigmentColor } from '../surface-Cn30xIV6.js';
3
5
  import { A as AgentTool } from '../registry-D-4fit9C.js';
4
6
  import '../schema-Di0CS6Pe.js';
5
7
 
@@ -36,4 +38,224 @@ declare function maskBounds(w: number, h: number, mask: ArrayLike<boolean | numb
36
38
  */
37
39
  declare function bestOffset(w: number, h: number, ch: number, img: ArrayLike<number>, hole: ArrayLike<boolean | number>, ring: number, maxRadius: number): [number, number] | null;
38
40
 
39
- export { bestOffset, createPigmentTools, dilateMask, maskBounds, membraneFill, seamlessClone, solveMembrane };
41
+ /**
42
+ * How wet-layer pigment looks, and how it bakes into 8-bit pixels.
43
+ *
44
+ * A cell carries pigment as Kubelka-Munk absorption `K` per channel (linear R, G, B) and one
45
+ * scattering `S`, in mass units where `PIGMENT_UNIT` of a colour's pigment is a full-strength wash.
46
+ * Over what is below it (`below`, linear), the film reflects
47
+ *
48
+ * film = hide·R∞ + (1 − hide)·T·below, T = e^(−2K), hide = 1 − e^(−HIDE·S),
49
+ * R∞ = 1 + K/S − √((K/S)² + 2·K/S) (the shipped pigment model's two-flux formula)
50
+ *
51
+ * so transparent washes (S ≈ 0) multiply like glazes and opaque paint (gouache, oil) hides.
52
+ *
53
+ * The bake is a pure function of the f32 state and the 8-bit pixels, computed with deterministic
54
+ * maths only (`dexp`, `dlog`, `sqrt`, + − × ÷ in f64; never `Math.exp` / `Math.pow`, whose last
55
+ * bits differ between JavaScript engines), so "dry on save" gives the same pixels everywhere.
56
+ * The layer pixel is the film expressed as colour plus alpha over the paper colour (exact over the
57
+ * paper, a normal-blend approximation over other layers), with alpha never below the pixel's own.
58
+ */
59
+ /** Pigment mass of a full-strength wash of a colour. */
60
+ declare const PIGMENT_UNIT = 0.25;
61
+ /** Hiding per unit of scattering. */
62
+ declare const HIDE = 1.5;
63
+ /** Scattering of fully opaque paint (`body` 1), per `PIGMENT_UNIT` of mass. */
64
+ declare const BODY_SCATTER = 3;
65
+ /**
66
+ * e^x with + − × ÷ only: x = k·ln2 + r with |r| ≤ ln2/2, then a degree-11 Taylor polynomial
67
+ * (error below 1e-15). The same bits in every JavaScript engine.
68
+ */
69
+ declare function dexp(x: number): number;
70
+ /** ln x for x > 0 with + − × ÷ only: x = m·2^e, ln m by the atanh series. */
71
+ declare function dlog(x: number): number;
72
+ /** x^y for x ≥ 0, deterministically. */
73
+ declare function dpow(x: number, y: number): number;
74
+ /** sRGB byte → linear. */
75
+ declare const SRGB_TO_LINEAR: Float64Array<ArrayBuffer>;
76
+ /** sRGB value 0..255 (not necessarily whole) → linear, interpolating the byte table. */
77
+ declare function srgbByteToLinear(v: number): number;
78
+ /** Linear 0..1 → sRGB byte (16384-step table). */
79
+ declare function linearToSrgb8(v: number): number;
80
+ /**
81
+ * The pigment (K r, g, b, S per unit of mass) of an sRGB colour (0..1) at `body` 0 (a transparent
82
+ * watercolour: K = −ln R / 2 so a full wash over white shows the colour) .. 1 (opaque paint:
83
+ * `K/S = (1 − R)² / 2R` at `BODY_SCATTER`).
84
+ */
85
+ declare function pigmentOf(rgb: readonly [number, number, number] | readonly number[], body: number, out?: Float64Array | number[]): Float64Array | number[];
86
+ /** e^(−x) for x ≥ 0 (deterministic: a table built with `dexp`, interpolated with + − ×). */
87
+ declare function expNeg(x: number): number;
88
+ /** Linear reflectance of a film of pigment `k` (3) and `s` over `below` (linear) into `out`. */
89
+ declare function filmReflectance(k0: number, k1: number, k2: number, s: number, b0: number, b1: number, b2: number, out: Float64Array | number[]): void;
90
+ /** The sRGB colour (0..1) of pigment `k`, `s` over white: what a brush picking it up sees. */
91
+ declare function pigmentColor(k0: number, k1: number, k2: number, s: number, out?: number[]): number[];
92
+ /**
93
+ * Bakes one pixel: pigment `k0..k2`, `s` laid over layer pixel `px[i..i+3]` (straight sRGB) on paper
94
+ * `paper` (sRGB bytes). `wet` (0..1) darkens wet paper slightly (display only; 0 for a bake).
95
+ * Writes the new layer pixel into `out[o..o+3]`.
96
+ */
97
+ declare function filmPixel(k0: number, k1: number, k2: number, s: number, px: ArrayLike<number>, i: number, paper: ArrayLike<number>, wet: number, out: Uint8ClampedArray, o: number): void;
98
+ /**
99
+ * The pigment a layer pixel holds over the paper, as a transparent film (`K = −ln(below/paper)/2`,
100
+ * `S` 0): what re-wetting lifts back into the water. Writes K r, g, b, S into `out`.
101
+ */
102
+ declare function pixelPigment(px: ArrayLike<number>, i: number, paper: ArrayLike<number>, out: Float64Array | number[]): void;
103
+ /**
104
+ * `filmPixel` over a whole tile, specialised for speed (same results, pixel for pixel). Reads the
105
+ * slot's planes from `f`: settled pigment at `d` (4 planes, `plane` floats apart), suspended pigment
106
+ * at `p` (or −1 to leave it out), surface and paper water at `rho` / `sw` (or −1: no wet darkening).
107
+ * Cell (x, y) of the tile is at offset `(y + 1)·side + x + 1` of each plane. `src` is the base tile
108
+ * (or `null` for transparent); writes `out` (a copy of `src` where nothing changes). Returns
109
+ * whether any pixel was shaded.
110
+ */
111
+ declare function shadeTile(f: Float32Array, plane: number, side: number, d: number, p: number, rho: number, sw: number, src: Uint8ClampedArray | null, out: Uint8ClampedArray, w: number, h: number, paper: Uint8Array): boolean;
112
+
113
+ /**
114
+ * One wet-media step for the 256 × 256 interior of a tile slot, in plain TypeScript: the
115
+ * specification of the model. Every intermediate is rounded to f32 (`F`) in the same order as the
116
+ * WebAssembly SIMD kernel (`assembly/wet.ts`), so the two give identical bits: computing an f32
117
+ * `+ − × ÷ √` in f64 and rounding once is exactly the f32 operation. Keep the two in step; the
118
+ * kernel test compares them bit for bit.
119
+ *
120
+ * A slot is `SLOT_PLANES` planes of 258 × 258 f32 (the tile plus a one-cell halo, filled from the
121
+ * neighbouring slots after each step). The step reads set `parity` (and the single planes) and
122
+ * writes the interior of the other set, the deposit planes in place, and returns the tile's flags.
123
+ *
124
+ * Per cell x:
125
+ * 1. Streaming with partial bounce-back: for each direction i, the source is n = x − eᵢ and the
126
+ * blocking is b = max(κ(x), κ(n)), κ = blockScale·h. b = 1 off the canvas (h < 0) and where the
127
+ * front is pinned: one side dry and the other shallower than the pin threshold
128
+ * (pinT + rough·h)·(1 − paperWater/capacity) of the dry side, so damp paper does not pin.
129
+ * Off-canvas cells (h < 0, in the halo or past a canvas edge inside a tile) only bounce back.
130
+ * Symmetric in x and n, so water is conserved: fᵢ(x) = (1 − b)·f*ᵢ(n) + b·f*ₒₚₚ₍ᵢ₎(x).
131
+ * 2. Depth and velocity; tilt plus the flow map shift the velocity (u += τ·g), capped at U_MAX.
132
+ * 3. Absorption into the paper until it holds its capacity, and evaporation (faster in the edge
133
+ * band); the collided populations are scaled by the depth ratio.
134
+ * 4. BGK collision towards the D2Q9 equilibrium.
135
+ * 5. Pigment (4 channels): upwind flux through the 4 faces with the previous step's velocities,
136
+ * plus bleed (diffusion) between wet cells; never below 0.
137
+ * 6. Deposition (more in valleys and in the edge band) and pickup (more where water arrives);
138
+ * where a cell dries, all its suspended pigment settles.
139
+ * 7. The edge field: max(dry neighbours / 4, 0.99 × the mean of the 4 neighbours' edge), at most
140
+ * 1, and 0 where the cell is dry.
141
+ */
142
+ /**
143
+ * Steps one slot. `f` views the whole memory; `base` is the slot's first float; `prm` is the
144
+ * lane's packed parameters (`packWetParams`). Returns the tile's flag bits.
145
+ */
146
+ declare function stepSlotTs(f: Float32Array, base: number, parity: number, prm: Float32Array): number;
147
+
148
+ /**
149
+ * The wet layer as a `PaintMedium`: the canvas side of the shared pick-up / mix exchange
150
+ * (`PaintExchange`), so wet brushes pick up and mix paint the same way the Mixer Brush and the
151
+ * phase 2 dab brushes do.
152
+ *
153
+ * - `sample` sees only wet paint (pigment still suspended in surface water): what a brush can
154
+ * lift. Its colour is the suspended pigment's hue at full strength; contact is how much of the
155
+ * footprint is wet with pigment in it.
156
+ * - `deposit` lays water and pigment: the colour becomes Kubelka-Munk pigment (`pigmentOf` at the
157
+ * brush's body), at `mass` per unit of coverage, with `water` depth.
158
+ */
159
+
160
+ interface WetMediumOptions {
161
+ /** Water depth laid per unit of coverage (at deposit weight 1). */
162
+ water: number;
163
+ /** Pigment mass laid per unit of coverage (at deposit weight 1). */
164
+ mass: number;
165
+ /** 0 transparent watercolour .. 1 opaque gouache. */
166
+ body: number;
167
+ }
168
+ declare class WetMedium implements PaintMedium {
169
+ readonly world: WetWorld;
170
+ readonly laneId: string;
171
+ options: WetMediumOptions;
172
+ private readonly pig;
173
+ constructor(world: WetWorld, laneId: string, options: WetMediumOptions);
174
+ sample(rect: RasterRect, cov: ArrayLike<number>): PaintSample | null;
175
+ deposit(rect: RasterRect, cov: ArrayLike<number>, dep: number, paint: Readonly<RgbTriple>, _pigment: Pigment | null, field?: Float32Array | null): void;
176
+ }
177
+
178
+ /**
179
+ * A brush stroke along a path: polyline samples, each with an optional pressure and pen tilt, are
180
+ * walked at the brush's spacing (pressure and tilt interpolated between samples) into dabs, built
181
+ * up in a coverage map and composited onto a layer. This is what a vector editor calls to draw a
182
+ * path with a natural-media brush ("brushstrokes on vector paths"): the path is the data, the
183
+ * pixels are rendered from it.
184
+ *
185
+ * - Pressure scales size and / or opacity as the brush says.
186
+ * - Tilt (`tiltX` / `tiltY` in degrees, or `altitude` / `azimuth` in radians, as Pointer Events give
187
+ * them) widens the tip (`tilt.size`), flattens it along the lean (`tilt.roundness`), and with
188
+ * `tilt.followAzimuth` turns the tip to the lean, as a pen laid on its side does.
189
+ * - With `followPath` the tip turns with the path (a calligraphic nib along a curve).
190
+ *
191
+ * Deterministic and DOM-free: the same samples and brush give the same pixels everywhere.
192
+ */
193
+
194
+ /** One sample of the path (document pixels). */
195
+ interface PathSample {
196
+ x: number;
197
+ y: number;
198
+ /** 0..1 (default 1). */
199
+ pressure?: number;
200
+ /** Pointer Events tilt in degrees (−90..90). */
201
+ tiltX?: number;
202
+ tiltY?: number;
203
+ /** Radians above the surface (π/2 upright); overrides tiltX / tiltY. */
204
+ altitude?: number;
205
+ /** Radians clockwise from +x: where the pen leans (with altitude). */
206
+ azimuth?: number;
207
+ }
208
+ interface PathStrokeOptions {
209
+ brush: Partial<BrushSettings>;
210
+ /** How tilt shapes the tip (each 0..1; default none). */
211
+ tilt?: {
212
+ size?: number;
213
+ roundness?: number;
214
+ followAzimuth?: boolean;
215
+ };
216
+ /** Turn the tip with the direction of the path (added to the brush angle). */
217
+ followPath?: boolean;
218
+ /** Size at zero pressure as a fraction of the full size, when pressure controls size (default 0). */
219
+ minSize?: number;
220
+ /** Join the last sample back to the first. */
221
+ closed?: boolean;
222
+ }
223
+ /** The dabs of a brush stroke along `samples`, with pressure and tilt interpolated between them. */
224
+ declare function pathStrokeDabs(samples: readonly PathSample[], options: PathStrokeOptions): Dab[];
225
+ /** The coverage of a brush stroke along `samples` (build-up towards each dab's opacity) and its bounds. */
226
+ declare function pathStrokeCoverage(samples: readonly PathSample[], options: PathStrokeOptions): {
227
+ coverage: CoverageMap;
228
+ bounds: RasterRect | null;
229
+ dabs: number;
230
+ };
231
+ interface PaintPathOptions extends PathStrokeOptions {
232
+ /** RGBA 0..255 of the paint. */
233
+ color: readonly [number, number, number, number];
234
+ /** `erase` removes paint instead (default `paint`). */
235
+ mode?: 'paint' | 'erase';
236
+ /** Blend mode (default the brush's). */
237
+ blend?: BlendMode;
238
+ /** Layer offset: layer pixel = document pixel − offset (default 0, 0). */
239
+ offset?: {
240
+ x: number;
241
+ y: number;
242
+ };
243
+ lockTransparency?: boolean;
244
+ /** Where paint may land (canvas-sized coverage 0..255), or none. */
245
+ selection?: {
246
+ width: number;
247
+ height: number;
248
+ data: ArrayLike<number>;
249
+ } | null;
250
+ }
251
+ /**
252
+ * Paints a brush stroke along `samples` onto an RGBA layer surface and returns the new surface
253
+ * (the input is not changed; untouched tiles are shared) with the bounds it touched.
254
+ */
255
+ declare function paintPathStroke(surface: TiledSurface, samples: readonly PathSample[], options: PaintPathOptions): {
256
+ surface: TiledSurface;
257
+ bounds: RasterRect | null;
258
+ dabs: number;
259
+ };
260
+
261
+ export { BODY_SCATTER, BrushSettings, CoverageMap, Dab, HIDE, PIGMENT_UNIT, PaintMedium, type PaintPathOptions, PaintSample, type PathSample, type PathStrokeOptions, Pigment, RgbTriple, SRGB_TO_LINEAR, WetMedium, type WetMediumOptions, WetWorld, bestOffset, createPigmentTools, dexp, dilateMask, dlog, dpow, expNeg, filmPixel, filmReflectance, linearToSrgb8, maskBounds, membraneFill, paintPathStroke, pathStrokeCoverage, pathStrokeDabs, pigmentColor, pigmentOf, pixelPigment, seamlessClone, shadeTile, solveMembrane, srgbByteToLinear, stepSlotTs };