@pixerate/editor-react 0.69.0 → 0.70.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/paint-editor/index.ts","../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["export * from './usePaintEditor';\nexport * from './PaintCanvas';\nexport * from './PaintToolbar';\nexport * from './BrushPanel';\nexport * from './PaperPanel';\nexport * from './ColorPanel';\nexport * from './PaintLayersPanel';\nexport * from './PaintEditor';\nexport { PaintSlider } from './shared';\n","import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n\n/**\n * A `PaintPresence` and `PaintDirector` for a paint editor: pass `presence` to `PaintEditor` (or\n * `PaintCanvas`) and `director` to `createPaintEditorToolProvider`, so agent strokes are painted\n * live by a cursor on the canvas. Options are read on the first render.\n */\nexport function usePaintDirector(controller: PaintEditorController, options: Omit<PaintDirectorOptions, 'clock'> = {}): { presence: PaintPresence; director: PaintDirector } {\n const [value] = useState(() => {\n const presence = new PaintPresence();\n return { presence, director: new PaintDirector(controller, presence, options) };\n });\n return value;\n}\n","import React, { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n documentToScreen,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintPresence,\n type PaintTool,\n type PaintView,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n /** Agent cursors to draw over the canvas (see `PaintDirector` and `usePaintDirector`). */\n presence?: PaintPresence;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, presence, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n {presence && <PaintPresenceLayer presence={presence} view={state.view} canvas={doc} viewport={size} />}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/**\n * Agent cursors and notes over the canvas. Positions are document pixels, placed through the view\n * (zoom, pan, rotation, mirroring), while the cursors themselves stay upright and unscaled.\n */\nexport const PaintPresenceLayer: React.FC<{ presence: PaintPresence; view: PaintView; canvas: { width: number; height: number }; viewport: { width: number; height: number } }> = ({ presence, view, canvas, viewport }) => {\n const { actors } = useSyncExternalStore(presence.subscribe, presence.getState, presence.getState);\n return (\n <div className=\"pointer-events-none absolute inset-0 overflow-hidden\" data-paint-presence=\"\" aria-hidden=\"true\">\n {actors.map((a) => {\n const p = documentToScreen(view, canvas, viewport, a.x, a.y);\n return (\n <div key={a.id} className=\"absolute\" style={{ left: p.x, top: p.y }} data-actor={a.id}>\n <svg width=\"18\" height=\"20\" viewBox=\"0 0 18 20\" className=\"drop-shadow-md\" style={{ transform: a.pressed ? 'scale(0.85)' : undefined, transformOrigin: '0 0' }}>\n <path d=\"M0 0 L0 15 L4.5 10.8 L7.6 17 L10.2 15.8 L7.2 9.7 L13.5 9.4 Z\" fill={a.color} stroke=\"white\" strokeWidth=\"1.4\" strokeLinejoin=\"round\" />\n </svg>\n <span className=\"absolute left-4 top-4 w-max max-w-[240px] rounded-md px-2 py-0.5 text-[11px] font-semibold text-white shadow\" style={{ background: a.color }}>\n {a.message ?? a.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport { BRUSH_ROTATIONS, BRUSH_SLIDERS, downloadBytes, patchPath, readPath, type BrushRotation, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited\n * brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n hsvToRgb,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MENU_GROUPS, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MENU_GROUPS.map((g) => (\n <optgroup key={g.label} label={g.label}>\n {g.modes.map((m) => (\n <option key={m.id} value={m.id} title={m.description}>\n {m.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintPresence, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n /** Agent cursors to draw over the canvas (see `usePaintDirector`). */\n presence?: PaintPresence;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, presence, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} presence={presence} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["import_react","import_paint_editor","import_react","import_paint_editor","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../../src/paint-editor/index.ts","../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["export * from './usePaintEditor';\nexport * from './PaintCanvas';\nexport * from './PaintToolbar';\nexport * from './BrushPanel';\nexport * from './PaperPanel';\nexport * from './ColorPanel';\nexport * from './PaintLayersPanel';\nexport * from './PaintEditor';\nexport { PaintSlider } from './shared';\n","import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n\n/**\n * A `PaintPresence` and `PaintDirector` for a paint editor: pass `presence` to `PaintEditor` (or\n * `PaintCanvas`) and `director` to `createPaintEditorToolProvider`, so agent strokes are painted\n * live by a cursor on the canvas. Options are read on the first render.\n */\nexport function usePaintDirector(controller: PaintEditorController, options: Omit<PaintDirectorOptions, 'clock'> = {}): { presence: PaintPresence; director: PaintDirector } {\n const [value] = useState(() => {\n const presence = new PaintPresence();\n return { presence, director: new PaintDirector(controller, presence, options) };\n });\n return value;\n}\n","import React, { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n documentToScreen,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintPresence,\n type PaintTool,\n type PaintView,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n /** Agent cursors to draw over the canvas (see `PaintDirector` and `usePaintDirector`). */\n presence?: PaintPresence;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, presence, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n {presence && <PaintPresenceLayer presence={presence} view={state.view} canvas={doc} viewport={size} />}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/**\n * Agent cursors and notes over the canvas. Positions are document pixels, placed through the view\n * (zoom, pan, rotation, mirroring), while the cursors themselves stay upright and unscaled.\n */\nexport const PaintPresenceLayer: React.FC<{ presence: PaintPresence; view: PaintView; canvas: { width: number; height: number }; viewport: { width: number; height: number } }> = ({ presence, view, canvas, viewport }) => {\n const { actors } = useSyncExternalStore(presence.subscribe, presence.getState, presence.getState);\n return (\n <div className=\"pointer-events-none absolute inset-0 overflow-hidden\" data-paint-presence=\"\" aria-hidden=\"true\">\n {actors.map((a) => {\n const p = documentToScreen(view, canvas, viewport, a.x, a.y);\n return (\n <div key={a.id} className=\"absolute\" style={{ left: p.x, top: p.y }} data-actor={a.id}>\n <svg width=\"18\" height=\"20\" viewBox=\"0 0 18 20\" className=\"drop-shadow-md\" style={{ transform: a.pressed ? 'scale(0.85)' : undefined, transformOrigin: '0 0' }}>\n <path d=\"M0 0 L0 15 L4.5 10.8 L7.6 17 L10.2 15.8 L7.2 9.7 L13.5 9.4 Z\" fill={a.color} stroke=\"white\" strokeWidth=\"1.4\" strokeLinejoin=\"round\" />\n </svg>\n <span className=\"absolute left-4 top-4 w-max max-w-[240px] rounded-md px-2 py-0.5 text-[11px] font-semibold text-white shadow\" style={{ background: a.color }}>\n {a.message ?? a.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n BLEND_MENU_GROUPS,\n BRUSH_ROTATIONS,\n BRUSH_SLIDERS,\n brushEngineControls,\n brushLoadColor,\n downloadBytes,\n multiColorSliders,\n patchBrushValue,\n patchPath,\n readPath,\n type BlendMode,\n type BrushRotation,\n type MultiColorMode,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics, rotation mode and blend mode;\n * then the engine's own controls (`brushEngineControls`): blender strength and blend distance,\n * smudge strength and length, pick-up and mix ratios, RGB / pigment mixing, dirty brush,\n * multi-colour and the brush load. Save the edited brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const engine = brushEngineControls(brush);\n const mc = brush.behavior.multicolor;\n const carried = brushLoadColor(state.mixerLoad);\n const setColors = (colors: string[]) => controller.setBrush({ behavior: { multicolor: { colors } } });\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n {brush.engine === 'dab' && (\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Blend</span>\n <select aria-label=\"Brush blend\" value={brush.tip.blend} onChange={(e) => controller.setBrush({ tip: { blend: e.target.value as BlendMode } })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BLEND_MENU_GROUPS.map((g) => (\n <optgroup key={g.label} label={g.label}>\n {g.modes.map((m) => (\n <option key={m.id} value={m.id} title={m.description}>\n {m.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n </label>\n )}\n </div>\n {engine && (\n <div className=\"flex flex-col gap-1.5\" data-testid=\"brush-engine\">\n <span className=\"font-medium text-slate-300\">{engine.title}</span>\n {engine.sliders.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n {engine.mixingPath && (\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Mixing</span>\n <select\n aria-label=\"Brush mixing\"\n value={engine.mixingPath === 'blender.mixing' ? brush.blender.mixing : engine.mixingPath === 'smudge.mixing' ? brush.smudge.mixing : brush.behavior.mixing}\n onChange={(e) => controller.setBrush(patchBrushValue(brush, engine.mixingPath!, e.target.value))}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value=\"pigment\">Pigment</option>\n <option value=\"rgb\">RGB</option>\n </select>\n </label>\n )}\n {engine.dirty && (\n <label className=\"flex items-center gap-2\" title=\"Keep the colour the brush picked up for the next stroke (needs Pick-up above 0)\">\n <input type=\"checkbox\" aria-label=\"Dirty brush\" checked={brush.behavior.dirty} onChange={(e) => controller.setBrush({ behavior: { dirty: e.target.checked } })} /> Dirty brush\n </label>\n )}\n {engine.multicolor && (\n <div className=\"flex flex-col gap-1.5\" data-testid=\"multicolor\">\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Multi-colour</span>\n <select aria-label=\"Multi-colour\" value={mc.mode} onChange={(e) => controller.setBrush({ behavior: { multicolor: { mode: e.target.value as MultiColorMode } } })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n <option value=\"off\">Off</option>\n <option value=\"tip\">Across the tip</option>\n <option value=\"dab\">Per dab</option>\n </select>\n </label>\n {mc.mode !== 'off' && (\n <>\n <div className=\"flex flex-wrap items-center gap-1\" aria-label=\"Multi-colour colours\">\n {mc.colors.map((col, i) => (\n <span key={i} className=\"flex items-center\">\n <input type=\"color\" aria-label={`Multi-colour ${i + 1}`} value={col} onChange={(e) => setColors(mc.colors.map((x, j) => (j === i ? e.target.value : x)))} className=\"h-5 w-6 rounded bg-transparent\" />\n <button type=\"button\" aria-label={`Remove multi-colour ${i + 1}`} className=\"px-0.5 text-slate-500 hover:text-white\" onClick={() => setColors(mc.colors.filter((_, j) => j !== i))}>\n ×\n </button>\n </span>\n ))}\n {mc.colors.length < 8 && (\n <button type=\"button\" className={button} aria-label=\"Add multi-colour\" onClick={() => setColors([...(mc.colors.length ? mc.colors : [state.color, state.secondaryColor]), state.color].slice(0, 8))}>\n +\n </button>\n )}\n {mc.colors.length < 2 && <span className=\"text-[10px] text-slate-500\">Uses the paint and second colours</span>}\n </div>\n {mc.mode === 'dab' && (\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Order</span>\n <select aria-label=\"Colour order\" value={mc.order} onChange={(e) => controller.setBrush({ behavior: { multicolor: { order: e.target.value as 'sequence' | 'random' } } })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n <option value=\"sequence\">In order</option>\n <option value=\"random\">Random</option>\n </select>\n </label>\n )}\n {multiColorSliders(mc.mode).map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n </>\n )}\n </div>\n )}\n {engine.load && (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Carries</span>\n <span aria-label=\"Brush load\" title={carried ?? 'Clean'} className=\"h-4 w-4 rounded ring-1 ring-slate-700\" style={{ background: carried ?? 'transparent' }} />\n {brush.engine === 'mixer' && (\n <button type=\"button\" className={button} onClick={() => controller.loadMixerBrush()}>\n Load\n </button>\n )}\n <button type=\"button\" className={button} onClick={() => controller.cleanMixerBrush(brush.engine === 'mixer')}>\n Clean\n </button>\n </div>\n )}\n </div>\n )}\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n PAD_SAMPLE_SIZES,\n hsvToRgb,\n padSampleRadius,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from (with a sample size), mix the paint\n * and second colours in measured parts on, and keep by name.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const [sample, setSample] = useState(3);\n const [parts, setParts] = useState<[number, number]>([1, 1]);\n const [padName, setPadName] = useState('');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true, radius: padSampleRadius(sample) }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <label className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Sample</span>\n <select aria-label=\"Pick sample size\" value={sample} onChange={(e) => setSample(Number(e.target.value))} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {PAD_SAMPLE_SIZES.map((n) => (\n <option key={n} value={n}>\n {n === 1 ? '1 px' : `${n}×${n}`}\n </option>\n ))}\n </select>\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <span className=\"h-4 w-4 rounded ring-1 ring-slate-700\" style={{ background: color }} />\n <input type=\"number\" aria-label=\"Paint colour parts\" min={0} max={20} value={parts[0]} onChange={(e) => setParts([Number(e.target.value), parts[1]])} className=\"w-10 rounded bg-slate-800 px-1 py-0.5\" />\n <span className=\"text-slate-500\">:</span>\n <input type=\"number\" aria-label=\"Second colour parts\" min={0} max={20} value={parts[1]} onChange={(e) => setParts([parts[0], Number(e.target.value)])} className=\"w-10 rounded bg-slate-800 px-1 py-0.5\" />\n <span className=\"h-4 w-4 rounded ring-1 ring-slate-700\" style={{ background: state.secondaryColor }} />\n <button\n type=\"button\"\n className={button}\n title=\"Mix the paint and second colours in these parts on the pad, and use the mix\"\n onClick={() =>\n attempt(() =>\n controller.mixOnPad(\n [\n { color, parts: parts[0] },\n { color: state.secondaryColor, parts: parts[1] },\n ],\n { setColor: true }\n )\n )\n }\n >\n Mix\n </button>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={padName} placeholder=\"Pad name\" aria-label=\"Pad name\" onChange={(e) => setPadName(e.target.value)} className=\"w-24 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => (controller.saveMixingPad(padName || undefined), setPadName('')))}>\n Keep pad\n </button>\n </div>\n {state.savedMixingPads.length > 0 && (\n <ul className=\"flex flex-col gap-0.5\" aria-label=\"Kept pads\">\n {state.savedMixingPads.map((p) => (\n <li key={p.id} className=\"flex items-center gap-1\">\n <button type=\"button\" className={`${button} flex-1 text-left`} onClick={() => attempt(() => controller.loadMixingPad(p.id))}>\n {p.name}\n </button>\n <button type=\"button\" className={button} aria-label={`Remove ${p.name}`} onClick={() => attempt(() => controller.removeMixingPad(p.id))}>\n ×\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MENU_GROUPS, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MENU_GROUPS.map((g) => (\n <optgroup key={g.label} label={g.label}>\n {g.modes.map((m) => (\n <option key={m.id} value={m.id} title={m.description}>\n {m.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintPresence, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n /** Agent cursors to draw over the canvas (see `usePaintDirector`). */\n presence?: PaintPresence;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, presence, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} presence={presence} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["import_react","import_paint_editor","import_react","import_paint_editor","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_jsx_runtime"]}
@@ -87,8 +87,10 @@ interface BrushPanelProps {
87
87
  /**
88
88
  * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by
89
89
  * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,
90
- * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited
91
- * brush, import and export libraries as JSON.
90
+ * angle, paper grain, position and pressure smoothing, dynamics, rotation mode and blend mode;
91
+ * then the engine's own controls (`brushEngineControls`): blender strength and blend distance,
92
+ * smudge strength and length, pick-up and mix ratios, RGB / pigment mixing, dirty brush,
93
+ * multi-colour and the brush load. Save the edited brush, import and export libraries as JSON.
92
94
  */
93
95
  declare const BrushPanel: React__default.FC<BrushPanelProps>;
94
96
 
@@ -114,7 +116,8 @@ interface ColorPanelProps {
114
116
  /**
115
117
  * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and
116
118
  * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,
117
- * smear with a palette knife (pigment mixing) and pick from.
119
+ * smear with a palette knife (pigment mixing) and pick from (with a sample size), mix the paint
120
+ * and second colours in measured parts on, and keep by name.
118
121
  */
119
122
  declare const ColorPanel: React__default.FC<ColorPanelProps>;
120
123
 
@@ -87,8 +87,10 @@ interface BrushPanelProps {
87
87
  /**
88
88
  * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by
89
89
  * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,
90
- * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited
91
- * brush, import and export libraries as JSON.
90
+ * angle, paper grain, position and pressure smoothing, dynamics, rotation mode and blend mode;
91
+ * then the engine's own controls (`brushEngineControls`): blender strength and blend distance,
92
+ * smudge strength and length, pick-up and mix ratios, RGB / pigment mixing, dirty brush,
93
+ * multi-colour and the brush load. Save the edited brush, import and export libraries as JSON.
92
94
  */
93
95
  declare const BrushPanel: React__default.FC<BrushPanelProps>;
94
96
 
@@ -114,7 +116,8 @@ interface ColorPanelProps {
114
116
  /**
115
117
  * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and
116
118
  * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,
117
- * smear with a palette knife (pigment mixing) and pick from.
119
+ * smear with a palette knife (pigment mixing) and pick from (with a sample size), mix the paint
120
+ * and second colours in measured parts on, and keep by name.
118
121
  */
119
122
  declare const ColorPanel: React__default.FC<ColorPanelProps>;
120
123