@pixerate/editor 0.177.0 → 0.178.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.
@@ -597,6 +597,11 @@ var EFFECT_USE_LABELS = {
597
597
  };
598
598
  var HEX2 = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
599
599
  var typeOf = (s) => Array.isArray(s.type) ? s.type.find((t) => t !== "null") : s.type;
600
+ function hexColour(value) {
601
+ if (typeof value === "string") return HEX2.test(value) ? value : void 0;
602
+ if (!Array.isArray(value) || value.length !== 3 && value.length !== 4 || !value.every((n) => typeof n === "number" && Number.isFinite(n))) return void 0;
603
+ return `#${value.map((n) => Math.round(Math.min(1, Math.max(0, n)) * 255).toString(16).padStart(2, "0")).join("")}`;
604
+ }
600
605
  function isEffectFontControl(schema) {
601
606
  return typeOf(schema) === "string" && (schema.format === "font" || schema["x-pixerate-control"] === "font");
602
607
  }
@@ -649,7 +654,10 @@ function effectFontFamilies(description, values = {}) {
649
654
  }
650
655
  return out;
651
656
  }
652
- var effectFieldValue = (field, value) => value === void 0 || value === null || typeof value === "object" && !Array.isArray(value) ? field.default : value;
657
+ var effectFieldValue = (field, value) => {
658
+ if (field.type === "color") return _nullishCoalesce(hexColour(value), () => ( field.default));
659
+ return value === void 0 || value === null || typeof value === "object" && !Array.isArray(value) ? field.default : value;
660
+ };
653
661
  function effectSamplePicture(width, height, variant = 0) {
654
662
  const p = _chunkA3A5TI6Rcjs.createEffectPixels.call(void 0, width, height);
655
663
  for (let y = 0, i = 0; y < height; y++) {
@@ -597,6 +597,11 @@ var EFFECT_USE_LABELS = {
597
597
  };
598
598
  var HEX2 = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
599
599
  var typeOf = (s) => Array.isArray(s.type) ? s.type.find((t) => t !== "null") : s.type;
600
+ function hexColour(value) {
601
+ if (typeof value === "string") return HEX2.test(value) ? value : void 0;
602
+ if (!Array.isArray(value) || value.length !== 3 && value.length !== 4 || !value.every((n) => typeof n === "number" && Number.isFinite(n))) return void 0;
603
+ return `#${value.map((n) => Math.round(Math.min(1, Math.max(0, n)) * 255).toString(16).padStart(2, "0")).join("")}`;
604
+ }
600
605
  function isEffectFontControl(schema) {
601
606
  return typeOf(schema) === "string" && (schema.format === "font" || schema["x-pixerate-control"] === "font");
602
607
  }
@@ -649,7 +654,10 @@ function effectFontFamilies(description, values = {}) {
649
654
  }
650
655
  return out;
651
656
  }
652
- var effectFieldValue = (field, value) => value === void 0 || value === null || typeof value === "object" && !Array.isArray(value) ? field.default : value;
657
+ var effectFieldValue = (field, value) => {
658
+ if (field.type === "color") return hexColour(value) ?? field.default;
659
+ return value === void 0 || value === null || typeof value === "object" && !Array.isArray(value) ? field.default : value;
660
+ };
653
661
  function effectSamplePicture(width, height, variant = 0) {
654
662
  const p = createEffectPixels(width, height);
655
663
  for (let y = 0, i = 0; y < height; y++) {
@@ -27,7 +27,10 @@ export declare function effectParameterFields(description: Pick<EffectDescriptio
27
27
  * to load with `ensureFontsLoaded` before rendering a title preview.
28
28
  */
29
29
  export declare function effectFontFamilies(description: Pick<EffectDescription, 'controls' | 'defaults'>, values?: Readonly<Record<string, unknown>>): string[];
30
- /** A saved value as a field shows it (`ParameterValue`), or the field's default. */
30
+ /**
31
+ * A saved value as a field shows it (`ParameterValue`), or the field's default. Colour fields show
32
+ * channel arrays as hex, and the default for values they can't show (`"currentColor"`, `rgb(…)`).
33
+ */
31
34
  export declare const effectFieldValue: (field: ParameterField, value: unknown) => ParameterValue;
32
35
  /**
33
36
  * A colourful, deterministic picture for previews of filters and transitions (`variant` 0 and 1
@@ -27,7 +27,10 @@ export declare function effectParameterFields(description: Pick<EffectDescriptio
27
27
  * to load with `ensureFontsLoaded` before rendering a title preview.
28
28
  */
29
29
  export declare function effectFontFamilies(description: Pick<EffectDescription, 'controls' | 'defaults'>, values?: Readonly<Record<string, unknown>>): string[];
30
- /** A saved value as a field shows it (`ParameterValue`), or the field's default. */
30
+ /**
31
+ * A saved value as a field shows it (`ParameterValue`), or the field's default. Colour fields show
32
+ * channel arrays as hex, and the default for values they can't show (`"currentColor"`, `rgb(…)`).
33
+ */
31
34
  export declare const effectFieldValue: (field: ParameterField, value: unknown) => ParameterValue;
32
35
  /**
33
36
  * A colourful, deterministic picture for previews of filters and transitions (`variant` 0 and 1
@@ -14711,31 +14711,21 @@ function layerPanels(layer, options = {}) {
14711
14711
  ];
14712
14712
  }
14713
14713
  const panels = [{ id: "properties", title: "Layer Properties" }];
14714
- const styles = (id, title) => {
14715
- if (!options.effects) panels.push({ id, title });
14716
- };
14717
14714
  const effects = () => {
14718
14715
  if (options.effects) panels.push({ id: "provider-effects", title: "Effects" });
14719
14716
  };
14720
14717
  if (layer.type === "pixel") {
14721
14718
  effects();
14722
14719
  panels.push({ id: "paint", title: "Brush Options" });
14723
- styles("effects", "Layer Effects");
14724
14720
  } else if (layer.type === "adjustment") {
14725
14721
  panels.push({ id: "adjustment", title: _chunkUHMSMUHKcjs.adjustmentKindLabel.call(void 0, layer.kind) });
14726
14722
  } else if (layer.type === "type") {
14727
14723
  panels.push({ id: "type", title: "Typography" });
14728
14724
  effects();
14729
- styles("effects", "Layer Effects");
14730
14725
  } else if (layer.type === "shape") {
14731
14726
  panels.push({ id: "shape", title: "Shape Options" });
14732
14727
  effects();
14733
- styles("effects", "Layer Effects");
14734
- } else if (layer.type === "smart") {
14735
- effects();
14736
- styles("smart-filters", "Smart Filters");
14737
- styles("effects", "Layer Effects");
14738
- } else if (layer.type === "group") {
14728
+ } else if (layer.type === "smart" || layer.type === "group") {
14739
14729
  effects();
14740
14730
  }
14741
14731
  if (layer.mask) {
@@ -14747,14 +14737,14 @@ function layerPanels(layer, options = {}) {
14747
14737
  // src/image-editor/layers/effects-ui.ts
14748
14738
  function layerEffectsPanel(layer) {
14749
14739
  const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
14750
- if (!layer) return { ...empty, available: false, reason: "Select a layer to add effects." };
14751
- if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have effects." };
14740
+ if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
14741
+ if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
14752
14742
  const fx = layer.effects;
14753
14743
  const readOnly = Boolean(_optionalChain([layer, 'access', _460 => _460.locks, 'optionalAccess', _461 => _461.all]));
14754
14744
  return {
14755
14745
  available: true,
14756
14746
  readOnly,
14757
- reason: readOnly ? "The layer is locked; unlock it to change its effects." : void 0,
14747
+ reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
14758
14748
  enabled: _nullishCoalesce(_optionalChain([fx, 'optionalAccess', _462 => _462.enabled]), () => ( true)),
14759
14749
  scale: _nullishCoalesce(_optionalChain([fx, 'optionalAccess', _463 => _463.scale]), () => ( 1)),
14760
14750
  rows: (_nullishCoalesce(_optionalChain([fx, 'optionalAccess', _464 => _464.items]), () => ( []))).map((e) => ({ id: e.id, kind: e.kind, label: _chunkHGTDMKNEcjs.layerEffectLabel.call(void 0, e.kind), enabled: e.enabled }))
@@ -14711,31 +14711,21 @@ function layerPanels(layer, options = {}) {
14711
14711
  ];
14712
14712
  }
14713
14713
  const panels = [{ id: "properties", title: "Layer Properties" }];
14714
- const styles = (id, title) => {
14715
- if (!options.effects) panels.push({ id, title });
14716
- };
14717
14714
  const effects = () => {
14718
14715
  if (options.effects) panels.push({ id: "provider-effects", title: "Effects" });
14719
14716
  };
14720
14717
  if (layer.type === "pixel") {
14721
14718
  effects();
14722
14719
  panels.push({ id: "paint", title: "Brush Options" });
14723
- styles("effects", "Layer Effects");
14724
14720
  } else if (layer.type === "adjustment") {
14725
14721
  panels.push({ id: "adjustment", title: adjustmentKindLabel(layer.kind) });
14726
14722
  } else if (layer.type === "type") {
14727
14723
  panels.push({ id: "type", title: "Typography" });
14728
14724
  effects();
14729
- styles("effects", "Layer Effects");
14730
14725
  } else if (layer.type === "shape") {
14731
14726
  panels.push({ id: "shape", title: "Shape Options" });
14732
14727
  effects();
14733
- styles("effects", "Layer Effects");
14734
- } else if (layer.type === "smart") {
14735
- effects();
14736
- styles("smart-filters", "Smart Filters");
14737
- styles("effects", "Layer Effects");
14738
- } else if (layer.type === "group") {
14728
+ } else if (layer.type === "smart" || layer.type === "group") {
14739
14729
  effects();
14740
14730
  }
14741
14731
  if (layer.mask) {
@@ -14747,14 +14737,14 @@ function layerPanels(layer, options = {}) {
14747
14737
  // src/image-editor/layers/effects-ui.ts
14748
14738
  function layerEffectsPanel(layer) {
14749
14739
  const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
14750
- if (!layer) return { ...empty, available: false, reason: "Select a layer to add effects." };
14751
- if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have effects." };
14740
+ if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
14741
+ if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
14752
14742
  const fx = layer.effects;
14753
14743
  const readOnly = Boolean(layer.locks?.all);
14754
14744
  return {
14755
14745
  available: true,
14756
14746
  readOnly,
14757
- reason: readOnly ? "The layer is locked; unlock it to change its effects." : void 0,
14747
+ reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
14758
14748
  enabled: fx?.enabled ?? true,
14759
14749
  scale: fx?.scale ?? 1,
14760
14750
  rows: (fx?.items ?? []).map((e) => ({ id: e.id, kind: e.kind, label: layerEffectLabel(e.kind), enabled: e.enabled }))
@@ -110,16 +110,19 @@ export interface LayerPanelDescriptor {
110
110
  }
111
111
  export interface LayerPanelsOptions {
112
112
  /**
113
- * The editor has an effects provider (`controller.effectsProvider`): one `provider-effects`
114
- * panel ("Effects") holds everything that changes how a layer looks beyond its own settings:
115
- * an effect layer's effect (change it, its frame or animation, its controls), and the layer's
116
- * styles (drop shadow, stroke…) and filters. It takes the place of the `effects` (Layer
117
- * Effects) and `smart-filters` panels. New effect layers are added from the layers panel
113
+ * The editor has an effects provider (`controller.effectsProvider`): adds the `provider-effects`
114
+ * panel ("Effects") for layers that can take provider effects. It holds an effect layer's own
115
+ * effect (change it, its frame or animation, its controls) and the provider filters applied to
116
+ * the layer (smart filters). New effect layers are added from the layers panel
118
117
  * (`newLayerOptions`).
119
118
  */
120
119
  effects?: boolean;
121
120
  }
122
121
  /**
123
122
  * Returns contextual panels that apply to the currently active layer (or layer-independent panels if null).
123
+ *
124
+ * `properties` ("Layer Properties") is first for every layer and includes the layer's Layer Style
125
+ * (drop shadow, stroke, glow…: `layerEffectsPanel`) for layers that can take one, with or without a
126
+ * provider. There is no separate `effects` (Layer Effects) or `smart-filters` panel.
124
127
  */
125
128
  export declare function layerPanels(layer: ImageLayer | null, options?: LayerPanelsOptions): LayerPanelDescriptor[];
@@ -110,16 +110,19 @@ export interface LayerPanelDescriptor {
110
110
  }
111
111
  export interface LayerPanelsOptions {
112
112
  /**
113
- * The editor has an effects provider (`controller.effectsProvider`): one `provider-effects`
114
- * panel ("Effects") holds everything that changes how a layer looks beyond its own settings:
115
- * an effect layer's effect (change it, its frame or animation, its controls), and the layer's
116
- * styles (drop shadow, stroke…) and filters. It takes the place of the `effects` (Layer
117
- * Effects) and `smart-filters` panels. New effect layers are added from the layers panel
113
+ * The editor has an effects provider (`controller.effectsProvider`): adds the `provider-effects`
114
+ * panel ("Effects") for layers that can take provider effects. It holds an effect layer's own
115
+ * effect (change it, its frame or animation, its controls) and the provider filters applied to
116
+ * the layer (smart filters). New effect layers are added from the layers panel
118
117
  * (`newLayerOptions`).
119
118
  */
120
119
  effects?: boolean;
121
120
  }
122
121
  /**
123
122
  * Returns contextual panels that apply to the currently active layer (or layer-independent panels if null).
123
+ *
124
+ * `properties` ("Layer Properties") is first for every layer and includes the layer's Layer Style
125
+ * (drop shadow, stroke, glow…: `layerEffectsPanel`) for layers that can take one, with or without a
126
+ * provider. There is no separate `effects` (Layer Effects) or `smart-filters` panel.
124
127
  */
125
128
  export declare function layerPanels(layer: ImageLayer | null, options?: LayerPanelsOptions): LayerPanelDescriptor[];
@@ -4,7 +4,8 @@
4
4
  * `remove_effect`) on layers, where filter effects become smart filters, plus `add_effect_layer`
5
5
  * for generator, overlay and title effects and `set_effect_layer` to change one (its effect, still
6
6
  * frame or animation). (Drop shadows, strokes and the other layer styles are
7
- * `set_layer_effect`, a different thing.)
7
+ * `add_layer_effect`, a different thing: the Layer Style section of Layer Properties, not the
8
+ * Effects panel.)
8
9
  */
9
10
  import { type AppliedEffectInfo } from '../effects/tools.cjs';
10
11
  import type { AgentToolProvider } from '../tools/registry.cjs';
@@ -4,7 +4,8 @@
4
4
  * `remove_effect`) on layers, where filter effects become smart filters, plus `add_effect_layer`
5
5
  * for generator, overlay and title effects and `set_effect_layer` to change one (its effect, still
6
6
  * frame or animation). (Drop shadows, strokes and the other layer styles are
7
- * `set_layer_effect`, a different thing.)
7
+ * `add_layer_effect`, a different thing: the Layer Style section of Layer Properties, not the
8
+ * Effects panel.)
8
9
  */
9
10
  import { type AppliedEffectInfo } from '../effects/tools.js';
10
11
  import type { AgentToolProvider } from '../tools/registry.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.177.0",
3
+ "version": "0.178.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -49,6 +49,11 @@ For general error reporting and undo conventions, see `pixerate-agent-tools`.
49
49
 
50
50
  - **Batch parameter changes.** Set all related control values in a single `effect_authoring_set_values`
51
51
  call so they apply cleanly in a single undo step.
52
+ - **Write colours as hex.** A control with `type: "color"` in `effect_authoring_describe` takes
53
+ `#rrggbb` (or `#rrggbbaa` when `alpha` is true), even when the provider's schema also accepts 0–1
54
+ channel arrays or CSS colour strings (Flair's colours do). Hex keyframes blend smoothly. A control
55
+ that is in `values` but has no entry in `controls` has a shape no field can edit. Set it only with a
56
+ value that matches the provider's schema.
52
57
  - **Check compile issues.** When editing source code via `effect_authoring_set_source`, always verify
53
58
  the returned `issues` array. Fix errors before attempting to preview or set controls.
54
59
  - **Keyframe animation tracks.** Controls with active keyframes calculate their values dynamically
@@ -117,7 +117,10 @@ drawing or editing either.
117
117
  annotation and group layers (not adjustment layers) and follow the layer's pixels as they
118
118
  change. Add them with `add_layer_effect` (`kind` plus only the `settings` that differ from
119
119
  Photoshop's defaults), tune them with `update_layer_effect` and read them back with
120
- `list_layer_effects`. Each call is one undo step and returns the layer's effects.
120
+ `list_layer_effects`. Each call is one undo step and returns the layer's effects. In the UI
121
+ they are the **Layer Style** section of **Layer Properties**; the separate **Effects** panel is
122
+ for provider effects (effect layers and filters), so say "layer style" when you tell the user
123
+ where a drop shadow or stroke lives.
121
124
  2. **Keep the ids**: `add_layer_effect` returns `effectId`; `update_layer_effect` and
122
125
  `remove_layer_effect` need it. `list_layers` shows which layers have effects (ids and kinds
123
126
  only).
@@ -2,7 +2,10 @@
2
2
 
3
3
  The host may register an effects provider (for example Flair). The tools then reach its catalog:
4
4
  filter effects become **smart filters**, and generator, overlay and title effects become
5
- **effect layers**. These are not the layer styles of `set_layer_effect` (drop shadow, stroke, glow).
5
+ **effect layers**. These are not the layer styles of `add_layer_effect` (drop shadow, stroke, glow).
6
+ In the UI, the **Effects** panel holds an effect layer's controls and the layer's filters; layer
7
+ styles are the **Layer Style** section of **Layer Properties**. Use those names when you tell the
8
+ user where to find what you changed.
6
9
 
7
10
  ## Working method
8
11