@pixerate/editor-svelte 0.88.1 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/animation-editor/AnimationEditor.svelte +12 -1
  2. package/dist/animation-editor/AnimationEditor.svelte.d.ts +7 -0
  3. package/dist/animation-editor/AnimationEditor.svelte.d.ts.map +1 -1
  4. package/dist/animation-editor/AnimationEffectControls.svelte +35 -0
  5. package/dist/animation-editor/AnimationEffectControls.svelte.d.ts +11 -0
  6. package/dist/animation-editor/AnimationEffectControls.svelte.d.ts.map +1 -0
  7. package/dist/animation-editor/AnimationEffectsPanel.svelte +71 -0
  8. package/dist/animation-editor/AnimationEffectsPanel.svelte.d.ts +11 -0
  9. package/dist/animation-editor/AnimationEffectsPanel.svelte.d.ts.map +1 -0
  10. package/dist/animation-editor/createAnimationEditor.svelte.d.ts +7 -1
  11. package/dist/animation-editor/createAnimationEditor.svelte.d.ts.map +1 -1
  12. package/dist/animation-editor/createAnimationEditor.svelte.js +14 -1
  13. package/dist/animation-editor/index.d.ts +1 -0
  14. package/dist/animation-editor/index.d.ts.map +1 -1
  15. package/dist/animation-editor/index.js +1 -0
  16. package/dist/effects/EffectThumbnail.svelte +7 -3
  17. package/dist/effects/EffectThumbnail.svelte.d.ts.map +1 -1
  18. package/dist/effects/EffectsBrowser.svelte +5 -3
  19. package/dist/effects/EffectsBrowser.svelte.d.ts +3 -1
  20. package/dist/effects/EffectsBrowser.svelte.d.ts.map +1 -1
  21. package/dist/paint-editor/PaintEditor.svelte +8 -4
  22. package/dist/paint-editor/PaintEditor.svelte.d.ts.map +1 -1
  23. package/dist/paint-editor/PaintEffectsPanel.svelte +127 -0
  24. package/dist/paint-editor/PaintEffectsPanel.svelte.d.ts +9 -0
  25. package/dist/paint-editor/PaintEffectsPanel.svelte.d.ts.map +1 -0
  26. package/dist/paint-editor/index.d.ts +4 -1
  27. package/dist/paint-editor/index.d.ts.map +1 -1
  28. package/dist/paint-editor/index.js +2 -1
  29. package/dist/paint-editor/paintEditorRune.svelte.d.ts +13 -1
  30. package/dist/paint-editor/paintEditorRune.svelte.d.ts.map +1 -1
  31. package/dist/paint-editor/paintEditorRune.svelte.js +32 -1
  32. package/dist/vector/VectorEditor.svelte +16 -2
  33. package/dist/vector/VectorEditor.svelte.d.ts +7 -0
  34. package/dist/vector/VectorEditor.svelte.d.ts.map +1 -1
  35. package/dist/vector/VectorProviderEffectControls.svelte +37 -0
  36. package/dist/vector/VectorProviderEffectControls.svelte.d.ts +9 -0
  37. package/dist/vector/VectorProviderEffectControls.svelte.d.ts.map +1 -0
  38. package/dist/vector/VectorProviderEffectsPanel.svelte +63 -0
  39. package/dist/vector/VectorProviderEffectsPanel.svelte.d.ts +9 -0
  40. package/dist/vector/VectorProviderEffectsPanel.svelte.d.ts.map +1 -0
  41. package/dist/vector/createVectorEditor.svelte.d.ts +8 -1
  42. package/dist/vector/createVectorEditor.svelte.d.ts.map +1 -1
  43. package/dist/vector/createVectorEditor.svelte.js +14 -1
  44. package/dist/vector/index.d.ts +1 -0
  45. package/dist/vector/index.d.ts.map +1 -1
  46. package/dist/vector/index.js +1 -0
  47. package/package.json +2 -2
@@ -7,6 +7,9 @@
7
7
  import SceneSettings from './SceneSettings.svelte';
8
8
  import ShotInspector from './ShotInspector.svelte';
9
9
  import { animationEditorStateOf } from './createAnimationEditor.svelte.js';
10
+ import type { EffectProvider } from '@pixerate/editor/effects';
11
+ import { useEffects } from '../effects/effects.svelte.js';
12
+ import AnimationEffectsPanel from './AnimationEffectsPanel.svelte';
10
13
 
11
14
  interface Props {
12
15
  controller: AnimationEditorController;
@@ -23,10 +26,17 @@
23
26
  * scrubber and issues only.
24
27
  */
25
28
  editable?: boolean;
29
+ /**
30
+ * An effects provider (see `@pixerate/editor/effects`), registered with the controller while
31
+ * mounted: provider motion applied to the picked element and vector effects, with an Effects
32
+ * panel. Optional: without one the editor is as before.
33
+ */
34
+ effects?: EffectProvider | null;
26
35
  class?: string;
27
36
  }
28
37
 
29
- let { controller, values, onionSkin, motionPaths, showIssues = true, editable = true, class: className = '' }: Props = $props();
38
+ let { controller, values, onionSkin, motionPaths, showIssues = true, editable = true, effects, class: className = '' }: Props = $props();
39
+ useEffects(() => controller, () => effects);
30
40
  const view = animationEditorStateOf(() => controller);
31
41
  const editor = $derived(view.current);
32
42
  const ONION: MotionOnionSkin = { before: 3, after: 1 };
@@ -115,6 +125,7 @@
115
125
  </div>
116
126
  <div class="flex min-w-0 flex-col gap-3">
117
127
  <CommandList {controller} targets={pickedValid ? [pickedValid] : undefined} />
128
+ {#if editor.effectsProvider || controller.appliedEffects().length > 0}<AnimationEffectsPanel {controller} node={pickedValid} class="border-t border-border pt-2" />{/if}
118
129
  <CommandInspector {controller} picked={pickedValid} class="border-t border-border pt-2" />
119
130
  <details open class="border-t border-border pt-2">
120
131
  <summary class="cursor-pointer text-xs font-medium">Shot</summary>
@@ -1,4 +1,5 @@
1
1
  import { type AnimationEditorController, type MotionFrameOptions, type MotionOnionSkin } from '@pixerate/editor/animation-editor';
2
+ import type { EffectProvider } from '@pixerate/editor/effects';
2
3
  interface Props {
3
4
  controller: AnimationEditorController;
4
5
  values?: MotionFrameOptions['values'];
@@ -14,6 +15,12 @@ interface Props {
14
15
  * scrubber and issues only.
15
16
  */
16
17
  editable?: boolean;
18
+ /**
19
+ * An effects provider (see `@pixerate/editor/effects`), registered with the controller while
20
+ * mounted: provider motion applied to the picked element and vector effects, with an Effects
21
+ * panel. Optional: without one the editor is as before.
22
+ */
23
+ effects?: EffectProvider | null;
17
24
  class?: string;
18
25
  }
19
26
  declare const AnimationEditor: import("svelte").Component<Props, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"AnimationEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/AnimationEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,KAAK,yBAAyB,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAUnK,UAAU,KAAK;IACb,UAAU,EAAE,yBAAyB,CAAC;IACtC,MAAM,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,kHAAkH;IAClH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,oGAAoG;IACpG,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IAC1C,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqGH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"AnimationEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/AnimationEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,KAAK,yBAAyB,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAQrK,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK7D,UAAU,KAAK;IACb,UAAU,EAAE,yBAAyB,CAAC;IACtC,MAAM,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,kHAAkH;IAClH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,oGAAoG;IACpG,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IAC1C,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0GH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import type { AnimationEditorController, MotionEffectResult } from '@pixerate/editor/animation-editor';
3
+ import EffectParameters from '../effects/EffectParameters.svelte';
4
+ import { effectDescriptionOf } from '../effects/effects.svelte.js';
5
+
6
+ interface Props {
7
+ controller: AnimationEditorController;
8
+ instance: string;
9
+ effect: string;
10
+ values: Readonly<Record<string, unknown>>;
11
+ }
12
+
13
+ let { controller, instance, effect, values }: Props = $props();
14
+ const loaded = effectDescriptionOf(() => controller.effectsProvider, () => effect);
15
+ let message = $state<string | null>(null);
16
+ const report = (r: Promise<MotionEffectResult>) => void r.then((x) => (message = x.ok ? null : x.error));
17
+ </script>
18
+
19
+ <!-- One applied effect's controls, loaded from the provider. -->
20
+ {#if !controller.effectsProvider}
21
+ <p class="text-[11px] text-muted-foreground">No effects provider: its commands are kept as they are.</p>
22
+ {:else if loaded.error}
23
+ <p class="text-[11px] text-amber-500">{loaded.error}</p>
24
+ {:else if !loaded.description}
25
+ <p class="text-[11px] text-muted-foreground">Loading…</p>
26
+ {:else}
27
+ <EffectParameters
28
+ description={loaded.description}
29
+ {values}
30
+ onchange={(k, v, g) => report(controller.updateMotionEffect(instance, { [k]: v as never }, { merge: g ?? undefined }))}
31
+ onreset={(k) => report(controller.updateMotionEffect(instance, { [k]: null }))}
32
+ onpreset={(v) => report(controller.updateMotionEffect(instance, v as never))}
33
+ />
34
+ {#if message}<p role="alert" class="text-[11px] text-destructive">{message}</p>{/if}
35
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { AnimationEditorController } from '@pixerate/editor/animation-editor';
2
+ interface Props {
3
+ controller: AnimationEditorController;
4
+ instance: string;
5
+ effect: string;
6
+ values: Readonly<Record<string, unknown>>;
7
+ }
8
+ declare const AnimationEffectControls: import("svelte").Component<Props, {}, "">;
9
+ type AnimationEffectControls = ReturnType<typeof AnimationEffectControls>;
10
+ export default AnimationEffectControls;
11
+ //# sourceMappingURL=AnimationEffectControls.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnimationEffectControls.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/AnimationEffectControls.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAsB,MAAM,mCAAmC,CAAC;AAKrG,UAAU,KAAK;IACb,UAAU,EAAE,yBAAyB,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3C;AA2BH,QAAA,MAAM,uBAAuB,2CAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,71 @@
1
+ <script lang="ts">
2
+ import { indexMotionNodes, type AnimationEditorController, type MotionEffectResult } from '@pixerate/editor/animation-editor';
3
+ import EffectsBrowser from '../effects/EffectsBrowser.svelte';
4
+ import AnimationEffectControls from './AnimationEffectControls.svelte';
5
+ import { animationEditorStateOf } from './createAnimationEditor.svelte.js';
6
+
7
+ interface Props {
8
+ controller: AnimationEditorController;
9
+ /** The node motion effects are applied to (e.g. the element picked on the stage). */
10
+ node?: string | null;
11
+ class?: string;
12
+ }
13
+
14
+ let { controller, node = null, class: className = '' }: Props = $props();
15
+ const view = animationEditorStateOf(() => controller);
16
+ const ed = $derived(view.current);
17
+ const provider = $derived(ed.effectsProvider);
18
+ const nodes = $derived([...indexMotionNodes(ed.scene.artwork.nodes).keys()]);
19
+ let chosen = $state('');
20
+ const target = $derived(node && nodes.includes(node) ? node : chosen && nodes.includes(chosen) ? chosen : '');
21
+ let browse = $state<null | 'motion' | 'vector'>(null);
22
+ let open = $state<string | null>(null);
23
+ let message = $state<string | null>(null);
24
+ const applied = $derived.by(() => {
25
+ void ed.scene;
26
+ return controller.appliedEffects();
27
+ });
28
+ const btn = 'rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40';
29
+ function report(r: MotionEffectResult | Promise<MotionEffectResult>) {
30
+ void Promise.resolve(r).then((x) => (message = x.ok ? (x.notes.length ? x.notes.join(' ') : null) : x.error));
31
+ }
32
+ </script>
33
+
34
+ <!--
35
+ Provider effects in an animation: apply a motion effect to a node (its changes become commands in
36
+ a new shot), add a vector effect with its own picture, and change or remove the effects the scene
37
+ holds. Every change is one undo step (a slider drag is one).
38
+ -->
39
+ <section class="flex flex-col gap-2 text-xs {className}" aria-label="Effects" data-animation-effects="">
40
+ <div class="flex flex-wrap items-center gap-1">
41
+ <span class="flex-1 font-semibold">Effects</span>
42
+ <select class="rounded border border-border bg-transparent px-1 py-0.5 text-[11px]" aria-label="Node to animate" value={target} disabled={!!node} onchange={(e) => (chosen = e.currentTarget.value)}>
43
+ <option value="">Node…</option>
44
+ {#each nodes as id (id)}<option value={id}>{id}</option>{/each}
45
+ </select>
46
+ <button type="button" class={btn} disabled={ed.readOnly || !provider || !target} aria-pressed={browse === 'motion'} onclick={() => (browse = browse === 'motion' ? null : 'motion')}>Animate…</button>
47
+ <button type="button" class={btn} disabled={ed.readOnly || !provider} aria-pressed={browse === 'vector'} onclick={() => (browse = browse === 'vector' ? null : 'vector')}>Vector effect…</button>
48
+ </div>
49
+ {#if !provider}<p class="text-[11px] text-muted-foreground">No effects provider is registered. Commands effects made are kept.</p>{/if}
50
+ {#if browse === 'motion'}
51
+ <EffectsBrowser {provider} uses={['motion']} kinds={['motion']} title="Motion for {target}" onpick={(e) => ((browse = null), report(controller.applyMotionEffect(e.id, [target])))} />
52
+ {/if}
53
+ {#if browse === 'vector'}
54
+ <EffectsBrowser {provider} kinds={['vector']} title="Vector effects" onpick={(e) => ((browse = null), report(controller.addVectorEffect(e.id)))} />
55
+ {/if}
56
+ <ol class="space-y-1">
57
+ {#each applied as e (e.instance)}
58
+ <li class="rounded border border-border p-1" data-motion-effect={e.instance}>
59
+ <div class="flex items-center gap-1">
60
+ <button type="button" class="min-w-0 flex-1 truncate text-left" aria-expanded={open === e.instance} onclick={() => (open = open === e.instance ? null : e.instance)}>
61
+ {e.name ?? e.effect} <span class="text-muted-foreground">· {e.kind === 'vector' ? 'picture' : e.targets.join(', ')}</span>
62
+ </button>
63
+ <button type="button" class={btn} disabled={ed.readOnly} aria-label="Remove {e.name ?? e.effect}" onclick={() => report(controller.removeMotionEffect(e.instance))}>✕</button>
64
+ </div>
65
+ {#if open === e.instance}<div class="mt-1"><AnimationEffectControls {controller} instance={e.instance} effect={e.effect} values={e.values} /></div>{/if}
66
+ </li>
67
+ {/each}
68
+ </ol>
69
+ {#if !applied.length}<p class="text-[11px] text-muted-foreground">No provider effects in this scene.</p>{/if}
70
+ {#if message}<p role="status" class="text-[11px] text-muted-foreground" data-effects-message="">{message}</p>{/if}
71
+ </section>
@@ -0,0 +1,11 @@
1
+ import { type AnimationEditorController } from '@pixerate/editor/animation-editor';
2
+ interface Props {
3
+ controller: AnimationEditorController;
4
+ /** The node motion effects are applied to (e.g. the element picked on the stage). */
5
+ node?: string | null;
6
+ class?: string;
7
+ }
8
+ declare const AnimationEffectsPanel: import("svelte").Component<Props, {}, "">;
9
+ type AnimationEffectsPanel = ReturnType<typeof AnimationEffectsPanel>;
10
+ export default AnimationEffectsPanel;
11
+ //# sourceMappingURL=AnimationEffectsPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnimationEffectsPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/AnimationEffectsPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,yBAAyB,EAA2B,MAAM,mCAAmC,CAAC;AAM5H,UAAU,KAAK;IACb,UAAU,EAAE,yBAAyB,CAAC;IACtC,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiEH,QAAA,MAAM,qBAAqB,2CAAwC,CAAC;AACpE,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACtE,eAAe,qBAAqB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { AnimationEditorController, type AnimationEditorOptions, type AnimationEditorState, type AnimationEditorToolProviderOptions } from "@pixerate/editor/animation-editor";
1
+ import { AnimationEditorController, type AnimationEffectsToolProviderOptions, type AnimationEditorOptions, type AnimationEditorState, type AnimationEditorToolProviderOptions } from "@pixerate/editor/animation-editor";
2
2
  import type { ToolRegistry } from "@pixerate/editor/tools";
3
3
  export interface SvelteAnimationEditor {
4
4
  readonly controller: AnimationEditorController;
@@ -30,4 +30,10 @@ export declare function animationEditorStateOf(getController: () => AnimationEdi
30
30
  * initialisation). Pass a getter to follow a changing registry.
31
31
  */
32
32
  export declare function useAnimationEditorTools(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: AnimationEditorController, options?: AnimationEditorToolProviderOptions): void;
33
+ /**
34
+ * Registers the animation editor's provider-effect tools (`search_effects`, `apply_effect`,
35
+ * `add_vector_effect`, …) for the lifetime of the calling component. They work once an effects
36
+ * provider is registered (see `useEffects`).
37
+ */
38
+ export declare function useAnimationEffectsTools(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: AnimationEditorController, options?: AnimationEffectsToolProviderOptions): void;
33
39
  //# sourceMappingURL=createAnimationEditor.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createAnimationEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/createAnimationEditor.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EAEzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,kCAAkC,EACxC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC;IAC/C,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,wCAAwC;IACxC,KAAK,IAAI,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,mBAAmB,GAAE,yBAAyB,GAAG,sBAA2B,GAAG,qBAAqB,CAwBzI;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,yBAAyB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,CAgBjI;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,yBAAyB,EACrC,OAAO,GAAE,kCAAuC,GAC/C,IAAI,CAMN"}
1
+ {"version":3,"file":"createAnimationEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/animation-editor/createAnimationEditor.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EAGzB,KAAK,mCAAmC,EACxC,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,kCAAkC,EACxC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC;IAC/C,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,wCAAwC;IACxC,KAAK,IAAI,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,mBAAmB,GAAE,yBAAyB,GAAG,sBAA2B,GAAG,qBAAqB,CAwBzI;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,yBAAyB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,CAgBjI;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,yBAAyB,EACrC,OAAO,GAAE,kCAAuC,GAC/C,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,yBAAyB,EACrC,OAAO,GAAE,mCAAwC,GAChD,IAAI,CAMN"}
@@ -1,5 +1,5 @@
1
1
  import { untrack } from "svelte";
2
- import { AnimationEditorController, createAnimationEditorToolProvider, } from "@pixerate/editor/animation-editor";
2
+ import { AnimationEditorController, createAnimationEditorToolProvider, createAnimationEffectsToolProvider, } from "@pixerate/editor/animation-editor";
3
3
  /**
4
4
  * Svelte 5 rune: subscribes to an `AnimationEditorController` (or creates one from options)
5
5
  * and exposes its state reactively with bound actions.
@@ -59,3 +59,16 @@ export function useAnimationEditorTools(registry, controller, options = {}) {
59
59
  return target.register(createAnimationEditorToolProvider(controller, options));
60
60
  });
61
61
  }
62
+ /**
63
+ * Registers the animation editor's provider-effect tools (`search_effects`, `apply_effect`,
64
+ * `add_vector_effect`, …) for the lifetime of the calling component. They work once an effects
65
+ * provider is registered (see `useEffects`).
66
+ */
67
+ export function useAnimationEffectsTools(registry, controller, options = {}) {
68
+ $effect(() => {
69
+ const target = typeof registry === "function" ? registry() : registry;
70
+ if (!target)
71
+ return;
72
+ return target.register(createAnimationEffectsToolProvider(controller, options));
73
+ });
74
+ }
@@ -17,6 +17,7 @@ export { default as CommandInspector } from "./CommandInspector.svelte";
17
17
  export { default as EasePicker } from "./EasePicker.svelte";
18
18
  export { default as ShotInspector } from "./ShotInspector.svelte";
19
19
  export { default as SceneSettings } from "./SceneSettings.svelte";
20
+ export { default as AnimationEffectsPanel } from "./AnimationEffectsPanel.svelte";
20
21
  export * from "./createAnimationEditor.svelte.js";
21
22
  export type AnimationEditorProps = ComponentProps<typeof AnimationEditorComponent>;
22
23
  export type AnimationStageProps = ComponentProps<typeof AnimationStageComponent>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,cAAc,mCAAmC,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,wBAAwB,CAAC,CAAC;AACnF,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACjF,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,cAAc,mCAAmC,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,wBAAwB,CAAC,CAAC;AACnF,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACjF,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -7,4 +7,5 @@ export { default as CommandInspector } from "./CommandInspector.svelte";
7
7
  export { default as EasePicker } from "./EasePicker.svelte";
8
8
  export { default as ShotInspector } from "./ShotInspector.svelte";
9
9
  export { default as SceneSettings } from "./SceneSettings.svelte";
10
+ export { default as AnimationEffectsPanel } from "./AnimationEffectsPanel.svelte";
10
11
  export * from "./createAnimationEditor.svelte.js";
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { untrack } from 'svelte';
2
3
  import { renderEffectThumbnail, type EffectProvider, type EffectSummary } from '@pixerate/editor/effects';
3
4
 
4
5
  interface Props {
@@ -15,10 +16,13 @@
15
16
  let failed = $state(false);
16
17
 
17
18
  $effect(() => {
18
- failed = item.kind === 'motion';
19
- if (failed) return;
19
+ // Reads only what picks the picture: setting `failed` below must not run this again.
20
+ const motion = item.kind === 'motion';
21
+ const request = { provider, item, size: { width, height } };
22
+ failed = motion;
23
+ if (motion) return;
20
24
  let live = true;
21
- renderEffectThumbnail(provider, item, { width, height }).then(
25
+ untrack(() => renderEffectThumbnail(request.provider, request.item, request.size)).then(
22
26
  (pixels) => {
23
27
  const ctx = live ? canvas?.getContext('2d') : null;
24
28
  if (!ctx || typeof ImageData === 'undefined') return;
@@ -1 +1 @@
1
- {"version":3,"file":"EffectThumbnail.svelte.d.ts","sourceRoot":"","sources":["../../src/effects/EffectThumbnail.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGxG,UAAU,KAAK;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwCH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"EffectThumbnail.svelte.d.ts","sourceRoot":"","sources":["../../src/effects/EffectThumbnail.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGxG,UAAU,KAAK;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { EFFECT_USE_LABELS, type EffectProvider, type EffectSummary, type EffectUse } from '@pixerate/editor/effects';
2
+ import { EFFECT_USE_LABELS, type EffectKind, type EffectProvider, type EffectSummary, type EffectUse } from '@pixerate/editor/effects';
3
3
  import EffectThumbnail from './EffectThumbnail.svelte';
4
4
 
5
5
  interface Props {
@@ -7,6 +7,8 @@
7
7
  provider: EffectProvider | null | undefined;
8
8
  /** Only effects with one of these uses (default: all but motion). */
9
9
  uses?: readonly EffectUse[];
10
+ /** Only effects of these kinds (default: any). */
11
+ kinds?: readonly EffectKind[];
10
12
  /** Called with the effect the user picks. */
11
13
  onpick: (effect: EffectSummary) => void;
12
14
  /** Draw previews with the provider's renderer (default true). */
@@ -16,7 +18,7 @@
16
18
  class?: string;
17
19
  }
18
20
 
19
- let { provider, uses, onpick, thumbnails = true, title = 'Effects', class: className = '' }: Props = $props();
21
+ let { provider, uses, kinds, onpick, thumbnails = true, title = 'Effects', class: className = '' }: Props = $props();
20
22
  let all = $state.raw<readonly EffectSummary[]>([]);
21
23
  let found = $state.raw<readonly EffectSummary[]>([]);
22
24
  let query = $state('');
@@ -66,7 +68,7 @@
66
68
  live = false;
67
69
  };
68
70
  });
69
- const allowed = (e: EffectSummary) => (uses ? e.kind !== 'motion' || uses.includes('motion') : e.kind !== 'motion') && (!uses || e.uses.some((u) => uses.includes(u)));
71
+ const allowed = (e: EffectSummary) => (!kinds || kinds.includes(e.kind)) && (uses ? e.kind !== 'motion' || uses.includes('motion') : e.kind !== 'motion') && (!uses || e.uses.some((u) => uses.includes(u)));
70
72
  const categories = $derived([...new Set(all.filter(allowed).map((e) => e.category))]);
71
73
  const shown = $derived(found.filter(allowed));
72
74
  </script>
@@ -1,9 +1,11 @@
1
- import { type EffectProvider, type EffectSummary, type EffectUse } from '@pixerate/editor/effects';
1
+ import { type EffectKind, type EffectProvider, type EffectSummary, type EffectUse } from '@pixerate/editor/effects';
2
2
  interface Props {
3
3
  /** The editor's provider; without one the browser says effects are unavailable. */
4
4
  provider: EffectProvider | null | undefined;
5
5
  /** Only effects with one of these uses (default: all but motion). */
6
6
  uses?: readonly EffectUse[];
7
+ /** Only effects of these kinds (default: any). */
8
+ kinds?: readonly EffectKind[];
7
9
  /** Called with the effect the user picks. */
8
10
  onpick: (effect: EffectSummary) => void;
9
11
  /** Draw previews with the provider's renderer (default true). */
@@ -1 +1 @@
1
- {"version":3,"file":"EffectsBrowser.svelte.d.ts","sourceRoot":"","sources":["../../src/effects/EffectsBrowser.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAIpH,UAAU,KAAK;IACb,mFAAmF;IACnF,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,qEAAqE;IACrE,IAAI,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC5B,6CAA6C;IAC7C,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoGH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"EffectsBrowser.svelte.d.ts","sourceRoot":"","sources":["../../src/effects/EffectsBrowser.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAIrI,UAAU,KAAK;IACb,mFAAmF;IACnF,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,qEAAqE;IACrE,IAAI,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC5B,kDAAkD;IAClD,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,6CAA6C;IAC7C,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoGH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -8,7 +8,8 @@
8
8
  import PaperPanel from './PaperPanel.svelte';
9
9
  import WetPanel from './WetPanel.svelte';
10
10
  import StickerPanel from './StickerPanel.svelte';
11
- import { chip } from './paintEditorRune.svelte.js';
11
+ import PaintEffectsPanel from './PaintEffectsPanel.svelte';
12
+ import { chip, paintEffectsProvider } from './paintEditorRune.svelte.js';
12
13
 
13
14
  interface Props {
14
15
  controller: PaintEditorController;
@@ -22,7 +23,9 @@
22
23
  }
23
24
  let { controller, fileName, height = 720, presence, class: className = '' }: Props = $props();
24
25
  let tool = $state<PaintTool>('brush');
25
- let tab = $state<'color' | 'wet' | 'paper' | 'layers'>('color');
26
+ let tab = $state<'color' | 'wet' | 'paper' | 'layers' | 'effects'>('color');
27
+ const effects = paintEffectsProvider(() => controller);
28
+ const tabs = $derived(effects.current ? (['color', 'wet', 'paper', 'layers', 'effects'] as const) : (['color', 'wet', 'paper', 'layers'] as const));
26
29
  let error = $state<string | null>(null);
27
30
  </script>
28
31
 
@@ -37,14 +40,15 @@
37
40
  </div>
38
41
  <div class="flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1">
39
42
  <div class="flex gap-1" role="tablist" aria-label="Paint panels">
40
- {#each ['color', 'wet', 'paper', 'layers'] as const as t (t)}
41
- <button type="button" role="tab" aria-selected={tab === t} class={chip(tab === t)} onclick={() => (tab = t)}>{t === 'color' ? 'Colour' : t === 'wet' ? 'Wet' : t === 'paper' ? 'Paper' : 'Layers'}</button>
43
+ {#each tabs as t (t)}
44
+ <button type="button" role="tab" aria-selected={tab === t} class={chip(tab === t)} onclick={() => (tab = t)}>{t === 'color' ? 'Colour' : t === 'wet' ? 'Wet' : t === 'paper' ? 'Paper' : t === 'layers' ? 'Layers' : 'Effects'}</button>
42
45
  {/each}
43
46
  </div>
44
47
  {#if tab === 'color'}<ColorPanel {controller} />{/if}
45
48
  {#if tab === 'wet'}<WetPanel {controller} />{/if}
46
49
  {#if tab === 'paper'}<PaperPanel {controller} />{/if}
47
50
  {#if tab === 'layers'}<PaintLayersPanel {controller} /><StickerPanel {controller} />{/if}
51
+ {#if tab === 'effects' && effects.current}<PaintEffectsPanel {controller} />{/if}
48
52
  </div>
49
53
  </div>
50
54
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"PaintEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAa,MAAM,+BAA+B,CAAC;AAYnG,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"PaintEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAa,MAAM,+BAA+B,CAAC;AAanG,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgDH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ import { PAPER_EFFECT_BLENDS, type PaintEditorController, type PaperEffectBlend } from '@pixerate/editor/paint-editor';
3
+ import type { EffectUse } from '@pixerate/editor/effects';
4
+ import EffectsBrowser from '../effects/EffectsBrowser.svelte';
5
+ import ImageEffectControls from '../image-editor/ImageEffectControls.svelte';
6
+ import { attempt, button, paintEditorState, paintEffectsProvider, panel } from './paintEditorRune.svelte.js';
7
+
8
+ interface Props {
9
+ controller: PaintEditorController;
10
+ class?: string;
11
+ }
12
+ let { controller, class: className = '' }: Props = $props();
13
+ const editor = paintEditorState(() => controller);
14
+ const effects = paintEffectsProvider(() => controller);
15
+ const provider = $derived(effects.current);
16
+ const view = $derived.by(() => {
17
+ const doc = editor.current.document;
18
+ const activeId = doc.activeLayerId;
19
+ return {
20
+ activeId,
21
+ paper: controller.getPaperEffect(),
22
+ layerEffect: activeId ? controller.getEffectLayer(activeId) : undefined,
23
+ pixel: activeId ? controller.getLayer(activeId)?.type === 'pixel' : false,
24
+ };
25
+ });
26
+ type Browse = null | 'paper' | 'layer' | 'fill' | 'light';
27
+ const BROWSERS: Record<Exclude<Browse, null>, { uses: EffectUse[]; title: string }> = {
28
+ paper: { uses: ['generator'], title: 'Effect paper' },
29
+ layer: { uses: ['generator', 'overlay', 'title'], title: 'Effect layer' },
30
+ fill: { uses: ['generator', 'overlay', 'title'], title: 'Fill the layer' },
31
+ light: { uses: ['filter'], title: 'Light on the paint' },
32
+ };
33
+ let browse = $state<Browse>(null);
34
+ let error = $state<string | null>(null);
35
+ let busy = $state(false);
36
+ const run = (work: () => unknown) =>
37
+ attempt(() => {
38
+ busy = true;
39
+ return Promise.resolve().then(work).finally(() => (busy = false));
40
+ }, (m) => (error = m));
41
+ const drags = new Set<string>();
42
+ /** The first change of a drag records the undo step; later ones join it. */
43
+ function commit(gesture: string | null) {
44
+ if (!gesture) return true;
45
+ if (drags.has(gesture)) return false;
46
+ drags.add(gesture);
47
+ return true;
48
+ }
49
+ function toggle(b: Exclude<Browse, null>) {
50
+ browse = browse === b ? null : b;
51
+ }
52
+ function pick(id: string) {
53
+ const kind = browse;
54
+ const layerId = view.activeId;
55
+ browse = null;
56
+ if (kind === 'paper') run(() => controller.setPaperEffect(id));
57
+ else if (kind === 'layer') run(() => controller.addEffectLayer(id));
58
+ else if (kind === 'fill') run(() => controller.fillLayerWithEffect(id));
59
+ else if (kind === 'light' && layerId) run(() => controller.applyLightEffect(layerId, id));
60
+ }
61
+ </script>
62
+
63
+ <!--
64
+ Provider effects in the paint editor: effect paper (a generator over the sheet, multiplied so the
65
+ grain shows), effect layers, effect fills and light baked onto the active layer's dried paint;
66
+ plus the controls of the effect paper and of an active effect layer. Each change is one undo
67
+ step (a slider drag is one). Without a provider it says why nothing can be added.
68
+ -->
69
+ <div class={`${panel} ${className}`} data-testid="paint-effects-panel" aria-busy={busy}>
70
+ <div class="flex flex-wrap items-center gap-1">
71
+ <span class="flex-1 font-medium text-slate-300">Effects</span>
72
+ <button type="button" class={button} disabled={!provider} aria-pressed={browse === 'paper'} onclick={() => toggle('paper')}>Paper…</button>
73
+ <button type="button" class={button} disabled={!provider} aria-pressed={browse === 'layer'} onclick={() => toggle('layer')}>Layer…</button>
74
+ <button type="button" class={button} disabled={!provider || !view.pixel} aria-pressed={browse === 'fill'} onclick={() => toggle('fill')}>Fill…</button>
75
+ <button type="button" class={button} disabled={!provider || !view.pixel} aria-pressed={browse === 'light'} onclick={() => toggle('light')} title="Bake a light, glow or grade into the active layer's dried paint">Light…</button>
76
+ </div>
77
+ {#if !provider}<p class="text-[11px] text-slate-400">No effects provider is registered. Effects in the painting are kept.</p>{/if}
78
+ {#if browse}
79
+ <EffectsBrowser {provider} uses={BROWSERS[browse].uses} title={BROWSERS[browse].title} onpick={(e) => pick(e.id)} />
80
+ {/if}
81
+ {#if view.paper}
82
+ {@const paper = view.paper}
83
+ <div class="flex flex-col gap-1 rounded border border-slate-700 p-1" data-effect-part="paper">
84
+ <div class="flex items-center gap-1">
85
+ <span class="flex-1 truncate">Paper: {paper.name ?? paper.effect}</span>
86
+ <button type="button" class={button} aria-label="Remove the effect paper" onclick={() => run(() => controller.setPaperEffect(null))}>✕</button>
87
+ </div>
88
+ <label class="flex items-center gap-1">
89
+ <span class="w-14 text-[11px] text-slate-400">Opacity</span>
90
+ <input type="range" min="0" max="1" step="0.01" class="flex-1" aria-label="Effect paper opacity" value={paper.opacity} onchange={(e) => { const opacity = Number(e.currentTarget.value); run(() => controller.updatePaperEffect({ opacity })); }} />
91
+ </label>
92
+ <label class="flex items-center gap-1">
93
+ <span class="w-14 text-[11px] text-slate-400">Blend</span>
94
+ <select class="flex-1 rounded bg-slate-800 px-1 py-0.5 text-[11px]" aria-label="Effect paper blend" value={paper.blend} onchange={(e) => { const blend = e.currentTarget.value as PaperEffectBlend; run(() => controller.updatePaperEffect({ blend })); }}>
95
+ {#each PAPER_EFFECT_BLENDS as b (b)}<option value={b}>{b}</option>{/each}
96
+ </select>
97
+ </label>
98
+ <ImageEffectControls
99
+ {provider}
100
+ effect={paper.effect}
101
+ name={paper.name}
102
+ values={paper.values}
103
+ onchange={(k, v, gesture) => run(() => controller.updatePaperEffect({ values: { [k]: v as never } }, commit(gesture)))}
104
+ onpreset={(values) => run(() => controller.updatePaperEffect({ values: { ...values } as never }))}
105
+ />
106
+ </div>
107
+ {/if}
108
+ {#if view.layerEffect && view.activeId}
109
+ {@const fx = view.layerEffect}
110
+ {@const layerId = view.activeId}
111
+ <div class="flex flex-col gap-1 rounded border border-slate-700 p-1" data-effect-part="layer">
112
+ <div class="flex items-center gap-1">
113
+ <span class="flex-1 truncate">Layer: {fx.name ?? fx.effect}</span>
114
+ <button type="button" class={button} title="Keep the pixels as a plain layer" onclick={() => run(() => controller.rasterizeEffectLayer(layerId))}>Rasterize</button>
115
+ </div>
116
+ <ImageEffectControls
117
+ {provider}
118
+ effect={fx.effect}
119
+ name={fx.name}
120
+ values={fx.values}
121
+ onchange={(k, v, gesture) => run(() => controller.updateEffectLayer(layerId, { values: { [k]: v as never } }, commit(gesture)))}
122
+ onpreset={(values) => run(() => controller.updateEffectLayer(layerId, { values: { ...values } as never }))}
123
+ />
124
+ </div>
125
+ {/if}
126
+ {#if error}<p role="alert" class="text-[11px] text-rose-400">{error}</p>{/if}
127
+ </div>
@@ -0,0 +1,9 @@
1
+ import { type PaintEditorController } from '@pixerate/editor/paint-editor';
2
+ interface Props {
3
+ controller: PaintEditorController;
4
+ class?: string;
5
+ }
6
+ declare const PaintEffectsPanel: import("svelte").Component<Props, {}, "">;
7
+ type PaintEffectsPanel = ReturnType<typeof PaintEffectsPanel>;
8
+ export default PaintEffectsPanel;
9
+ //# sourceMappingURL=PaintEffectsPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaintEffectsPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEffectsPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,qBAAqB,EAAyB,MAAM,+BAA+B,CAAC;AAOrH,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA6GH,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -8,6 +8,7 @@ import type ColorPanelComponent from './ColorPanel.svelte';
8
8
  import type PaintLayersPanelComponent from './PaintLayersPanel.svelte';
9
9
  import type WetPanelComponent from './WetPanel.svelte';
10
10
  import type StickerPanelComponent from './StickerPanel.svelte';
11
+ import type PaintEffectsPanelComponent from './PaintEffectsPanel.svelte';
11
12
  import type PaintGradientEditorComponent from './PaintGradientEditor.svelte';
12
13
  export { default as PaintEditor } from './PaintEditor.svelte';
13
14
  export { default as PaintCanvas } from './PaintCanvas.svelte';
@@ -18,10 +19,11 @@ export { default as ColorPanel } from './ColorPanel.svelte';
18
19
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
19
20
  export { default as WetPanel } from './WetPanel.svelte';
20
21
  export { default as StickerPanel } from './StickerPanel.svelte';
22
+ export { default as PaintEffectsPanel } from './PaintEffectsPanel.svelte';
21
23
  export { default as PaintGradientEditor } from './PaintGradientEditor.svelte';
22
24
  export { default as PaintSlider } from './PaintSlider.svelte';
23
25
  export { default as PaintPresenceLayer } from './PaintPresenceLayer.svelte';
24
- export { createPaintDirector, createReactivePaintEditor, paintEditorState } from './paintEditorRune.svelte.js';
26
+ export { createPaintDirector, createReactivePaintEditor, paintEditorState, paintEffectsProvider, usePaintEffectsTools } from './paintEditorRune.svelte.js';
25
27
  export type PaintEditorProps = ComponentProps<typeof PaintEditorComponent>;
26
28
  export type PaintCanvasProps = ComponentProps<typeof PaintCanvasComponent>;
27
29
  export type PaintToolbarProps = ComponentProps<typeof PaintToolbarComponent>;
@@ -31,5 +33,6 @@ export type ColorPanelProps = ComponentProps<typeof ColorPanelComponent>;
31
33
  export type PaintLayersPanelProps = ComponentProps<typeof PaintLayersPanelComponent>;
32
34
  export type WetPanelProps = ComponentProps<typeof WetPanelComponent>;
33
35
  export type StickerPanelProps = ComponentProps<typeof StickerPanelComponent>;
36
+ export type PaintEffectsPanelProps = ComponentProps<typeof PaintEffectsPanelComponent>;
34
37
  export type PaintGradientEditorProps = ComponentProps<typeof PaintGradientEditorComponent>;
35
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paint-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/G,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paint-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAE3J,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEvF,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
@@ -7,7 +7,8 @@ export { default as ColorPanel } from './ColorPanel.svelte';
7
7
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
8
8
  export { default as WetPanel } from './WetPanel.svelte';
9
9
  export { default as StickerPanel } from './StickerPanel.svelte';
10
+ export { default as PaintEffectsPanel } from './PaintEffectsPanel.svelte';
10
11
  export { default as PaintGradientEditor } from './PaintGradientEditor.svelte';
11
12
  export { default as PaintSlider } from './PaintSlider.svelte';
12
13
  export { default as PaintPresenceLayer } from './PaintPresenceLayer.svelte';
13
- export { createPaintDirector, createReactivePaintEditor, paintEditorState } from './paintEditorRune.svelte.js';
14
+ export { createPaintDirector, createReactivePaintEditor, paintEditorState, paintEffectsProvider, usePaintEffectsTools } from './paintEditorRune.svelte.js';
@@ -1,4 +1,6 @@
1
- import { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';
1
+ import { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState, type PaintEffectsToolProviderOptions } from '@pixerate/editor/paint-editor';
2
+ import type { EffectProvider } from '@pixerate/editor/effects';
3
+ import type { ToolRegistry } from '@pixerate/editor/tools';
2
4
  /**
3
5
  * A `PaintEditorController` (created from `options`, or the one given) with its state as a
4
6
  * rune: `editor.state` updates after every change. Call `destroy()` to unsubscribe.
@@ -26,4 +28,14 @@ export declare const button = "px-2 py-1 rounded text-[11px] bg-slate-800 text-s
26
28
  export declare const panel = "flex flex-col gap-2 text-xs text-slate-200";
27
29
  /** Runs `fn` and returns the error message it threw (or a rejected promise's, through `onAsync`). */
28
30
  export declare function attempt(fn: () => unknown, onError: (msg: string | null) => void): void;
31
+ /** The controller's effects provider as a rune, following `setEffectsProvider`. */
32
+ export declare function paintEffectsProvider(controller: () => PaintEditorController): {
33
+ readonly current: EffectProvider | null;
34
+ };
35
+ /**
36
+ * Registers the paint editor's provider-effect tools (`set_paper_effect`, `add_effect_layer`,
37
+ * `fill_layer_with_effect`, `apply_effect`, …) for the lifetime of the calling component. Before
38
+ * an effects provider is registered the read tools say so and the write tools refuse.
39
+ */
40
+ export declare function usePaintEffectsTools(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: PaintEditorController, options?: PaintEffectsToolProviderOptions): void;
29
41
  //# sourceMappingURL=paintEditorRune.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paintEditorRune.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/paintEditorRune.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAE/K;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,kBAAkB,GAAG,qBAA0B;;;;EAiBjG;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAoBhH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAM,GAAG;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAG9K;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,OAAO,WAAwH,CAAC;AACzJ,eAAO,MAAM,MAAM,qGAAqG,CAAC;AACzH,eAAO,MAAM,KAAK,+CAA+C,CAAC;AAElE,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAQtF"}
1
+ {"version":3,"file":"paintEditorRune.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/paintEditorRune.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,KAAK,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AACrP,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,kBAAkB,GAAG,qBAA0B;;;;EAiBjG;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAoBhH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAM,GAAG;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAG9K;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,OAAO,WAAwH,CAAC;AACzJ,eAAO,MAAM,MAAM,qGAAqG,CAAC;AACzH,eAAO,MAAM,KAAK,+CAA+C,CAAC;AAElE,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAQtF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,CAgBzH;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,qBAAqB,EACjC,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CAMN"}
@@ -1,5 +1,5 @@
1
1
  import { untrack } from 'svelte';
2
- import { PaintDirector, PaintEditorController, PaintPresence } from '@pixerate/editor/paint-editor';
2
+ import { createPaintEffectsToolProvider, PaintDirector, PaintEditorController, PaintPresence } from '@pixerate/editor/paint-editor';
3
3
  /**
4
4
  * A `PaintEditorController` (created from `options`, or the one given) with its state as a
5
5
  * rune: `editor.state` updates after every change. Call `destroy()` to unsubscribe.
@@ -68,3 +68,34 @@ export function attempt(fn, onError) {
68
68
  onError(e instanceof Error ? e.message : String(e));
69
69
  }
70
70
  }
71
+ /** The controller's effects provider as a rune, following `setEffectsProvider`. */
72
+ export function paintEffectsProvider(controller) {
73
+ let provider = $state.raw(controller().effectsProvider);
74
+ $effect(() => {
75
+ const c = controller();
76
+ return untrack(() => {
77
+ provider = c.effectsProvider;
78
+ return c.effects.subscribe((p) => {
79
+ provider = p;
80
+ });
81
+ });
82
+ });
83
+ return {
84
+ get current() {
85
+ return provider;
86
+ },
87
+ };
88
+ }
89
+ /**
90
+ * Registers the paint editor's provider-effect tools (`set_paper_effect`, `add_effect_layer`,
91
+ * `fill_layer_with_effect`, `apply_effect`, …) for the lifetime of the calling component. Before
92
+ * an effects provider is registered the read tools say so and the write tools refuse.
93
+ */
94
+ export function usePaintEffectsTools(registry, controller, options = {}) {
95
+ $effect(() => {
96
+ const target = typeof registry === 'function' ? registry() : registry;
97
+ if (!target)
98
+ return;
99
+ return target.register(createPaintEffectsToolProvider(controller, options));
100
+ });
101
+ }
@@ -4,6 +4,9 @@
4
4
  import VectorCanvas from './VectorCanvas.svelte';
5
5
  import VectorStylePanel from './VectorStylePanel.svelte';
6
6
  import VectorToolbar from './VectorToolbar.svelte';
7
+ import type { EffectProvider } from '@pixerate/editor/effects';
8
+ import { useEffects } from '../effects/effects.svelte.js';
9
+ import VectorProviderEffectsPanel from './VectorProviderEffectsPanel.svelte';
7
10
 
8
11
  interface Props {
9
12
  controller: VectorEditorController;
@@ -14,10 +17,18 @@
14
17
  /** Canvas height (default 520px). */
15
18
  height?: number | string;
16
19
  canvasProps?: Omit<ComponentProps<typeof VectorCanvas>, 'controller'>;
20
+ /**
21
+ * An effects provider (see `@pixerate/editor/effects`), registered with the controller while
22
+ * mounted: provider vector effects as groups, with an Effects section under the style panel.
23
+ * Optional: without one the editor is as before.
24
+ */
25
+ effects?: EffectProvider | null;
17
26
  class?: string;
18
27
  }
19
28
 
20
- let { controller, tools, showStylePanel = true, height = 520, canvasProps = {}, class: className = '' }: Props = $props();
29
+ let { controller, tools, showStylePanel = true, height = 520, canvasProps = {}, effects, class: className = '' }: Props = $props();
30
+ useEffects(() => controller, () => effects);
31
+ const effectsShown = $derived(!!effects || controller.vectorEffectGroups().length > 0);
21
32
  </script>
22
33
 
23
34
  <div class="flex flex-col gap-2 {className}" data-vector-editor="">
@@ -30,7 +41,10 @@
30
41
  <VectorCanvas {controller} {...canvasProps} />
31
42
  </div>
32
43
  {#if showStylePanel}
33
- <VectorStylePanel {controller} class="w-full shrink-0 rounded-md border border-border p-3 md:w-56" />
44
+ <div class="flex w-full shrink-0 flex-col gap-2 md:w-56">
45
+ <VectorStylePanel {controller} class="rounded-md border border-border p-3" />
46
+ {#if effectsShown}<VectorProviderEffectsPanel {controller} class="rounded-md border border-border p-3" />{/if}
47
+ </div>
34
48
  {/if}
35
49
  </div>
36
50
  </div>
@@ -1,6 +1,7 @@
1
1
  import type { ComponentProps } from 'svelte';
2
2
  import type { VectorEditorController, VectorTool } from '@pixerate/editor/vector';
3
3
  import VectorCanvas from './VectorCanvas.svelte';
4
+ import type { EffectProvider } from '@pixerate/editor/effects';
4
5
  interface Props {
5
6
  controller: VectorEditorController;
6
7
  /** Tools in the toolbar (default: all). */
@@ -10,6 +11,12 @@ interface Props {
10
11
  /** Canvas height (default 520px). */
11
12
  height?: number | string;
12
13
  canvasProps?: Omit<ComponentProps<typeof VectorCanvas>, 'controller'>;
14
+ /**
15
+ * An effects provider (see `@pixerate/editor/effects`), registered with the controller while
16
+ * mounted: provider vector effects as groups, with an Effects section under the style panel.
17
+ * Optional: without one the editor is as before.
18
+ */
19
+ effects?: EffectProvider | null;
13
20
  class?: string;
14
21
  }
15
22
  declare const VectorEditor: import("svelte").Component<Props, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"VectorEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,YAAY,MAAM,uBAAuB,CAAC;AAK/C,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,2CAA2C;IAC3C,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"VectorEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,YAAY,MAAM,uBAAuB,CAAC;AAGjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK7D,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,2CAA2C;IAC3C,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;IACtE;;;;OAIG;IACH,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkCH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { VectorEditorController, VectorGroupNode } from '@pixerate/editor/vector';
3
+ import EffectParameters from '../effects/EffectParameters.svelte';
4
+ import { effectDescriptionOf } from '../effects/effects.svelte.js';
5
+
6
+ interface Props {
7
+ controller: VectorEditorController;
8
+ group: VectorGroupNode;
9
+ }
10
+
11
+ let { controller, group }: Props = $props();
12
+ const loaded = effectDescriptionOf(() => controller.effectsProvider, () => group.providerEffect?.effect);
13
+ let message = $state<string | null>(null);
14
+ const run = (work: Promise<unknown>) =>
15
+ void work.then(
16
+ () => (message = null),
17
+ (e: unknown) => (message = e instanceof Error ? e.message : String(e)),
18
+ );
19
+ </script>
20
+
21
+ <!-- One effect group's controls, loaded from the provider. -->
22
+ {#if !controller.effectsProvider}
23
+ <p class="text-[11px] text-muted-foreground">No effects provider: the shapes are kept as they are.</p>
24
+ {:else if loaded.error}
25
+ <p class="text-[11px] text-amber-500">{loaded.error}</p>
26
+ {:else if !loaded.description}
27
+ <p class="text-[11px] text-muted-foreground">Loading…</p>
28
+ {:else}
29
+ <EffectParameters
30
+ description={loaded.description}
31
+ values={group.providerEffect?.values ?? {}}
32
+ onchange={(k, v) => run(controller.updateVectorEffect(group.id, { [k]: v as never }))}
33
+ onreset={(k) => run(controller.updateVectorEffect(group.id, { [k]: null }))}
34
+ onpreset={(v) => run(controller.updateVectorEffect(group.id, v as never))}
35
+ />
36
+ {#if message}<p role="alert" class="text-[11px] text-destructive">{message}</p>{/if}
37
+ {/if}
@@ -0,0 +1,9 @@
1
+ import type { VectorEditorController, VectorGroupNode } from '@pixerate/editor/vector';
2
+ interface Props {
3
+ controller: VectorEditorController;
4
+ group: VectorGroupNode;
5
+ }
6
+ declare const VectorProviderEffectControls: import("svelte").Component<Props, {}, "">;
7
+ type VectorProviderEffectControls = ReturnType<typeof VectorProviderEffectControls>;
8
+ export default VectorProviderEffectControls;
9
+ //# sourceMappingURL=VectorProviderEffectControls.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VectorProviderEffectControls.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorProviderEffectControls.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAKrF,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,KAAK,EAAE,eAAe,CAAC;CACxB;AA+BH,QAAA,MAAM,4BAA4B,2CAAwC,CAAC;AAC3E,KAAK,4BAA4B,GAAG,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC;AACpF,eAAe,4BAA4B,CAAC"}
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import { untrack } from 'svelte';
3
+ import type { EffectProvider } from '@pixerate/editor/effects';
4
+ import type { VectorEditorController } from '@pixerate/editor/vector';
5
+ import EffectsBrowser from '../effects/EffectsBrowser.svelte';
6
+ import VectorProviderEffectControls from './VectorProviderEffectControls.svelte';
7
+ import { vectorStateOf } from './subscribe.svelte.js';
8
+
9
+ interface Props {
10
+ controller: VectorEditorController;
11
+ class?: string;
12
+ }
13
+
14
+ let { controller, class: className = '' }: Props = $props();
15
+ const view = vectorStateOf(() => controller);
16
+ let provider = $state.raw<EffectProvider | null>(untrack(() => controller.effects.provider));
17
+ $effect(() => {
18
+ const c = controller;
19
+ provider = c.effects.provider;
20
+ return untrack(() => c.effects.subscribe((p) => (provider = p)));
21
+ });
22
+ let browse = $state(false);
23
+ let message = $state<string | null>(null);
24
+ const groups = $derived.by(() => {
25
+ void view.current.document;
26
+ return controller.vectorEffectGroups();
27
+ });
28
+ const selected = $derived(groups.filter((g) => view.current.selection.includes(g.id)));
29
+ const btn = 'rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40';
30
+ function run(work: () => unknown) {
31
+ message = null;
32
+ Promise.resolve()
33
+ .then(work)
34
+ .catch((e: unknown) => (message = e instanceof Error ? e.message : String(e)));
35
+ }
36
+ </script>
37
+
38
+ <!--
39
+ Provider vector effects in a drawing: add one (its picture at rest becomes a selected group of
40
+ editable shapes), draw it again with new values, or detach it to keep the shapes. Motion is
41
+ applied in the animation editor.
42
+ -->
43
+ <section class="flex flex-col gap-2 text-xs {className}" aria-label="Vector effects" data-vector-provider-effects="">
44
+ <div class="flex items-center gap-1">
45
+ <span class="flex-1 font-semibold">Effects</span>
46
+ <button type="button" class={btn} disabled={!provider} aria-pressed={browse} onclick={() => (browse = !browse)}>Add effect…</button>
47
+ </div>
48
+ {#if !provider}<p class="text-[11px] text-muted-foreground">No effects provider is registered. Effect groups are kept as shapes.</p>{/if}
49
+ {#if browse}
50
+ <EffectsBrowser {provider} kinds={['vector']} title="Vector effects" onpick={(e) => ((browse = false), run(() => controller.addVectorEffect(e.id)))} />
51
+ {/if}
52
+ {#each selected as g (g.id)}
53
+ <div class="space-y-1 rounded border border-border p-1" data-vector-effect-group={g.id}>
54
+ <div class="flex items-center gap-1">
55
+ <span class="min-w-0 flex-1 truncate font-medium">{g.providerEffect?.name ?? g.providerEffect?.effect}</span>
56
+ <button type="button" class={btn} title="Keep the shapes as a plain group" onclick={() => run(() => controller.detachVectorEffect(g.id))}>Detach</button>
57
+ </div>
58
+ <VectorProviderEffectControls {controller} group={g} />
59
+ </div>
60
+ {/each}
61
+ {#if groups.length > 0 && !selected.length}<p class="text-[11px] text-muted-foreground">Select an effect group ({groups.length} in the drawing) to change it.</p>{/if}
62
+ {#if message}<p role="alert" class="text-[11px] text-destructive">{message}</p>{/if}
63
+ </section>
@@ -0,0 +1,9 @@
1
+ import type { VectorEditorController } from '@pixerate/editor/vector';
2
+ interface Props {
3
+ controller: VectorEditorController;
4
+ class?: string;
5
+ }
6
+ declare const VectorProviderEffectsPanel: import("svelte").Component<Props, {}, "">;
7
+ type VectorProviderEffectsPanel = ReturnType<typeof VectorProviderEffectsPanel>;
8
+ export default VectorProviderEffectsPanel;
9
+ //# sourceMappingURL=VectorProviderEffectsPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VectorProviderEffectsPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorProviderEffectsPanel.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAMpE,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2DH,QAAA,MAAM,0BAA0B,2CAAwC,CAAC;AACzE,KAAK,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAChF,eAAe,0BAA0B,CAAC"}
@@ -1,4 +1,5 @@
1
- import { VectorEditorController, type VectorCommandOptions, type VectorEditorOptions, type VectorEditorState, type VectorTool } from "@pixerate/editor/vector";
1
+ import { VectorEditorController, type VectorEffectsToolProviderOptions, type VectorCommandOptions, type VectorEditorOptions, type VectorEditorState, type VectorTool } from "@pixerate/editor/vector";
2
+ import type { ToolRegistry } from "@pixerate/editor/tools";
2
3
  export interface SvelteVectorEditor {
3
4
  readonly controller: VectorEditorController;
4
5
  /** The controller's state (reactive). */
@@ -27,4 +28,10 @@ export interface VectorCommandTarget {
27
28
  * registry.
28
29
  */
29
30
  export declare function useVectorCommands(registry: VectorCommandTarget | null | undefined | (() => VectorCommandTarget | null | undefined), controller: VectorEditorController, options?: VectorCommandOptions): void;
31
+ /**
32
+ * Registers the vector editor's provider-effect tools (`search_effects`, `apply_effect`, …) for the
33
+ * lifetime of the calling component. They work once an effects provider is registered (see
34
+ * `useEffects`).
35
+ */
36
+ export declare function useVectorEffectsTools(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: VectorEditorController, options?: VectorEffectsToolProviderOptions): void;
30
37
  //# sourceMappingURL=createVectorEditor.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createVectorEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/createVectorEditor.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAEtB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,eAAe,IAAI,IAAI,CAAC;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,mBAAmB,GAAE,sBAAsB,GAAG,mBAAwB,GAAG,kBAAkB,CAuB7H;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC,EACjG,UAAU,EAAE,sBAAsB,EAClC,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAMN"}
1
+ {"version":3,"file":"createVectorEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/createVectorEditor.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAGtB,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,eAAe,IAAI,IAAI,CAAC;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,mBAAmB,GAAE,sBAAsB,GAAG,mBAAwB,GAAG,kBAAkB,CAuB7H;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC,EACjG,UAAU,EAAE,sBAAsB,EAClC,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,sBAAsB,EAClC,OAAO,GAAE,gCAAqC,GAC7C,IAAI,CAMN"}
@@ -1,4 +1,4 @@
1
- import { VectorEditorController, createVectorCommands, } from "@pixerate/editor/vector";
1
+ import { VectorEditorController, createVectorCommands, createVectorEffectsToolProvider, } from "@pixerate/editor/vector";
2
2
  /**
3
3
  * Svelte 5 rune: subscribes to a `VectorEditorController` (or creates one from options) and
4
4
  * exposes its state reactively with bound actions.
@@ -41,3 +41,16 @@ export function useVectorCommands(registry, controller, options = {}) {
41
41
  return target.register(createVectorCommands(controller, options));
42
42
  });
43
43
  }
44
+ /**
45
+ * Registers the vector editor's provider-effect tools (`search_effects`, `apply_effect`, …) for the
46
+ * lifetime of the calling component. They work once an effects provider is registered (see
47
+ * `useEffects`).
48
+ */
49
+ export function useVectorEffectsTools(registry, controller, options = {}) {
50
+ $effect(() => {
51
+ const target = typeof registry === "function" ? registry() : registry;
52
+ if (!target)
53
+ return;
54
+ return target.register(createVectorEffectsToolProvider(controller, options));
55
+ });
56
+ }
@@ -26,6 +26,7 @@ export { default as VectorPaintPath } from "./VectorPaintPath.svelte";
26
26
  export { default as VectorAppearancePanel } from "./VectorAppearancePanel.svelte";
27
27
  export { default as VectorGradientAnnotator } from "./VectorGradientAnnotator.svelte";
28
28
  export { default as VectorGradientEditor } from "./VectorGradientEditor.svelte";
29
+ export { default as VectorProviderEffectsPanel } from "./VectorProviderEffectsPanel.svelte";
29
30
  export * from "./createVectorEditor.svelte.js";
30
31
  export { vectorStateOf } from "./subscribe.svelte.js";
31
32
  export * from "./styles.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAChF,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,cAAc,aAAa,CAAC;AAE5B,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAC5F,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,cAAc,aAAa,CAAC;AAE5B,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -23,6 +23,7 @@ export { default as VectorPaintPath } from "./VectorPaintPath.svelte";
23
23
  export { default as VectorAppearancePanel } from "./VectorAppearancePanel.svelte";
24
24
  export { default as VectorGradientAnnotator } from "./VectorGradientAnnotator.svelte";
25
25
  export { default as VectorGradientEditor } from "./VectorGradientEditor.svelte";
26
+ export { default as VectorProviderEffectsPanel } from "./VectorProviderEffectsPanel.svelte";
26
27
  export * from "./createVectorEditor.svelte.js";
27
28
  export { vectorStateOf } from "./subscribe.svelte.js";
28
29
  export * from "./styles.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.88.1",
3
+ "version": "0.90.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -144,7 +144,7 @@
144
144
  "@tiptap/extension-bubble-menu": "^2.11.5",
145
145
  "@tiptap/extension-placeholder": "^2.11.5",
146
146
  "@tiptap/starter-kit": "^2.11.5",
147
- "@pixerate/editor": "0.124.1"
147
+ "@pixerate/editor": "0.126.0"
148
148
  },
149
149
  "peerDependencies": {
150
150
  "@dagrejs/dagre": "^1.1.4",