@pixerate/editor-svelte 0.212.0 → 0.213.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.
@@ -0,0 +1,90 @@
1
+ <script lang="ts">
2
+ import { CULTURE_SLIDERS, readPath, type PaintEditorController } from '@pixerate/editor/paint-editor';
3
+ import PaintSlider from './PaintSlider.svelte';
4
+ import { attempt, button, chip, paintEditorState, panel } from './paintEditorRune.svelte.js';
5
+
6
+ interface Props {
7
+ controller: PaintEditorController;
8
+ class?: string;
9
+ }
10
+ let { controller, class: className = '' }: Props = $props();
11
+ const editor = paintEditorState(() => controller);
12
+ const cultures = $derived(editor.current.cultures);
13
+ const brush = $derived(editor.current.brush);
14
+ const activeColony = $derived.by(() => {
15
+ const activeId = editor.current.document.activeLayerId;
16
+ return cultures.layers.find((l) => l.layerId === activeId) ?? cultures.layers[0] ?? null;
17
+ });
18
+ const totalTips = $derived(cultures.layers.reduce((acc, l) => acc + l.tips, 0));
19
+ const totalSegments = $derived(cultures.layers.reduce((acc, l) => acc + l.segments, 0));
20
+ const canCarryCulture = $derived(['dab', 'mixer', 'impasto', 'particle', 'bristle'].includes(brush.engine));
21
+ let error = $state<string | null>(null);
22
+ const run = (fn: () => unknown) => attempt(fn, (m) => (error = m));
23
+ </script>
24
+
25
+ <!-- Biopaint (culture) panel: inspect living mycelial colonies, step growth, pause/resume, kill tips, and tune brush spores. -->
26
+ <div class={`${panel} ${className}`} data-testid="culture-panel">
27
+ <div class="flex items-center justify-between">
28
+ <span class="font-medium text-slate-300">Biopaint (mycelial ink)</span>
29
+ <div class="flex gap-1">
30
+ <button type="button" class={button} onclick={() => run(() => controller.growCultures({ steps: 40 }))}>Grow</button>
31
+ <button
32
+ type="button"
33
+ aria-pressed={cultures.paused}
34
+ class={chip(cultures.paused)}
35
+ onclick={() => controller.setCulturePaused(!cultures.paused)}
36
+ >
37
+ {cultures.paused ? 'Paused' : 'Pause'}
38
+ </button>
39
+ <button
40
+ type="button"
41
+ class={button}
42
+ disabled={!activeColony || activeColony.tips === 0}
43
+ onclick={() => run(() => controller.removeCultures(activeColony?.layerId))}
44
+ >
45
+ Kill colony
46
+ </button>
47
+ </div>
48
+ </div>
49
+ <div class="flex items-center justify-between text-[11px] text-slate-400">
50
+ <span>
51
+ {activeColony
52
+ ? `${totalTips} living tips · ${totalSegments} segments (${activeColony.status})`
53
+ : 'No mycelial colony on canvas'}
54
+ </span>
55
+ </div>
56
+ <label class="flex items-center gap-2 text-[11px]">
57
+ <input
58
+ type="checkbox"
59
+ checked={cultures.growWhileClosed}
60
+ onchange={(e) => run(() => controller.setCultureOptions({ growWhileClosed: e.currentTarget.checked }))}
61
+ />
62
+ Grow while closed
63
+ </label>
64
+ {#if canCarryCulture}
65
+ <div class="flex flex-col gap-1 border-t border-slate-800 pt-1.5">
66
+ <div class="flex items-center justify-between">
67
+ <span class="text-[11px] text-slate-400">Brush spores</span>
68
+ <button
69
+ type="button"
70
+ aria-pressed={Boolean(brush.culture)}
71
+ class={chip(Boolean(brush.culture))}
72
+ onclick={() => run(() => controller.setBrush({ culture: brush.culture ? null : {} }))}
73
+ >
74
+ {brush.culture ? 'On' : 'Off'}
75
+ </button>
76
+ </div>
77
+ {#if brush.culture}
78
+ {#each CULTURE_SLIDERS as c (c.path)}
79
+ {@const key = c.path.replace(/^culture\./, '')}
80
+ <PaintSlider
81
+ control={c}
82
+ value={readPath(brush.culture, key)}
83
+ oncommit={(v) => run(() => controller.setBrush({ culture: { [key]: v } }))}
84
+ />
85
+ {/each}
86
+ {/if}
87
+ </div>
88
+ {/if}
89
+ {#if error}<p role="alert" class="text-[11px] text-rose-400">{error}</p>{/if}
90
+ </div>
@@ -0,0 +1,8 @@
1
+ import { type PaintEditorController } from '@pixerate/editor/paint-editor';
2
+ interface Props {
3
+ controller: PaintEditorController;
4
+ class?: string;
5
+ }
6
+ declare const CulturePanel: import("svelte").Component<Props, {}, "">;
7
+ type CulturePanel = ReturnType<typeof CulturePanel>;
8
+ export default CulturePanel;
@@ -140,11 +140,16 @@
140
140
  });
141
141
  });
142
142
 
143
- // Live effect paint plays while the canvas is mounted (idle when nothing is live or it is paused).
143
+ // Live effect paint and biopaint cultures play while the canvas is mounted (idle when nothing is live or paused).
144
144
  $effect(() => {
145
145
  const c = controller;
146
+ untrack(() => c.catchUpCultures());
146
147
  const player = untrack(() => c.playEffects());
147
- return () => player.stop();
148
+ const cultures = untrack(() => c.playCultures());
149
+ return () => {
150
+ player.stop();
151
+ cultures.stop();
152
+ };
148
153
  });
149
154
 
150
155
  // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).
@@ -5,6 +5,7 @@
5
5
  import PixelCanvas from './PixelCanvas.svelte';
6
6
  import FerroPanel from './FerroPanel.svelte';
7
7
  import TimeMachinePanel from './TimeMachinePanel.svelte';
8
+ import CulturePanel from './CulturePanel.svelte';
8
9
  import { attempt, button, chip, paintEditorState, panel } from './paintEditorRune.svelte.js';
9
10
 
10
11
  interface Props {
@@ -106,5 +107,6 @@
106
107
  </div>
107
108
  <FerroPanel {controller} />
108
109
  <TimeMachinePanel {controller} />
110
+ <CulturePanel {controller} />
109
111
  {#if error}<p role="alert" class="text-[11px] text-rose-400">{error}</p>{/if}
110
112
  </div>
@@ -8,6 +8,7 @@ import type BrushLibraryBrowserComponent from '../brushes/BrushLibraryBrowser.sv
8
8
  import type PaperPanelComponent from './PaperPanel.svelte';
9
9
  import type FerroPanelComponent from './FerroPanel.svelte';
10
10
  import type TimeMachinePanelComponent from './TimeMachinePanel.svelte';
11
+ import type CulturePanelComponent from './CulturePanel.svelte';
11
12
  import type ColorPanelComponent from './ColorPanel.svelte';
12
13
  import type PaintLayersPanelComponent from './PaintLayersPanel.svelte';
13
14
  import type WetPanelComponent from './WetPanel.svelte';
@@ -27,6 +28,7 @@ export { default as BrushLibraryBrowser } from '../brushes/BrushLibraryBrowser.s
27
28
  export { default as PaperPanel } from './PaperPanel.svelte';
28
29
  export { default as FerroPanel } from './FerroPanel.svelte';
29
30
  export { default as TimeMachinePanel } from './TimeMachinePanel.svelte';
31
+ export { default as CulturePanel } from './CulturePanel.svelte';
30
32
  export { default as ColorPanel } from './ColorPanel.svelte';
31
33
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
32
34
  export { default as WetPanel } from './WetPanel.svelte';
@@ -51,6 +53,7 @@ export type BrushLibraryBrowserProps = ComponentProps<typeof BrushLibraryBrowser
51
53
  export type PaperPanelProps = ComponentProps<typeof PaperPanelComponent>;
52
54
  export type FerroPanelProps = ComponentProps<typeof FerroPanelComponent>;
53
55
  export type TimeMachinePanelProps = ComponentProps<typeof TimeMachinePanelComponent>;
56
+ export type CulturePanelProps = ComponentProps<typeof CulturePanelComponent>;
54
57
  export type ColorPanelProps = ComponentProps<typeof ColorPanelComponent>;
55
58
  export type PaintLayersPanelProps = ComponentProps<typeof PaintLayersPanelComponent>;
56
59
  export type WetPanelProps = ComponentProps<typeof WetPanelComponent>;
@@ -9,6 +9,7 @@ export { default as BrushLibraryBrowser } from '../brushes/BrushLibraryBrowser.s
9
9
  export { default as PaperPanel } from './PaperPanel.svelte';
10
10
  export { default as FerroPanel } from './FerroPanel.svelte';
11
11
  export { default as TimeMachinePanel } from './TimeMachinePanel.svelte';
12
+ export { default as CulturePanel } from './CulturePanel.svelte';
12
13
  export { default as ColorPanel } from './ColorPanel.svelte';
13
14
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
14
15
  export { default as WetPanel } from './WetPanel.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.212.0",
3
+ "version": "0.213.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -184,7 +184,7 @@
184
184
  "**/*.css"
185
185
  ],
186
186
  "dependencies": {
187
- "@pixerate/editor": "0.284.0"
187
+ "@pixerate/editor": "0.285.0"
188
188
  },
189
189
  "peerDependencies": {
190
190
  "@dagrejs/dagre": "^1.1.4",