@pixerate/editor 0.137.0 → 0.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.d.cts +3 -3
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/index.cjs +57 -57
- package/dist/animation-editor/index.d.cts +3 -3
- package/dist/animation-editor/index.d.ts +3 -3
- package/dist/animation-editor/index.js +4 -4
- package/dist/{arrange-CKXK_hf7.d.cts → arrange-j_mLiFMO.d.cts} +1 -1
- package/dist/{arrange-BUREmgD9.d.ts → arrange-q5HQvnnB.d.ts} +1 -1
- package/dist/{bezier-CZ2AhjID.d.cts → bezier-CUaH8hcK.d.cts} +1 -1
- package/dist/{bezier-Dywv3Bw8.d.ts → bezier-DPmdGwgR.d.ts} +1 -1
- package/dist/{brushTypes-C7N3EBK7.d.cts → brushTypes-MX5UVs_m.d.cts} +27 -2
- package/dist/{brushTypes-C7N3EBK7.d.ts → brushTypes-MX5UVs_m.d.ts} +27 -2
- package/dist/{brushes-DJmUbIgz.d.ts → brushes-B1ABdDAs.d.ts} +2 -108
- package/dist/{brushes-CnvZSYYU.d.cts → brushes-DnIdJYxN.d.cts} +2 -108
- package/dist/{brushstrokeRender-IMFY3FF6.cjs → brushstrokeRender-PP6NTF6M.cjs} +52 -24
- package/dist/brushstrokeRender-PP6NTF6M.cjs.map +1 -0
- package/dist/{brushstrokeRender-2FAXA3XC.js → brushstrokeRender-QGEYJ4OZ.js} +40 -12
- package/dist/brushstrokeRender-QGEYJ4OZ.js.map +1 -0
- package/dist/{builtins-Cc-bH-3U.d.cts → builtins-BakDiKWf.d.cts} +3 -2
- package/dist/{builtins-ZU1GJnUA.d.ts → builtins-CE33vyv2.d.ts} +3 -2
- package/dist/canvas/index.cjs +16 -9
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +56 -11
- package/dist/canvas/index.d.ts +56 -11
- package/dist/canvas/index.js +10 -3
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-QBWEH3IM.cjs → chunk-3T5O225T.cjs} +391 -76
- package/dist/chunk-3T5O225T.cjs.map +1 -0
- package/dist/{chunk-PRSRYHQD.cjs → chunk-7MN75BXI.cjs} +36 -36
- package/dist/{chunk-PRSRYHQD.cjs.map → chunk-7MN75BXI.cjs.map} +1 -1
- package/dist/{chunk-EQQMGO42.js → chunk-C2J7GOMJ.js} +18 -5
- package/dist/chunk-C2J7GOMJ.js.map +1 -0
- package/dist/{chunk-2XS6LTUP.cjs → chunk-C46AZEBE.cjs} +104 -339
- package/dist/chunk-C46AZEBE.cjs.map +1 -0
- package/dist/{chunk-XN2NBLV5.cjs → chunk-CM3LJPR3.cjs} +82 -82
- package/dist/{chunk-XN2NBLV5.cjs.map → chunk-CM3LJPR3.cjs.map} +1 -1
- package/dist/{chunk-HUO3TI4C.js → chunk-CPSMARTX.js} +6 -241
- package/dist/chunk-CPSMARTX.js.map +1 -0
- package/dist/{chunk-KEENUAFN.cjs → chunk-DLLUOVQX.cjs} +18 -5
- package/dist/chunk-DLLUOVQX.cjs.map +1 -0
- package/dist/{chunk-LSXXAJG3.js → chunk-J7DSKTKB.js} +5 -4
- package/dist/chunk-J7DSKTKB.js.map +1 -0
- package/dist/{chunk-6S6362D2.js → chunk-OV7253FC.js} +2 -2
- package/dist/{chunk-5FSRTP6E.js → chunk-PQFVLOMR.js} +319 -4
- package/dist/chunk-PQFVLOMR.js.map +1 -0
- package/dist/{chunk-OIBIRXRG.js → chunk-PSPLRQL6.js} +2 -2
- package/dist/{chunk-SYT2TLQF.js → chunk-QBARQGSG.js} +2 -2
- package/dist/{chunk-5OOIUXNJ.cjs → chunk-SXOTFV3V.cjs} +6 -6
- package/dist/{chunk-5OOIUXNJ.cjs.map → chunk-SXOTFV3V.cjs.map} +1 -1
- package/dist/{chunk-DFSZO2B5.cjs → chunk-UFL5N4DK.cjs} +5 -4
- package/dist/chunk-UFL5N4DK.cjs.map +1 -0
- package/dist/{chunk-3D77LOBM.js → chunk-V45ZTW4R.js} +3 -3
- package/dist/{chunk-TLCTTQFF.cjs → chunk-VEHVXRJU.cjs} +17 -17
- package/dist/{chunk-TLCTTQFF.cjs.map → chunk-VEHVXRJU.cjs.map} +1 -1
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.d.cts +3 -3
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/index.js +1 -1
- package/dist/{export-DwnZ_hvQ.d.ts → export-BwFRiItd.d.ts} +4 -4
- package/dist/{export-CyJdfP_Z.d.cts → export-DuN3dpCg.d.cts} +4 -4
- package/dist/{blending-NgF3qo3d.d.ts → grain-COgYMMHv.d.ts} +58 -1
- package/dist/{blending-D7jCmjO6.d.cts → grain-GCt_O2kv.d.cts} +58 -1
- package/dist/image-editor/index.cjs +695 -677
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +11 -11
- package/dist/image-editor/index.d.ts +11 -11
- package/dist/image-editor/index.js +23 -5
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{opentype-a1KAW-qs.d.ts → opentype-T7bkbR2D.d.ts} +1 -1
- package/dist/{opentype-KR_jj6b_.d.cts → opentype-n99lqxEZ.d.cts} +1 -1
- package/dist/paint/index.cjs +21 -3
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +72 -7
- package/dist/paint/index.d.ts +72 -7
- package/dist/paint/index.js +20 -2
- package/dist/paint-editor/index.cjs +171 -171
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +75 -29
- package/dist/paint-editor/index.d.ts +75 -29
- package/dist/paint-editor/index.js +12 -12
- package/dist/{pathfinder-BHS4vQNm.d.cts → pathfinder-CQlldanv.d.cts} +2 -2
- package/dist/{pathfinder-BVvTIBMo.d.ts → pathfinder-D-V6JLSw.d.ts} +2 -2
- package/dist/{rand-Cw9VLrVC.d.cts → rand-D7nfeD1p.d.cts} +18 -2
- package/dist/{rand-8xbUb6ur.d.ts → rand-DJGxSq9d.d.ts} +18 -2
- package/dist/{svg-CSz3mzkw.d.ts → svg-CnDCpIy9.d.ts} +1 -1
- package/dist/{svg-DTb40ICU.d.cts → svg-DPJMUSNt.d.cts} +1 -1
- package/dist/vector/index.cjs +944 -944
- package/dist/vector/index.d.cts +10 -10
- package/dist/vector/index.d.ts +10 -10
- package/dist/vector/index.js +4 -4
- package/dist/{warp-DTOp0lON.d.cts → warp-C7rMWUgW.d.cts} +1 -1
- package/dist/{warp-pd7hrH4T.d.ts → warp-Doasjpyr.d.ts} +1 -1
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +12 -5
- package/dist/brushstrokeRender-2FAXA3XC.js.map +0 -1
- package/dist/brushstrokeRender-IMFY3FF6.cjs.map +0 -1
- package/dist/chunk-2XS6LTUP.cjs.map +0 -1
- package/dist/chunk-5FSRTP6E.js.map +0 -1
- package/dist/chunk-DFSZO2B5.cjs.map +0 -1
- package/dist/chunk-EQQMGO42.js.map +0 -1
- package/dist/chunk-HUO3TI4C.js.map +0 -1
- package/dist/chunk-KEENUAFN.cjs.map +0 -1
- package/dist/chunk-LSXXAJG3.js.map +0 -1
- package/dist/chunk-QBWEH3IM.cjs.map +0 -1
- /package/dist/{chunk-6S6362D2.js.map → chunk-OV7253FC.js.map} +0 -0
- /package/dist/{chunk-OIBIRXRG.js.map → chunk-PSPLRQL6.js.map} +0 -0
- /package/dist/{chunk-SYT2TLQF.js.map → chunk-QBARQGSG.js.map} +0 -0
- /package/dist/{chunk-3D77LOBM.js.map → chunk-V45ZTW4R.js.map} +0 -0
|
@@ -311,14 +311,39 @@ interface CanvasBrushstroke {
|
|
|
311
311
|
/** Pointer Events pen tilt in degrees (−90..90) along the length. */
|
|
312
312
|
tiltX?: number[];
|
|
313
313
|
tiltY?: number[];
|
|
314
|
+
/**
|
|
315
|
+
* Character seed. A stroke with one renders the brush's character: its seeded size, angle,
|
|
316
|
+
* opacity and scatter jitter and the paper grain it catches (charcoal, pastel and pencil get
|
|
317
|
+
* their look from these). New strokes get one; older strokes without it render plain dabs at
|
|
318
|
+
* the stroke width, exactly as before.
|
|
319
|
+
*/
|
|
320
|
+
seed?: number;
|
|
321
|
+
/**
|
|
322
|
+
* Brush diameter in path units. Missing: the preset's own size (tip settings: their `size`, else
|
|
323
|
+
* the stroke width) for strokes with a `seed`, the stroke width for older ones.
|
|
324
|
+
*/
|
|
325
|
+
size?: number;
|
|
326
|
+
/** The paper the grain comes from (default the built-in sanded grain); `null` for no grain. */
|
|
327
|
+
paper?: CanvasBrushPaper | null;
|
|
328
|
+
}
|
|
329
|
+
/** Paper for a brushed stroke's grain (the paint engine's `BrushstrokePaper`). */
|
|
330
|
+
interface CanvasBrushPaper {
|
|
331
|
+
/** Grain pattern (default `sanded`: a fine, even tooth). */
|
|
332
|
+
pattern?: 'smooth' | 'cold-pressed' | 'hot-pressed' | 'rough' | 'vellum' | 'laid' | 'ingres' | 'sanded' | 'canvas' | 'linen' | 'gesso';
|
|
333
|
+
/** Grain seed (default 1). */
|
|
334
|
+
seed?: number;
|
|
335
|
+
/** Grain scale in canvas units, 1 the pattern's natural size (0.25..8, default 1). */
|
|
336
|
+
scale?: number;
|
|
337
|
+
/** Grain depth 0..1, times the brush's grain response (default 0.5). */
|
|
338
|
+
depth?: number;
|
|
314
339
|
}
|
|
315
340
|
/** A dry paint preset that can brush a canvas stroke. */
|
|
316
341
|
interface CanvasBrushPreset {
|
|
317
342
|
id: string;
|
|
318
343
|
name: string;
|
|
319
344
|
category: string;
|
|
320
|
-
/** The preset's own tip diameter in
|
|
345
|
+
/** The preset's own tip diameter in canvas units: a new brushed stroke's default size. */
|
|
321
346
|
size: number;
|
|
322
347
|
}
|
|
323
348
|
|
|
324
|
-
export type { CanvasBrush as C, DirectionalDisplacementOptions as D, ExplodeNodeOptions as E, FanOutTrajectoryOptions as F, GraphDifferences as G, IncrementalLayoutOptions as I, NodeTransition as N, Point as P, Rect as R, Side as S, TrajectoryFunction as T, XYPosition as X, CanvasBrushPaint as a, CanvasBrushPreset as b, CanvasNode as c, CanvasNodeStyle as d, CanvasBrushstroke as e, CanvasEdge as f, CanvasLayoutOptions as g, PlaceBesideOptions as h, ReflowDisplacementOptions as i, CanvasClipboardPayload as j, Position as k, CanvasBrushPaintMapping as l, CanvasBrushPaintStop as m,
|
|
349
|
+
export type { CanvasBrush as C, DirectionalDisplacementOptions as D, ExplodeNodeOptions as E, FanOutTrajectoryOptions as F, GraphDifferences as G, IncrementalLayoutOptions as I, NodeTransition as N, Point as P, Rect as R, Side as S, TrajectoryFunction as T, XYPosition as X, CanvasBrushPaint as a, CanvasBrushPreset as b, CanvasNode as c, CanvasNodeStyle as d, CanvasBrushstroke as e, CanvasEdge as f, CanvasLayoutOptions as g, PlaceBesideOptions as h, ReflowDisplacementOptions as i, CanvasClipboardPayload as j, Position as k, CanvasBrushPaintMapping as l, CanvasBrushPaintStop as m, CanvasBrushPaper as n, CanvasBrushSettings as o, CanvasDockingCallbacks as p, CollapseNodeOptions as q, DisplacementDirection as r, DockStrategy as s, ExplosionSnapshot as t, TrajectoryPoint as u };
|
|
@@ -1,112 +1,6 @@
|
|
|
1
|
-
import { D as Dab, C as CoverageMap, B as BrushSettings, S as StrokePoint,
|
|
1
|
+
import { D as Dab, C as CoverageMap, P as PaperGrain, B as BrushSettings, S as StrokePoint, a as PaintTileTarget, b as PaintGradientSource, T as TileMedium, M as MixerSettings, c as MixingModel, d as BlenderSettings, e as SmudgeSettings, f as PaintSource } from './grain-COgYMMHv.js';
|
|
2
2
|
import { R as RasterRect, T as TiledSurface } from './surface-1MRncXpF.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Paper: a generated grain height map (0 = valley, 1 = peak) that tiles across the canvas, a paper
|
|
6
|
-
* colour, grain depth, and the three properties wet media will read later (absorption,
|
|
7
|
-
* permeability, roughness). Dry media catch the peaks: a light stroke only marks the high grain, a
|
|
8
|
-
* firm one fills the valleys too. Everything is generated from a pattern and a seed, so a paper is
|
|
9
|
-
* a few numbers in the document, never a bitmap, and no third-party texture is bundled.
|
|
10
|
-
*/
|
|
11
|
-
/** Grain generators. Each is our own procedural pattern (no scanned textures). */
|
|
12
|
-
type GrainPattern = 'smooth' | 'cold-pressed' | 'hot-pressed' | 'rough' | 'vellum' | 'laid' | 'ingres' | 'sanded' | 'canvas' | 'linen' | 'gesso';
|
|
13
|
-
declare const GRAIN_PATTERNS: readonly GrainPattern[];
|
|
14
|
-
/** Paper families, as a library groups them. */
|
|
15
|
-
type PaperFamily = 'watercolor' | 'drawing' | 'pastel' | 'canvas' | 'panel' | 'smooth';
|
|
16
|
-
declare const PAPER_FAMILIES: readonly PaperFamily[];
|
|
17
|
-
/** How a height map is tuned for one kind of media. */
|
|
18
|
-
interface GrainTuning {
|
|
19
|
-
/** Height contrast around the middle, 0..3 (default 1). */
|
|
20
|
-
contrast: number;
|
|
21
|
-
/** Swap peaks and valleys (default false). */
|
|
22
|
-
invert: boolean;
|
|
23
|
-
}
|
|
24
|
-
type PaperTiling = 'repeat' | 'mirror';
|
|
25
|
-
interface PaperSettings {
|
|
26
|
-
/** The library preset this paper started from (`custom` when it matches none). */
|
|
27
|
-
preset: string;
|
|
28
|
-
name: string;
|
|
29
|
-
family: PaperFamily;
|
|
30
|
-
pattern: GrainPattern;
|
|
31
|
-
/** Grain seed: another seed gives another sheet of the same paper. */
|
|
32
|
-
seed: number;
|
|
33
|
-
/** Paper colour #rrggbb. */
|
|
34
|
-
color: string;
|
|
35
|
-
/** Grain scale: 1 is the pattern's natural size, 2 twice as coarse (0.25..8). */
|
|
36
|
-
scale: number;
|
|
37
|
-
/** How the grain tile repeats: `repeat` or `mirror` (alternate tiles flipped, so seams vanish). */
|
|
38
|
-
tiling: PaperTiling;
|
|
39
|
-
/** Grain depth 0..1: how much grain-responsive dry media skip the valleys (0: none). */
|
|
40
|
-
depth: number;
|
|
41
|
-
/** How much the grain shades the paper colour on screen and in exports, 0..1. */
|
|
42
|
-
shading: number;
|
|
43
|
-
/** The height map as dry media read it. */
|
|
44
|
-
dry: GrainTuning;
|
|
45
|
-
/** The height map as wet media will read it (stored now; wet media is a later phase). */
|
|
46
|
-
wet: GrainTuning;
|
|
47
|
-
/** Wet media: how fast the paper takes up water, 0..1. */
|
|
48
|
-
absorption: number;
|
|
49
|
-
/** Wet media: how far water spreads inside the paper, 0..1. */
|
|
50
|
-
permeability: number;
|
|
51
|
-
/** Wet media: how much the grain catches pigment, 0..1. */
|
|
52
|
-
roughness: number;
|
|
53
|
-
/** Metallic paper (gold or silver leaf, pearlescent card): the grain catches the light, 0..1 (default 0). */
|
|
54
|
-
metallic?: number;
|
|
55
|
-
}
|
|
56
|
-
/** Side of the generated grain tile in pixels (at scale 1). */
|
|
57
|
-
declare const GRAIN_TILE = 256;
|
|
58
|
-
type PaperPreset = PaperSettings;
|
|
59
|
-
/** The built-in paper library: generated papers in families. */
|
|
60
|
-
declare const PAPER_LIBRARY: readonly PaperPreset[];
|
|
61
|
-
declare const DEFAULT_PAPER: Readonly<PaperSettings>;
|
|
62
|
-
/** A paper from the library by id, or `undefined`. */
|
|
63
|
-
declare function paperPreset(id: string): PaperSettings | undefined;
|
|
64
|
-
declare function clonePaper(p: PaperSettings): PaperSettings;
|
|
65
|
-
/**
|
|
66
|
-
* A paper with every field in range. Missing fields come from `base` (default: the library preset
|
|
67
|
-
* named by `raw.preset`, else cold pressed).
|
|
68
|
-
*/
|
|
69
|
-
declare function normalizePaper(raw?: Partial<PaperSettings> | Record<string, unknown>, base?: PaperSettings): PaperSettings;
|
|
70
|
-
/** The raw height map of a pattern (`GRAIN_TILE` square, 0..1), generated once per pattern and seed. */
|
|
71
|
-
declare function grainHeights(pattern: GrainPattern, seed: number, size?: number): Float32Array;
|
|
72
|
-
/**
|
|
73
|
-
* A paper's height field over the canvas (document pixels), tuned for one kind of media. Read it
|
|
74
|
-
* with `at(x, y)`: bilinear, tiled by `paper.tiling`, at `paper.scale`.
|
|
75
|
-
*/
|
|
76
|
-
declare class PaperGrain {
|
|
77
|
-
readonly size = 256;
|
|
78
|
-
private readonly heights;
|
|
79
|
-
private readonly scale;
|
|
80
|
-
private readonly mirror;
|
|
81
|
-
readonly flat: boolean;
|
|
82
|
-
constructor(paper: PaperSettings, media?: 'dry' | 'wet');
|
|
83
|
-
/** Tile cell index for a coordinate in grain pixels (mirrored on odd tiles when mirroring). */
|
|
84
|
-
private wrap;
|
|
85
|
-
/** Height 0..1 at document position (x, y). */
|
|
86
|
-
at(x: number, y: number): number;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* How much of a dry dab lands at grain height `h` (0..1): the media catches the peaks first, and
|
|
90
|
-
* pressure pushes it into the valleys. `depth` is the paper's grain depth times the brush's grain
|
|
91
|
-
* response; at 0 everything lands (1).
|
|
92
|
-
*/
|
|
93
|
-
declare function grainCatch(h: number, depth: number, pressure: number): number;
|
|
94
|
-
/** `#rrggbb` → [r, g, b] 0..255. */
|
|
95
|
-
declare function hexToRgb8(hex: string): [number, number, number];
|
|
96
|
-
/**
|
|
97
|
-
* The paper as opaque RGBA over `rect` (document pixels): its colour, darkened in the valleys by
|
|
98
|
-
* `shading`.
|
|
99
|
-
*/
|
|
100
|
-
declare function renderPaper(paper: PaperSettings, rect: {
|
|
101
|
-
x: number;
|
|
102
|
-
y: number;
|
|
103
|
-
width: number;
|
|
104
|
-
height: number;
|
|
105
|
-
}, grain?: PaperGrain, light?: {
|
|
106
|
-
azimuth: number;
|
|
107
|
-
elevation: number;
|
|
108
|
-
}): Uint8ClampedArray;
|
|
109
|
-
|
|
110
4
|
/**
|
|
111
5
|
* The paint editor's dry-media stroke engine, on the shared brush engine (`@pixerate/editor/paint`):
|
|
112
6
|
*
|
|
@@ -741,4 +635,4 @@ interface BrushLibraryFile {
|
|
|
741
635
|
*/
|
|
742
636
|
declare function parseBrushLibrary(raw: unknown, problems?: string[]): PaintBrush[];
|
|
743
637
|
|
|
744
|
-
export { type
|
|
638
|
+
export { type StickerSettings as $, IDENTITY_COPY as A, type BrushLibraryFile as B, type CoverageStroke as C, DEFAULT_BEHAVIOR as D, IMPASTO_TOOLS as E, type ImpastoSettings as F, MULTI_COLOR_MODES as G, type MultiColorMode as H, type ImpastoTool as I, PAINT_BRUSH_CATEGORIES as J, PAINT_BRUSH_ENGINES as K, type Linear2 as L, type MultiColorSettings as M, PARTICLE_KINDS as N, PARTICLE_RENDERS as O, type PaintBrush as P, type PaintBrushCategory as Q, type PaintBrushEngine as R, type StrokeCopy as S, type ParticleSettings as T, ParticleStroke as U, type PenDab as V, type WetMediumKind as W, PenDabWalker as X, PenSmoother as Y, type ProceduralStrokeOptions as Z, STAMP_KINDS as _, type PenPoint as a, StickerSpray as a0, type StickerSprayInit as a1, WET_MEDIA as a2, WET_TOOLS as a3, type WetBrushSettings as a4, brushTakesPaint as a5, brushToJSON as a6, drawSticker as a7, isWetBrush as a8, isWetCapable as a9, mixerTip as aa, multiColorToPaint as ab, normalizeBehavior as ac, normalizeBristle as ad, normalizeDynamics as ae, normalizeImpasto as af, normalizeMultiColor as ag, normalizePaintBrush as ah, normalizeParticle as ai, normalizeStickerSettings as aj, normalizeStickerUpdate as ak, normalizeWetBrush as al, paintToMultiColor as am, parseBrushLibrary as an, penOrientation as ao, renderStickers as ap, stampCoverage as aq, stickerRect as ar, stickerSurface as as, tiltToOrientation as at, toStrokePoint as au, usesPaintExchange as av, type Sticker as b, type PaintBrushInput as c, type ParticleKind as d, type ParticleRender as e, type StampKind as f, type WetTool as g, BRUSH_ID as h, BRUSH_ROTATIONS as i, BUILTIN_BRUSHES as j, type BristleSettings as k, BristleStroke as l, type BrushBehavior as m, type BrushBehaviorInput as n, type BrushDynamics as o, type BrushRotation as p, DEFAULT_BRISTLE as q, DEFAULT_BRUSH_ID as r, DEFAULT_DYNAMICS as s, DEFAULT_IMPASTO as t, DEFAULT_MULTI_COLOR as u, DEFAULT_PARTICLE as v, DEFAULT_STICKER as w, DEFAULT_WET_BRUSH as x, DryStroke as y, type DryStrokeOptions as z };
|
|
@@ -1,112 +1,6 @@
|
|
|
1
|
-
import { D as Dab, C as CoverageMap, B as BrushSettings, S as StrokePoint,
|
|
1
|
+
import { D as Dab, C as CoverageMap, P as PaperGrain, B as BrushSettings, S as StrokePoint, a as PaintTileTarget, b as PaintGradientSource, T as TileMedium, M as MixerSettings, c as MixingModel, d as BlenderSettings, e as SmudgeSettings, f as PaintSource } from './grain-GCt_O2kv.cjs';
|
|
2
2
|
import { R as RasterRect, T as TiledSurface } from './surface-1MRncXpF.cjs';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Paper: a generated grain height map (0 = valley, 1 = peak) that tiles across the canvas, a paper
|
|
6
|
-
* colour, grain depth, and the three properties wet media will read later (absorption,
|
|
7
|
-
* permeability, roughness). Dry media catch the peaks: a light stroke only marks the high grain, a
|
|
8
|
-
* firm one fills the valleys too. Everything is generated from a pattern and a seed, so a paper is
|
|
9
|
-
* a few numbers in the document, never a bitmap, and no third-party texture is bundled.
|
|
10
|
-
*/
|
|
11
|
-
/** Grain generators. Each is our own procedural pattern (no scanned textures). */
|
|
12
|
-
type GrainPattern = 'smooth' | 'cold-pressed' | 'hot-pressed' | 'rough' | 'vellum' | 'laid' | 'ingres' | 'sanded' | 'canvas' | 'linen' | 'gesso';
|
|
13
|
-
declare const GRAIN_PATTERNS: readonly GrainPattern[];
|
|
14
|
-
/** Paper families, as a library groups them. */
|
|
15
|
-
type PaperFamily = 'watercolor' | 'drawing' | 'pastel' | 'canvas' | 'panel' | 'smooth';
|
|
16
|
-
declare const PAPER_FAMILIES: readonly PaperFamily[];
|
|
17
|
-
/** How a height map is tuned for one kind of media. */
|
|
18
|
-
interface GrainTuning {
|
|
19
|
-
/** Height contrast around the middle, 0..3 (default 1). */
|
|
20
|
-
contrast: number;
|
|
21
|
-
/** Swap peaks and valleys (default false). */
|
|
22
|
-
invert: boolean;
|
|
23
|
-
}
|
|
24
|
-
type PaperTiling = 'repeat' | 'mirror';
|
|
25
|
-
interface PaperSettings {
|
|
26
|
-
/** The library preset this paper started from (`custom` when it matches none). */
|
|
27
|
-
preset: string;
|
|
28
|
-
name: string;
|
|
29
|
-
family: PaperFamily;
|
|
30
|
-
pattern: GrainPattern;
|
|
31
|
-
/** Grain seed: another seed gives another sheet of the same paper. */
|
|
32
|
-
seed: number;
|
|
33
|
-
/** Paper colour #rrggbb. */
|
|
34
|
-
color: string;
|
|
35
|
-
/** Grain scale: 1 is the pattern's natural size, 2 twice as coarse (0.25..8). */
|
|
36
|
-
scale: number;
|
|
37
|
-
/** How the grain tile repeats: `repeat` or `mirror` (alternate tiles flipped, so seams vanish). */
|
|
38
|
-
tiling: PaperTiling;
|
|
39
|
-
/** Grain depth 0..1: how much grain-responsive dry media skip the valleys (0: none). */
|
|
40
|
-
depth: number;
|
|
41
|
-
/** How much the grain shades the paper colour on screen and in exports, 0..1. */
|
|
42
|
-
shading: number;
|
|
43
|
-
/** The height map as dry media read it. */
|
|
44
|
-
dry: GrainTuning;
|
|
45
|
-
/** The height map as wet media will read it (stored now; wet media is a later phase). */
|
|
46
|
-
wet: GrainTuning;
|
|
47
|
-
/** Wet media: how fast the paper takes up water, 0..1. */
|
|
48
|
-
absorption: number;
|
|
49
|
-
/** Wet media: how far water spreads inside the paper, 0..1. */
|
|
50
|
-
permeability: number;
|
|
51
|
-
/** Wet media: how much the grain catches pigment, 0..1. */
|
|
52
|
-
roughness: number;
|
|
53
|
-
/** Metallic paper (gold or silver leaf, pearlescent card): the grain catches the light, 0..1 (default 0). */
|
|
54
|
-
metallic?: number;
|
|
55
|
-
}
|
|
56
|
-
/** Side of the generated grain tile in pixels (at scale 1). */
|
|
57
|
-
declare const GRAIN_TILE = 256;
|
|
58
|
-
type PaperPreset = PaperSettings;
|
|
59
|
-
/** The built-in paper library: generated papers in families. */
|
|
60
|
-
declare const PAPER_LIBRARY: readonly PaperPreset[];
|
|
61
|
-
declare const DEFAULT_PAPER: Readonly<PaperSettings>;
|
|
62
|
-
/** A paper from the library by id, or `undefined`. */
|
|
63
|
-
declare function paperPreset(id: string): PaperSettings | undefined;
|
|
64
|
-
declare function clonePaper(p: PaperSettings): PaperSettings;
|
|
65
|
-
/**
|
|
66
|
-
* A paper with every field in range. Missing fields come from `base` (default: the library preset
|
|
67
|
-
* named by `raw.preset`, else cold pressed).
|
|
68
|
-
*/
|
|
69
|
-
declare function normalizePaper(raw?: Partial<PaperSettings> | Record<string, unknown>, base?: PaperSettings): PaperSettings;
|
|
70
|
-
/** The raw height map of a pattern (`GRAIN_TILE` square, 0..1), generated once per pattern and seed. */
|
|
71
|
-
declare function grainHeights(pattern: GrainPattern, seed: number, size?: number): Float32Array;
|
|
72
|
-
/**
|
|
73
|
-
* A paper's height field over the canvas (document pixels), tuned for one kind of media. Read it
|
|
74
|
-
* with `at(x, y)`: bilinear, tiled by `paper.tiling`, at `paper.scale`.
|
|
75
|
-
*/
|
|
76
|
-
declare class PaperGrain {
|
|
77
|
-
readonly size = 256;
|
|
78
|
-
private readonly heights;
|
|
79
|
-
private readonly scale;
|
|
80
|
-
private readonly mirror;
|
|
81
|
-
readonly flat: boolean;
|
|
82
|
-
constructor(paper: PaperSettings, media?: 'dry' | 'wet');
|
|
83
|
-
/** Tile cell index for a coordinate in grain pixels (mirrored on odd tiles when mirroring). */
|
|
84
|
-
private wrap;
|
|
85
|
-
/** Height 0..1 at document position (x, y). */
|
|
86
|
-
at(x: number, y: number): number;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* How much of a dry dab lands at grain height `h` (0..1): the media catches the peaks first, and
|
|
90
|
-
* pressure pushes it into the valleys. `depth` is the paper's grain depth times the brush's grain
|
|
91
|
-
* response; at 0 everything lands (1).
|
|
92
|
-
*/
|
|
93
|
-
declare function grainCatch(h: number, depth: number, pressure: number): number;
|
|
94
|
-
/** `#rrggbb` → [r, g, b] 0..255. */
|
|
95
|
-
declare function hexToRgb8(hex: string): [number, number, number];
|
|
96
|
-
/**
|
|
97
|
-
* The paper as opaque RGBA over `rect` (document pixels): its colour, darkened in the valleys by
|
|
98
|
-
* `shading`.
|
|
99
|
-
*/
|
|
100
|
-
declare function renderPaper(paper: PaperSettings, rect: {
|
|
101
|
-
x: number;
|
|
102
|
-
y: number;
|
|
103
|
-
width: number;
|
|
104
|
-
height: number;
|
|
105
|
-
}, grain?: PaperGrain, light?: {
|
|
106
|
-
azimuth: number;
|
|
107
|
-
elevation: number;
|
|
108
|
-
}): Uint8ClampedArray;
|
|
109
|
-
|
|
110
4
|
/**
|
|
111
5
|
* The paint editor's dry-media stroke engine, on the shared brush engine (`@pixerate/editor/paint`):
|
|
112
6
|
*
|
|
@@ -741,4 +635,4 @@ interface BrushLibraryFile {
|
|
|
741
635
|
*/
|
|
742
636
|
declare function parseBrushLibrary(raw: unknown, problems?: string[]): PaintBrush[];
|
|
743
637
|
|
|
744
|
-
export { type
|
|
638
|
+
export { type StickerSettings as $, IDENTITY_COPY as A, type BrushLibraryFile as B, type CoverageStroke as C, DEFAULT_BEHAVIOR as D, IMPASTO_TOOLS as E, type ImpastoSettings as F, MULTI_COLOR_MODES as G, type MultiColorMode as H, type ImpastoTool as I, PAINT_BRUSH_CATEGORIES as J, PAINT_BRUSH_ENGINES as K, type Linear2 as L, type MultiColorSettings as M, PARTICLE_KINDS as N, PARTICLE_RENDERS as O, type PaintBrush as P, type PaintBrushCategory as Q, type PaintBrushEngine as R, type StrokeCopy as S, type ParticleSettings as T, ParticleStroke as U, type PenDab as V, type WetMediumKind as W, PenDabWalker as X, PenSmoother as Y, type ProceduralStrokeOptions as Z, STAMP_KINDS as _, type PenPoint as a, StickerSpray as a0, type StickerSprayInit as a1, WET_MEDIA as a2, WET_TOOLS as a3, type WetBrushSettings as a4, brushTakesPaint as a5, brushToJSON as a6, drawSticker as a7, isWetBrush as a8, isWetCapable as a9, mixerTip as aa, multiColorToPaint as ab, normalizeBehavior as ac, normalizeBristle as ad, normalizeDynamics as ae, normalizeImpasto as af, normalizeMultiColor as ag, normalizePaintBrush as ah, normalizeParticle as ai, normalizeStickerSettings as aj, normalizeStickerUpdate as ak, normalizeWetBrush as al, paintToMultiColor as am, parseBrushLibrary as an, penOrientation as ao, renderStickers as ap, stampCoverage as aq, stickerRect as ar, stickerSurface as as, tiltToOrientation as at, toStrokePoint as au, usesPaintExchange as av, type Sticker as b, type PaintBrushInput as c, type ParticleKind as d, type ParticleRender as e, type StampKind as f, type WetTool as g, BRUSH_ID as h, BRUSH_ROTATIONS as i, BUILTIN_BRUSHES as j, type BristleSettings as k, BristleStroke as l, type BrushBehavior as m, type BrushBehaviorInput as n, type BrushDynamics as o, type BrushRotation as p, DEFAULT_BRISTLE as q, DEFAULT_BRUSH_ID as r, DEFAULT_DYNAMICS as s, DEFAULT_IMPASTO as t, DEFAULT_MULTI_COLOR as u, DEFAULT_PARTICLE as v, DEFAULT_STICKER as w, DEFAULT_WET_BRUSH as x, DryStroke as y, type DryStrokeOptions as z };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkDLLUOVQXcjs = require('./chunk-DLLUOVQX.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var _chunk2YQONY6Gcjs = require('./chunk-2YQONY6G.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkC46AZEBEcjs = require('./chunk-C46AZEBE.cjs');
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
@@ -17,34 +17,34 @@ var _chunkIZ4WRXZAcjs = require('./chunk-IZ4WRXZA.cjs');
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var _chunk3T5O225Tcjs = require('./chunk-3T5O225T.cjs');
|
|
21
21
|
require('./chunk-SYPFUL5B.cjs');
|
|
22
22
|
require('./chunk-O7LUD7MH.cjs');
|
|
23
23
|
require('./chunk-643B2HKC.cjs');
|
|
24
24
|
|
|
25
25
|
// src/canvas/brushstrokeRender.ts
|
|
26
|
-
var DRY =
|
|
26
|
+
var DRY = _chunkC46AZEBEcjs.BUILTIN_BRUSHES.filter((b) => _chunk3T5O225Tcjs.isBrushstrokeBrush.call(void 0, b));
|
|
27
27
|
function listCanvasBrushes() {
|
|
28
28
|
return DRY.map((b) => ({ id: b.id, name: b.name, category: b.category, size: b.tip.size }));
|
|
29
29
|
}
|
|
30
30
|
function resolveCanvasBrush(brush, width) {
|
|
31
|
-
const
|
|
31
|
+
const given = width !== void 0 && Number.isFinite(width) ? Math.max(1, width) : void 0;
|
|
32
32
|
if (typeof brush === "string") {
|
|
33
|
-
const preset =
|
|
33
|
+
const preset = _chunkC46AZEBEcjs.BUILTIN_BRUSHES.find((b) => b.id === brush);
|
|
34
34
|
const ids = DRY.map((b) => b.id).join(", ");
|
|
35
35
|
if (!preset) throw new Error(`Unknown brush '${brush}'. Use one of the dry paint presets (${ids}) or tip settings ({ hardness, spacing, flow, \u2026 }).`);
|
|
36
|
-
if (!
|
|
36
|
+
if (!_chunk3T5O225Tcjs.isBrushstrokeBrush.call(void 0, preset)) {
|
|
37
37
|
throw new Error(`Brush '${brush}' (${preset.name}) is not a dry brush: brushed canvas strokes use dry media only (wet paint needs an area to flow in; mixer, blender, smudge and eraser brushes need paint under them). Use one of: ${ids}.`);
|
|
38
38
|
}
|
|
39
|
-
return { ...preset, tip: { ...preset.tip, size } };
|
|
39
|
+
return given === void 0 ? preset : { ...preset, tip: { ...preset.tip, size: given } };
|
|
40
40
|
}
|
|
41
41
|
if (!brush || typeof brush !== "object" || Array.isArray(brush)) {
|
|
42
42
|
throw new Error("A brush is a dry paint preset id (see listCanvasBrushes / canvas.listBrushes) or an object of tip settings.");
|
|
43
43
|
}
|
|
44
|
-
return { size, ...brush };
|
|
44
|
+
return { size: _nullishCoalesce(given, () => ( 3)), ...brush };
|
|
45
45
|
}
|
|
46
46
|
function resolveCanvasPaint(paint) {
|
|
47
|
-
const source =
|
|
47
|
+
const source = _chunk3T5O225Tcjs.parsePaintSource.call(void 0, paint, "paint");
|
|
48
48
|
if (source.type === "gradient" && (source.map.by === "velocity" || source.map.by === "time")) {
|
|
49
49
|
throw new Error(`paint.map.by "${source.map.by}" needs timed samples, which canvas strokes do not record; use distance, pressure, tilt, direction, across-tip or random.`);
|
|
50
50
|
}
|
|
@@ -60,48 +60,76 @@ function shapePaint(shape) {
|
|
|
60
60
|
}
|
|
61
61
|
function strokeColor(shape) {
|
|
62
62
|
const gradient = _chunkIZ4WRXZAcjs.resolveCanvasGradient.call(void 0, _nullishCoalesce(shape.strokeGradient, () => ( shape.stroke)));
|
|
63
|
-
const css = gradient ? _nullishCoalesce(_optionalChain([gradient, 'access',
|
|
63
|
+
const css = gradient ? _nullishCoalesce(_optionalChain([gradient, 'access', _2 => _2.stops, 'access', _3 => _3[0], 'optionalAccess', _4 => _4.color]), () => ( "#000")) : typeof shape.stroke === "string" && shape.stroke !== "none" ? shape.stroke : "#000";
|
|
64
64
|
const parsed = _nullishCoalesce(_chunk2YQONY6Gcjs.parseCssColor.call(void 0, css), () => ( { hex: "#000000", alpha: 1 }));
|
|
65
65
|
const n = parseInt(parsed.hex.slice(1), 16);
|
|
66
66
|
return [n >> 16 & 255, n >> 8 & 255, n & 255, Math.round(parsed.alpha * 255)];
|
|
67
67
|
}
|
|
68
|
-
var cache = new (0,
|
|
68
|
+
var cache = new (0, _chunk3T5O225Tcjs.BrushstrokeCache)(128);
|
|
69
69
|
var urls = /* @__PURE__ */ new WeakMap();
|
|
70
|
-
function renderShapeBrushstrokeNow(shape, scale) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
70
|
+
function renderShapeBrushstrokeNow(shape, scale, place = {}) {
|
|
71
|
+
const seed = shape.brush.seed;
|
|
72
|
+
const textured = typeof seed === "number" && Number.isFinite(seed);
|
|
73
|
+
const size = _nullishCoalesce(shape.brush.size, () => ( (textured ? void 0 : _nullishCoalesce(shape.strokeWidth, () => ( 3)))));
|
|
74
|
+
const brush = resolveCanvasBrush(shape.brush.brush, size);
|
|
75
|
+
const points = _chunkDLLUOVQXcjs.pathDataToPolyline.call(void 0, shape.d);
|
|
73
76
|
if (!points.length) return null;
|
|
74
77
|
const { pressure, tiltX, tiltY } = shape.brush;
|
|
75
78
|
const input = {
|
|
76
79
|
points: points.map(([x, y]) => ({ x, y })),
|
|
77
|
-
..._optionalChain([pressure, 'optionalAccess',
|
|
78
|
-
..._optionalChain([tiltX, 'optionalAccess',
|
|
79
|
-
..._optionalChain([tiltY, 'optionalAccess',
|
|
80
|
+
..._optionalChain([pressure, 'optionalAccess', _5 => _5.length]) ? { pressure } : {},
|
|
81
|
+
..._optionalChain([tiltX, 'optionalAccess', _6 => _6.length]) ? { tiltX } : {},
|
|
82
|
+
..._optionalChain([tiltY, 'optionalAccess', _7 => _7.length]) ? { tiltY } : {}
|
|
80
83
|
};
|
|
81
84
|
const paint = shapePaint(shape);
|
|
82
|
-
const
|
|
85
|
+
const character = textured ? {
|
|
86
|
+
character: {
|
|
87
|
+
seed,
|
|
88
|
+
...shape.brush.paper !== void 0 ? { paper: shape.brush.paper } : {},
|
|
89
|
+
// Whole canvas units: the grain stays put, and tiny drags do not re-render.
|
|
90
|
+
origin: { x: Math.round(_nullishCoalesce(_optionalChain([place, 'access', _8 => _8.origin, 'optionalAccess', _9 => _9.x]), () => ( 0))), y: Math.round(_nullishCoalesce(_optionalChain([place, 'access', _10 => _10.origin, 'optionalAccess', _11 => _11.y]), () => ( 0))) },
|
|
91
|
+
unit: place.unit && place.unit > 0 ? Math.round(place.unit * 1e3) / 1e3 : 1
|
|
92
|
+
}
|
|
93
|
+
} : {};
|
|
94
|
+
const stroke = cache.render(input, brush, { scale, color: strokeColor(shape), ...paint ? { paint } : {}, ...character });
|
|
83
95
|
if (!stroke.bounds) return null;
|
|
84
96
|
let href = urls.get(stroke);
|
|
85
97
|
if (href === void 0) {
|
|
86
|
-
href =
|
|
98
|
+
href = _chunk3T5O225Tcjs.brushstrokeDataUrl.call(void 0, stroke);
|
|
87
99
|
urls.set(stroke, href);
|
|
88
100
|
}
|
|
89
101
|
return { href, ...stroke.bounds, scale: stroke.scale };
|
|
90
102
|
}
|
|
91
103
|
var escapeAttr = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
92
|
-
function brushedShapeSvgNow(shape, size, scale) {
|
|
104
|
+
function brushedShapeSvgNow(shape, size, scale, place = {}) {
|
|
93
105
|
const f = (n) => _chunkIZ4WRXZAcjs.formatNumber.call(void 0, n, 3);
|
|
94
|
-
const image = renderShapeBrushstrokeNow(shape, scale);
|
|
106
|
+
const image = renderShapeBrushstrokeNow(shape, scale, place);
|
|
95
107
|
const svg = _chunkIZ4WRXZAcjs.getShapeSvg.call(void 0, shape, size);
|
|
96
108
|
const body = image ? `<image href="${escapeAttr(image.href)}" x="${f(image.x)}" y="${f(image.y)}" width="${f(image.width)}" height="${f(image.height)}" preserveAspectRatio="none"${shape.opacity !== void 0 ? ` opacity="${f(shape.opacity)}"` : ""}/>` : "";
|
|
97
109
|
const content = svg.transform && body ? `<g transform="${svg.transform}">${body}</g>` : body;
|
|
98
110
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${f(size.width)}" height="${f(size.height)}" viewBox="0 0 ${f(size.width)} ${f(size.height)}">${content}</svg>`;
|
|
99
111
|
}
|
|
112
|
+
function brushSwatchNow(brush, options) {
|
|
113
|
+
const w = options.width && options.width > 8 ? options.width : 96;
|
|
114
|
+
const h = options.height && options.height > 4 ? options.height : 24;
|
|
115
|
+
const own = typeof brush === "string" ? resolveCanvasBrush(brush, void 0) : resolveCanvasBrush(brush, brush.size);
|
|
116
|
+
const tip = "tip" in own && own.tip ? _nullishCoalesce(own.tip.size, () => ( 3)) : _nullishCoalesce(own.size, () => ( 3));
|
|
117
|
+
const size = Math.max(1.5, Math.min(tip, h * 0.55));
|
|
118
|
+
const pad = size / 2 + 2;
|
|
119
|
+
const pts = Array.from({ length: 9 }, (_, i) => [pad + (w - 2 * pad) * i / 8, h / 2 + Math.sin(i / 8 * Math.PI * 2) * (h / 2 - pad) * 0.6]);
|
|
120
|
+
const d = pts.map(([x, y], i) => `${i ? "L" : "M"}${x.toFixed(2)} ${y.toFixed(2)}`).join(" ");
|
|
121
|
+
const image = renderShapeBrushstrokeNow(
|
|
122
|
+
{ kind: "path", d, stroke: _nullishCoalesce(options.color, () => ( "#1f2937")), strokeWidth: size, brush: { brush, seed: 7, size, pressure: [0.35, 1, 0.5] } },
|
|
123
|
+
options.scale && options.scale > 0 ? options.scale : 2
|
|
124
|
+
);
|
|
125
|
+
return _nullishCoalesce(_optionalChain([image, 'optionalAccess', _12 => _12.href]), () => ( ""));
|
|
126
|
+
}
|
|
127
|
+
|
|
100
128
|
|
|
101
129
|
|
|
102
130
|
|
|
103
131
|
|
|
104
132
|
|
|
105
133
|
|
|
106
|
-
exports.brushedShapeSvgNow = brushedShapeSvgNow; exports.listCanvasBrushes = listCanvasBrushes; exports.renderShapeBrushstrokeNow = renderShapeBrushstrokeNow; exports.resolveCanvasBrush = resolveCanvasBrush; exports.resolveCanvasPaint = resolveCanvasPaint;
|
|
107
|
-
//# sourceMappingURL=brushstrokeRender-
|
|
134
|
+
exports.brushSwatchNow = brushSwatchNow; exports.brushedShapeSvgNow = brushedShapeSvgNow; exports.listCanvasBrushes = listCanvasBrushes; exports.renderShapeBrushstrokeNow = renderShapeBrushstrokeNow; exports.resolveCanvasBrush = resolveCanvasBrush; exports.resolveCanvasPaint = resolveCanvasPaint;
|
|
135
|
+
//# sourceMappingURL=brushstrokeRender-PP6NTF6M.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/brushstrokeRender-PP6NTF6M.cjs","../src/canvas/brushstrokeRender.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/brushstrokeRender-PP6NTF6M.cjs","sourcesContent":[null,"/**\n * The lazily loaded half of brushed freehand strokes (`./brushstroke.ts` imports it on first use):\n * the paint engine's dry brushstroke renderer, the paint presets and a CSS colour parser. Keep\n * every import of the paint engine in this file, so the canvas entry never reaches it statically.\n */\nimport { BrushstrokeCache, brushstrokeDataUrl, isBrushstrokeBrush, type BrushstrokeBrush, type BrushstrokeImage } from '../paint/brushstroke.js';\nimport { parsePaintSource, type PaintSource } from '../paint/gradient-paint.js';\nimport { BUILTIN_BRUSHES } from '../paint-editor/brushes.js';\nimport { parseCssColor } from '../image-editor/layers/css-color.js';\nimport { resolveCanvasGradient } from './gradient.js';\nimport { formatNumber, getShapeSvg, type ShapeSize } from './shapeGeometry.js';\nimport { pathDataToPolyline, type BrushedPathShape, type CanvasBrushSwatchOptions, type CanvasBrush, type CanvasBrushPaint, type CanvasBrushPreset, type CanvasBrushstrokeImage } from './brushstroke.js';\n\nconst DRY = BUILTIN_BRUSHES.filter((b) => isBrushstrokeBrush(b));\n\nexport function listCanvasBrushes(): CanvasBrushPreset[] {\n\treturn DRY.map((b) => ({ id: b.id, name: b.name, category: b.category, size: b.tip.size }));\n}\n\n/**\n * The paint engine brush for a canvas brush at diameter `width` (undefined: the preset's own size,\n * or the settings' `size`, else 3); throws with the usable ids.\n */\nexport function resolveCanvasBrush(brush: CanvasBrush, width: number | undefined): BrushstrokeBrush {\n\tconst given = width !== undefined && Number.isFinite(width) ? Math.max(1, width) : undefined;\n\tif (typeof brush === 'string') {\n\t\tconst preset = BUILTIN_BRUSHES.find((b) => b.id === brush);\n\t\tconst ids = DRY.map((b) => b.id).join(', ');\n\t\tif (!preset) throw new Error(`Unknown brush '${brush}'. Use one of the dry paint presets (${ids}) or tip settings ({ hardness, spacing, flow, … }).`);\n\t\tif (!isBrushstrokeBrush(preset)) {\n\t\t\tthrow new Error(`Brush '${brush}' (${preset.name}) is not a dry brush: brushed canvas strokes use dry media only (wet paint needs an area to flow in; mixer, blender, smudge and eraser brushes need paint under them). Use one of: ${ids}.`);\n\t\t}\n\t\treturn given === undefined ? preset : { ...preset, tip: { ...preset.tip, size: given } };\n\t}\n\tif (!brush || typeof brush !== 'object' || Array.isArray(brush)) {\n\t\tthrow new Error('A brush is a dry paint preset id (see listCanvasBrushes / canvas.listBrushes) or an object of tip settings.');\n\t}\n\treturn { size: given ?? 3, ...brush };\n}\n\n/**\n * The paint engine's `PaintSource` for a brushed stroke's `paint`; throws with what is wrong.\n * Mappings that need timed samples (`velocity`, `time`) are refused: canvas strokes carry no timing.\n */\nexport function resolveCanvasPaint(paint: CanvasBrushPaint | unknown): PaintSource {\n\tconst source = parsePaintSource(paint, 'paint');\n\tif (source.type === 'gradient' && (source.map.by === 'velocity' || source.map.by === 'time')) {\n\t\tthrow new Error(`paint.map.by \"${source.map.by}\" needs timed samples, which canvas strokes do not record; use distance, pressure, tilt, direction, across-tip or random.`);\n\t}\n\treturn source;\n}\n\n/** A stored stroke's paint, or null when it has none or it is not valid paint (the stroke colour is used then). */\nfunction shapePaint(shape: BrushedPathShape): PaintSource | null {\n\tif (shape.brush.paint === undefined || shape.brush.paint === null) return null;\n\ttry {\n\t\treturn resolveCanvasPaint(shape.brush.paint);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * RGBA of a shape's stroke paint: with `brush.paint` its alpha and the colour of `paint` stops.\n * A canvas gradient stroke without `brush.paint` uses its first stop.\n */\nfunction strokeColor(shape: BrushedPathShape): [number, number, number, number] {\n\tconst gradient = resolveCanvasGradient(shape.strokeGradient ?? shape.stroke);\n\tconst css = gradient ? (gradient.stops[0]?.color ?? '#000') : typeof shape.stroke === 'string' && shape.stroke !== 'none' ? shape.stroke : '#000';\n\tconst parsed = parseCssColor(css) ?? { hex: '#000000', alpha: 1 };\n\tconst n = parseInt(parsed.hex.slice(1), 16);\n\treturn [(n >> 16) & 255, (n >> 8) & 255, n & 255, Math.round(parsed.alpha * 255)];\n}\n\nconst cache = new BrushstrokeCache(128);\nconst urls = new WeakMap<BrushstrokeImage, string>();\n\nexport function renderShapeBrushstrokeNow(shape: BrushedPathShape, scale: number, place: { origin?: { x: number; y: number }; unit?: number } = {}): CanvasBrushstrokeImage | null {\n\t// Strokes with a character seed (new ones) default to the preset's size and render its jitter\n\t// and grain; older strokes keep the stroke width and plain dabs, so they look as they always did.\n\tconst seed = shape.brush.seed;\n\tconst textured = typeof seed === 'number' && Number.isFinite(seed);\n\tconst size = shape.brush.size ?? (textured ? undefined : (shape.strokeWidth ?? 3));\n\tconst brush = resolveCanvasBrush(shape.brush.brush, size);\n\tconst points = pathDataToPolyline(shape.d);\n\tif (!points.length) return null;\n\tconst { pressure, tiltX, tiltY } = shape.brush;\n\tconst input = {\n\t\tpoints: points.map(([x, y]) => ({ x, y })),\n\t\t...(pressure?.length ? { pressure } : {}),\n\t\t...(tiltX?.length ? { tiltX } : {}),\n\t\t...(tiltY?.length ? { tiltY } : {})\n\t};\n\tconst paint = shapePaint(shape);\n\tconst character = textured\n\t\t? {\n\t\t\t\tcharacter: {\n\t\t\t\t\tseed,\n\t\t\t\t\t...(shape.brush.paper !== undefined ? { paper: shape.brush.paper } : {}),\n\t\t\t\t\t// Whole canvas units: the grain stays put, and tiny drags do not re-render.\n\t\t\t\t\torigin: { x: Math.round(place.origin?.x ?? 0), y: Math.round(place.origin?.y ?? 0) },\n\t\t\t\t\tunit: place.unit && place.unit > 0 ? Math.round(place.unit * 1000) / 1000 : 1\n\t\t\t\t}\n\t\t\t}\n\t\t: {};\n\tconst stroke = cache.render(input, brush, { scale, color: strokeColor(shape), ...(paint ? { paint } : {}), ...character });\n\tif (!stroke.bounds) return null;\n\tlet href = urls.get(stroke);\n\tif (href === undefined) {\n\t\thref = brushstrokeDataUrl(stroke);\n\t\turls.set(stroke, href);\n\t}\n\treturn { href, ...stroke.bounds, scale: stroke.scale };\n}\n\nconst escapeAttr = (s: string) => s.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n\nexport function brushedShapeSvgNow(shape: BrushedPathShape, size: ShapeSize, scale: number, place: { origin?: { x: number; y: number }; unit?: number } = {}): string {\n\tconst f = (n: number) => formatNumber(n, 3);\n\tconst image = renderShapeBrushstrokeNow(shape, scale, place);\n\tconst svg = getShapeSvg(shape, size);\n\tconst body = image\n\t\t? `<image href=\"${escapeAttr(image.href)}\" x=\"${f(image.x)}\" y=\"${f(image.y)}\" width=\"${f(image.width)}\" height=\"${f(image.height)}\" preserveAspectRatio=\"none\"${shape.opacity !== undefined ? ` opacity=\"${f(shape.opacity)}\"` : ''}/>`\n\t\t: '';\n\tconst content = svg.transform && body ? `<g transform=\"${svg.transform}\">${body}</g>` : body;\n\treturn `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${f(size.width)}\" height=\"${f(size.height)}\" viewBox=\"0 0 ${f(size.width)} ${f(size.height)}\">${content}</svg>`;\n}\n\nexport function brushSwatchNow(brush: CanvasBrush, options: CanvasBrushSwatchOptions): string {\n\tconst w = options.width && options.width > 8 ? options.width : 96;\n\tconst h = options.height && options.height > 4 ? options.height : 24;\n\tconst own = typeof brush === 'string' ? resolveCanvasBrush(brush, undefined) : resolveCanvasBrush(brush, brush.size);\n\tconst tip = 'tip' in own && own.tip ? own.tip.size ?? 3 : (own as { size?: number }).size ?? 3;\n\tconst size = Math.max(1.5, Math.min(tip, h * 0.55));\n\tconst pad = size / 2 + 2;\n\t// A gentle S across the swatch, swelling in the middle.\n\tconst pts = Array.from({ length: 9 }, (_, i) => [pad + ((w - 2 * pad) * i) / 8, h / 2 + Math.sin((i / 8) * Math.PI * 2) * (h / 2 - pad) * 0.6] as const);\n\tconst d = pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(2)} ${y.toFixed(2)}`).join(' ');\n\tconst image = renderShapeBrushstrokeNow(\n\t\t{ kind: 'path', d, stroke: options.color ?? '#1f2937', strokeWidth: size, brush: { brush, seed: 7, size, pressure: [0.35, 1, 0.5] } },\n\t\toptions.scale && options.scale > 0 ? options.scale : 2\n\t);\n\treturn image?.href ?? '';\n}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pathDataToPolyline
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-C2J7GOMJ.js";
|
|
4
4
|
import {
|
|
5
5
|
parseCssColor
|
|
6
6
|
} from "./chunk-CTTF4KYV.js";
|
|
7
7
|
import {
|
|
8
8
|
BUILTIN_BRUSHES
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CPSMARTX.js";
|
|
10
10
|
import {
|
|
11
11
|
formatNumber,
|
|
12
12
|
getShapeSvg,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
brushstrokeDataUrl,
|
|
18
18
|
isBrushstrokeBrush,
|
|
19
19
|
parsePaintSource
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PQFVLOMR.js";
|
|
21
21
|
import "./chunk-63AZAUSN.js";
|
|
22
22
|
import "./chunk-3G6J7UFV.js";
|
|
23
23
|
import "./chunk-6FCKOS2B.js";
|
|
@@ -28,7 +28,7 @@ function listCanvasBrushes() {
|
|
|
28
28
|
return DRY.map((b) => ({ id: b.id, name: b.name, category: b.category, size: b.tip.size }));
|
|
29
29
|
}
|
|
30
30
|
function resolveCanvasBrush(brush, width) {
|
|
31
|
-
const
|
|
31
|
+
const given = width !== void 0 && Number.isFinite(width) ? Math.max(1, width) : void 0;
|
|
32
32
|
if (typeof brush === "string") {
|
|
33
33
|
const preset = BUILTIN_BRUSHES.find((b) => b.id === brush);
|
|
34
34
|
const ids = DRY.map((b) => b.id).join(", ");
|
|
@@ -36,12 +36,12 @@ function resolveCanvasBrush(brush, width) {
|
|
|
36
36
|
if (!isBrushstrokeBrush(preset)) {
|
|
37
37
|
throw new Error(`Brush '${brush}' (${preset.name}) is not a dry brush: brushed canvas strokes use dry media only (wet paint needs an area to flow in; mixer, blender, smudge and eraser brushes need paint under them). Use one of: ${ids}.`);
|
|
38
38
|
}
|
|
39
|
-
return { ...preset, tip: { ...preset.tip, size } };
|
|
39
|
+
return given === void 0 ? preset : { ...preset, tip: { ...preset.tip, size: given } };
|
|
40
40
|
}
|
|
41
41
|
if (!brush || typeof brush !== "object" || Array.isArray(brush)) {
|
|
42
42
|
throw new Error("A brush is a dry paint preset id (see listCanvasBrushes / canvas.listBrushes) or an object of tip settings.");
|
|
43
43
|
}
|
|
44
|
-
return { size, ...brush };
|
|
44
|
+
return { size: given ?? 3, ...brush };
|
|
45
45
|
}
|
|
46
46
|
function resolveCanvasPaint(paint) {
|
|
47
47
|
const source = parsePaintSource(paint, "paint");
|
|
@@ -67,8 +67,11 @@ function strokeColor(shape) {
|
|
|
67
67
|
}
|
|
68
68
|
var cache = new BrushstrokeCache(128);
|
|
69
69
|
var urls = /* @__PURE__ */ new WeakMap();
|
|
70
|
-
function renderShapeBrushstrokeNow(shape, scale) {
|
|
71
|
-
const
|
|
70
|
+
function renderShapeBrushstrokeNow(shape, scale, place = {}) {
|
|
71
|
+
const seed = shape.brush.seed;
|
|
72
|
+
const textured = typeof seed === "number" && Number.isFinite(seed);
|
|
73
|
+
const size = shape.brush.size ?? (textured ? void 0 : shape.strokeWidth ?? 3);
|
|
74
|
+
const brush = resolveCanvasBrush(shape.brush.brush, size);
|
|
72
75
|
const points = pathDataToPolyline(shape.d);
|
|
73
76
|
if (!points.length) return null;
|
|
74
77
|
const { pressure, tiltX, tiltY } = shape.brush;
|
|
@@ -79,7 +82,16 @@ function renderShapeBrushstrokeNow(shape, scale) {
|
|
|
79
82
|
...tiltY?.length ? { tiltY } : {}
|
|
80
83
|
};
|
|
81
84
|
const paint = shapePaint(shape);
|
|
82
|
-
const
|
|
85
|
+
const character = textured ? {
|
|
86
|
+
character: {
|
|
87
|
+
seed,
|
|
88
|
+
...shape.brush.paper !== void 0 ? { paper: shape.brush.paper } : {},
|
|
89
|
+
// Whole canvas units: the grain stays put, and tiny drags do not re-render.
|
|
90
|
+
origin: { x: Math.round(place.origin?.x ?? 0), y: Math.round(place.origin?.y ?? 0) },
|
|
91
|
+
unit: place.unit && place.unit > 0 ? Math.round(place.unit * 1e3) / 1e3 : 1
|
|
92
|
+
}
|
|
93
|
+
} : {};
|
|
94
|
+
const stroke = cache.render(input, brush, { scale, color: strokeColor(shape), ...paint ? { paint } : {}, ...character });
|
|
83
95
|
if (!stroke.bounds) return null;
|
|
84
96
|
let href = urls.get(stroke);
|
|
85
97
|
if (href === void 0) {
|
|
@@ -89,19 +101,35 @@ function renderShapeBrushstrokeNow(shape, scale) {
|
|
|
89
101
|
return { href, ...stroke.bounds, scale: stroke.scale };
|
|
90
102
|
}
|
|
91
103
|
var escapeAttr = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
92
|
-
function brushedShapeSvgNow(shape, size, scale) {
|
|
104
|
+
function brushedShapeSvgNow(shape, size, scale, place = {}) {
|
|
93
105
|
const f = (n) => formatNumber(n, 3);
|
|
94
|
-
const image = renderShapeBrushstrokeNow(shape, scale);
|
|
106
|
+
const image = renderShapeBrushstrokeNow(shape, scale, place);
|
|
95
107
|
const svg = getShapeSvg(shape, size);
|
|
96
108
|
const body = image ? `<image href="${escapeAttr(image.href)}" x="${f(image.x)}" y="${f(image.y)}" width="${f(image.width)}" height="${f(image.height)}" preserveAspectRatio="none"${shape.opacity !== void 0 ? ` opacity="${f(shape.opacity)}"` : ""}/>` : "";
|
|
97
109
|
const content = svg.transform && body ? `<g transform="${svg.transform}">${body}</g>` : body;
|
|
98
110
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${f(size.width)}" height="${f(size.height)}" viewBox="0 0 ${f(size.width)} ${f(size.height)}">${content}</svg>`;
|
|
99
111
|
}
|
|
112
|
+
function brushSwatchNow(brush, options) {
|
|
113
|
+
const w = options.width && options.width > 8 ? options.width : 96;
|
|
114
|
+
const h = options.height && options.height > 4 ? options.height : 24;
|
|
115
|
+
const own = typeof brush === "string" ? resolveCanvasBrush(brush, void 0) : resolveCanvasBrush(brush, brush.size);
|
|
116
|
+
const tip = "tip" in own && own.tip ? own.tip.size ?? 3 : own.size ?? 3;
|
|
117
|
+
const size = Math.max(1.5, Math.min(tip, h * 0.55));
|
|
118
|
+
const pad = size / 2 + 2;
|
|
119
|
+
const pts = Array.from({ length: 9 }, (_, i) => [pad + (w - 2 * pad) * i / 8, h / 2 + Math.sin(i / 8 * Math.PI * 2) * (h / 2 - pad) * 0.6]);
|
|
120
|
+
const d = pts.map(([x, y], i) => `${i ? "L" : "M"}${x.toFixed(2)} ${y.toFixed(2)}`).join(" ");
|
|
121
|
+
const image = renderShapeBrushstrokeNow(
|
|
122
|
+
{ kind: "path", d, stroke: options.color ?? "#1f2937", strokeWidth: size, brush: { brush, seed: 7, size, pressure: [0.35, 1, 0.5] } },
|
|
123
|
+
options.scale && options.scale > 0 ? options.scale : 2
|
|
124
|
+
);
|
|
125
|
+
return image?.href ?? "";
|
|
126
|
+
}
|
|
100
127
|
export {
|
|
128
|
+
brushSwatchNow,
|
|
101
129
|
brushedShapeSvgNow,
|
|
102
130
|
listCanvasBrushes,
|
|
103
131
|
renderShapeBrushstrokeNow,
|
|
104
132
|
resolveCanvasBrush,
|
|
105
133
|
resolveCanvasPaint
|
|
106
134
|
};
|
|
107
|
-
//# sourceMappingURL=brushstrokeRender-
|
|
135
|
+
//# sourceMappingURL=brushstrokeRender-QGEYJ4OZ.js.map
|