@pixerate/editor 0.167.0 → 0.168.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.
@@ -192,9 +192,11 @@ async function createEffectAuthoringSession(source, options) {
192
192
  let playing = false;
193
193
  let cancelSchedule = null;
194
194
  let lastScheduleTime = null;
195
- let playheadTime = 0;
196
195
  let duration = _nullishCoalesce(_nullishCoalesce(_optionalChain([initialDoc, 'optionalAccess', _ => _.duration]), () => ( description.duration)), () => ( 1e3));
197
196
  if (!(duration > 0)) duration = 1e3;
197
+ const start = options.startTime;
198
+ let playheadTime = typeof start === "number" && Number.isFinite(start) ? Math.max(0, Math.min(duration, start)) : duration / 2;
199
+ let previewError = null;
198
200
  let loop = _nullishCoalesce(_nullishCoalesce(_optionalChain([initialDoc, 'optionalAccess', _2 => _2.loop]), () => ( description.loop)), () => ( false));
199
201
  let compiled = null;
200
202
  let savedPresets = initialDoc ? [..._nullishCoalesce(initialDoc.presets, () => ( []))] : [];
@@ -258,6 +260,7 @@ async function createEffectAuthoringSession(source, options) {
258
260
  tracks: { ...tracks },
259
261
  issues: [],
260
262
  compiled,
263
+ previewError,
261
264
  time: playheadTime,
262
265
  duration,
263
266
  loop,
@@ -704,8 +707,23 @@ async function createEffectAuthoringSession(source, options) {
704
707
  if (disposed) {
705
708
  throw new (0, _chunkRUZQMYXHcjs.EffectDisposedError)(effectId);
706
709
  }
707
- const renderer = await provider.createRenderer(effectId, opts);
710
+ let renderer;
711
+ try {
712
+ renderer = await provider.createRenderer(effectId, opts);
713
+ } catch (e) {
714
+ const message = e instanceof Error ? e.message : String(e);
715
+ const reason = description.kind === "vector" ? `No pixel preview for this vector effect: ${message}` : `No pixel preview: ${message}`;
716
+ if (previewError !== reason) {
717
+ previewError = reason;
718
+ invalidateState();
719
+ }
720
+ throw e;
721
+ }
708
722
  livePreviews.add(renderer);
723
+ if (previewError !== null) {
724
+ previewError = null;
725
+ invalidateState();
726
+ }
709
727
  const preview = {
710
728
  effectId: renderer.effectId,
711
729
  width: renderer.width,
@@ -192,9 +192,11 @@ async function createEffectAuthoringSession(source, options) {
192
192
  let playing = false;
193
193
  let cancelSchedule = null;
194
194
  let lastScheduleTime = null;
195
- let playheadTime = 0;
196
195
  let duration = initialDoc?.duration ?? description.duration ?? 1e3;
197
196
  if (!(duration > 0)) duration = 1e3;
197
+ const start = options.startTime;
198
+ let playheadTime = typeof start === "number" && Number.isFinite(start) ? Math.max(0, Math.min(duration, start)) : duration / 2;
199
+ let previewError = null;
198
200
  let loop = initialDoc?.loop ?? description.loop ?? false;
199
201
  let compiled = null;
200
202
  let savedPresets = initialDoc ? [...initialDoc.presets ?? []] : [];
@@ -258,6 +260,7 @@ async function createEffectAuthoringSession(source, options) {
258
260
  tracks: { ...tracks },
259
261
  issues: [],
260
262
  compiled,
263
+ previewError,
261
264
  time: playheadTime,
262
265
  duration,
263
266
  loop,
@@ -704,8 +707,23 @@ async function createEffectAuthoringSession(source, options) {
704
707
  if (disposed) {
705
708
  throw new EffectDisposedError(effectId);
706
709
  }
707
- const renderer = await provider.createRenderer(effectId, opts);
710
+ let renderer;
711
+ try {
712
+ renderer = await provider.createRenderer(effectId, opts);
713
+ } catch (e) {
714
+ const message = e instanceof Error ? e.message : String(e);
715
+ const reason = description.kind === "vector" ? `No pixel preview for this vector effect: ${message}` : `No pixel preview: ${message}`;
716
+ if (previewError !== reason) {
717
+ previewError = reason;
718
+ invalidateState();
719
+ }
720
+ throw e;
721
+ }
708
722
  livePreviews.add(renderer);
723
+ if (previewError !== null) {
724
+ previewError = null;
725
+ invalidateState();
726
+ }
709
727
  const preview = {
710
728
  effectId: renderer.effectId,
711
729
  width: renderer.width,
@@ -17,6 +17,11 @@ export interface GenericAuthoringOptions {
17
17
  schedule?: (frame: (now: number) => void) => () => void;
18
18
  /** Ms within which `setValue` calls on one control with no gesture merge (default 400). */
19
19
  mergeWindowMs?: number;
20
+ /**
21
+ * Where the playhead starts (ms, clamped to 0..duration). Default: half the duration, as
22
+ * catalog thumbnails do, so entrance-style effects and transitions open on a frame that shows them.
23
+ */
24
+ startTime?: number;
20
25
  }
21
26
  /**
22
27
  * Creates an effect authoring session with values, presets, keyframes, timing and undo
@@ -17,6 +17,11 @@ export interface GenericAuthoringOptions {
17
17
  schedule?: (frame: (now: number) => void) => () => void;
18
18
  /** Ms within which `setValue` calls on one control with no gesture merge (default 400). */
19
19
  mergeWindowMs?: number;
20
+ /**
21
+ * Where the playhead starts (ms, clamped to 0..duration). Default: half the duration, as
22
+ * catalog thumbnails do, so entrance-style effects and transitions open on a frame that shows them.
23
+ */
24
+ startTime?: number;
20
25
  }
21
26
  /**
22
27
  * Creates an effect authoring session with values, presets, keyframes, timing and undo
@@ -65,6 +65,12 @@ export interface EffectAuthoringState {
65
65
  issues: readonly EffectAuthoringIssue[];
66
66
  /** Whether the source compiled: true, false, or null when that is not known yet (no preview has compiled it). */
67
67
  compiled: boolean | null;
68
+ /**
69
+ * Why `createPreview` could not make a pixel preview (for example a vector effect whose provider
70
+ * only draws it as SVG), or null when it could or has not been asked yet. Optional for sessions
71
+ * that never fail to preview.
72
+ */
73
+ previewError?: string | null;
68
74
  /** Current playhead position (ms). */
69
75
  time: number;
70
76
  /** Length of one play (ms). */
@@ -65,6 +65,12 @@ export interface EffectAuthoringState {
65
65
  issues: readonly EffectAuthoringIssue[];
66
66
  /** Whether the source compiled: true, false, or null when that is not known yet (no preview has compiled it). */
67
67
  compiled: boolean | null;
68
+ /**
69
+ * Why `createPreview` could not make a pixel preview (for example a vector effect whose provider
70
+ * only draws it as SVG), or null when it could or has not been asked yet. Optional for sessions
71
+ * that never fail to preview.
72
+ */
73
+ previewError?: string | null;
68
74
  /** Current playhead position (ms). */
69
75
  time: number;
70
76
  /** Length of one play (ms). */
@@ -3,7 +3,7 @@
3
3
  var _chunkFKUKJ3XAcjs = require('../chunk-FKUKJ3XA.cjs');
4
4
 
5
5
 
6
- var _chunk6DM3PUQDcjs = require('../chunk-6DM3PUQD.cjs');
6
+ var _chunkCYKWYP6Dcjs = require('../chunk-CYKWYP6D.cjs');
7
7
 
8
8
 
9
9
  var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
@@ -568,7 +568,7 @@ function createFakeEffectProvider(options = {}) {
568
568
  };
569
569
  },
570
570
  ...supportsAuthoring ? {
571
- openAuthoring: (from) => _chunk6DM3PUQDcjs.createEffectAuthoringSession.call(void 0, from, { provider })
571
+ openAuthoring: (from) => _chunkCYKWYP6Dcjs.createEffectAuthoringSession.call(void 0, from, { provider })
572
572
  } : {}
573
573
  };
574
574
  return provider;
@@ -738,7 +738,7 @@ function createEffectAuthoringToolProvider(host, options) {
738
738
  const describeTool = {
739
739
  name: "effect_authoring_describe",
740
740
  title: "Describe open effect",
741
- description: "Describes the effect currently open for authoring: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, duration, loop, and compile issues.",
741
+ description: "Describes the effect currently open for authoring: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, playhead time, duration, loop, compile issues, and previewError: why there is no pixel preview (e.g. a vector effect the provider only draws as SVG), or null.",
742
742
  inputSchema: object({}),
743
743
  annotations: { title: "Describe open effect", ...ANNOTATIONS.read },
744
744
  handler: () => {
@@ -755,9 +755,11 @@ function createEffectAuthoringToolProvider(host, options) {
755
755
  control,
756
756
  keyframes: track.length
757
757
  })),
758
+ time: state.time,
758
759
  duration: state.duration,
759
760
  loop: state.loop,
760
- issues: state.issues
761
+ issues: state.issues,
762
+ previewError: _nullishCoalesce(state.previewError, () => ( null))
761
763
  };
762
764
  }
763
765
  };
@@ -1013,7 +1015,7 @@ function createEffectAuthoringToolProvider(host, options) {
1013
1015
  const viewTool = {
1014
1016
  name: "effect_authoring_view",
1015
1017
  title: "View effect preview image",
1016
- description: "Captures an image of the effect preview at the current playhead time or at a specified time in milliseconds.",
1018
+ description: "Captures an image of the effect preview at the current playhead time or at a specified time in milliseconds. Refused, with the reason, when the effect has no pixel preview (see previewError in effect_authoring_describe).",
1017
1019
  inputSchema: object({
1018
1020
  time: { type: "number", minimum: 0, description: "Optional time in milliseconds to view the preview at. Moves playhead to this time before capturing." }
1019
1021
  }),
@@ -1021,6 +1023,10 @@ function createEffectAuthoringToolProvider(host, options) {
1021
1023
  handler: async (args) => {
1022
1024
  const session = requireSession();
1023
1025
  if (!host.capture) throw new Error("Capturing a preview image is not supported by this host.");
1026
+ const previewError = session.getState().previewError;
1027
+ if (previewError) {
1028
+ throw new Error(`${previewError} The other effect authoring tools still work; check values with effect_authoring_describe.`);
1029
+ }
1024
1030
  if (args.time !== void 0) {
1025
1031
  if (typeof args.time !== "number" || !Number.isFinite(args.time) || args.time < 0) {
1026
1032
  throw new Error("time must be a finite non-negative number.");
@@ -1107,4 +1113,4 @@ function createEffectAuthoringToolProvider(host, options) {
1107
1113
 
1108
1114
 
1109
1115
 
1110
- exports.EFFECT_ERROR_CODES = _chunkRUZQMYXHcjs.EFFECT_ERROR_CODES; exports.EFFECT_KINDS = _chunkRUZQMYXHcjs.EFFECT_KINDS; exports.EFFECT_USES = _chunkRUZQMYXHcjs.EFFECT_USES; exports.EFFECT_USE_LABELS = EFFECT_USE_LABELS; exports.EffectControlError = _chunkRUZQMYXHcjs.EffectControlError; exports.EffectDisposedError = _chunkRUZQMYXHcjs.EffectDisposedError; exports.EffectError = _chunkRUZQMYXHcjs.EffectError; exports.EffectRendererPool = _chunkPY4GWSE2cjs.EffectRendererPool; exports.EffectUnsupportedError = _chunkRUZQMYXHcjs.EffectUnsupportedError; exports.EffectsSlot = _chunkRUZQMYXHcjs.EffectsSlot; exports.NoEffectsProviderError = _chunkRUZQMYXHcjs.NoEffectsProviderError; exports.UnknownEffectError = _chunkRUZQMYXHcjs.UnknownEffectError; exports.applyEffectMask = _chunkRUZQMYXHcjs.applyEffectMask; exports.checkEffectProvider = checkEffectProvider; exports.createEffectAuthoringSession = _chunk6DM3PUQDcjs.createEffectAuthoringSession; exports.createEffectAuthoringToolProvider = createEffectAuthoringToolProvider; exports.createEffectPixels = _chunkRUZQMYXHcjs.createEffectPixels; exports.createEffectToolProvider = _chunkRUZQMYXHcjs.createEffectToolProvider; exports.createFakeEffectProvider = createFakeEffectProvider; exports.effectControlField = effectControlField; exports.effectFieldValue = effectFieldValue; exports.effectFontFamilies = effectFontFamilies; exports.effectParameterFields = effectParameterFields; exports.effectSampleInputs = effectSampleInputs; exports.effectSamplePicture = effectSamplePicture; exports.effectValueErrors = _chunkRUZQMYXHcjs.effectValueErrors; exports.encodeEffectFloat = _chunkRUZQMYXHcjs.encodeEffectFloat; exports.groupEffectsByCategory = groupEffectsByCategory; exports.isEffectError = _chunkRUZQMYXHcjs.isEffectError; exports.isEffectFontControl = isEffectFontControl; exports.isEffectPixels = _chunkRUZQMYXHcjs.isEffectPixels; exports.linearToSrgb = _chunkRUZQMYXHcjs.linearToSrgb; exports.renderEffectThumbnail = renderEffectThumbnail; exports.resolveEffectValues = _chunkRUZQMYXHcjs.resolveEffectValues; exports.searchEffectSummaries = _chunkRUZQMYXHcjs.searchEffectSummaries; exports.srgbToLinear = _chunkRUZQMYXHcjs.srgbToLinear;
1116
+ exports.EFFECT_ERROR_CODES = _chunkRUZQMYXHcjs.EFFECT_ERROR_CODES; exports.EFFECT_KINDS = _chunkRUZQMYXHcjs.EFFECT_KINDS; exports.EFFECT_USES = _chunkRUZQMYXHcjs.EFFECT_USES; exports.EFFECT_USE_LABELS = EFFECT_USE_LABELS; exports.EffectControlError = _chunkRUZQMYXHcjs.EffectControlError; exports.EffectDisposedError = _chunkRUZQMYXHcjs.EffectDisposedError; exports.EffectError = _chunkRUZQMYXHcjs.EffectError; exports.EffectRendererPool = _chunkPY4GWSE2cjs.EffectRendererPool; exports.EffectUnsupportedError = _chunkRUZQMYXHcjs.EffectUnsupportedError; exports.EffectsSlot = _chunkRUZQMYXHcjs.EffectsSlot; exports.NoEffectsProviderError = _chunkRUZQMYXHcjs.NoEffectsProviderError; exports.UnknownEffectError = _chunkRUZQMYXHcjs.UnknownEffectError; exports.applyEffectMask = _chunkRUZQMYXHcjs.applyEffectMask; exports.checkEffectProvider = checkEffectProvider; exports.createEffectAuthoringSession = _chunkCYKWYP6Dcjs.createEffectAuthoringSession; exports.createEffectAuthoringToolProvider = createEffectAuthoringToolProvider; exports.createEffectPixels = _chunkRUZQMYXHcjs.createEffectPixels; exports.createEffectToolProvider = _chunkRUZQMYXHcjs.createEffectToolProvider; exports.createFakeEffectProvider = createFakeEffectProvider; exports.effectControlField = effectControlField; exports.effectFieldValue = effectFieldValue; exports.effectFontFamilies = effectFontFamilies; exports.effectParameterFields = effectParameterFields; exports.effectSampleInputs = effectSampleInputs; exports.effectSamplePicture = effectSamplePicture; exports.effectValueErrors = _chunkRUZQMYXHcjs.effectValueErrors; exports.encodeEffectFloat = _chunkRUZQMYXHcjs.encodeEffectFloat; exports.groupEffectsByCategory = groupEffectsByCategory; exports.isEffectError = _chunkRUZQMYXHcjs.isEffectError; exports.isEffectFontControl = isEffectFontControl; exports.isEffectPixels = _chunkRUZQMYXHcjs.isEffectPixels; exports.linearToSrgb = _chunkRUZQMYXHcjs.linearToSrgb; exports.renderEffectThumbnail = renderEffectThumbnail; exports.resolveEffectValues = _chunkRUZQMYXHcjs.resolveEffectValues; exports.searchEffectSummaries = _chunkRUZQMYXHcjs.searchEffectSummaries; exports.srgbToLinear = _chunkRUZQMYXHcjs.srgbToLinear;
@@ -3,7 +3,7 @@ import {
3
3
  } from "../chunk-CJE5MOIS.js";
4
4
  import {
5
5
  createEffectAuthoringSession
6
- } from "../chunk-ZGOHKS3X.js";
6
+ } from "../chunk-HCC2LBCW.js";
7
7
  import {
8
8
  EffectRendererPool
9
9
  } from "../chunk-EHLOCVWB.js";
@@ -738,7 +738,7 @@ function createEffectAuthoringToolProvider(host, options) {
738
738
  const describeTool = {
739
739
  name: "effect_authoring_describe",
740
740
  title: "Describe open effect",
741
- description: "Describes the effect currently open for authoring: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, duration, loop, and compile issues.",
741
+ description: "Describes the effect currently open for authoring: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, playhead time, duration, loop, compile issues, and previewError: why there is no pixel preview (e.g. a vector effect the provider only draws as SVG), or null.",
742
742
  inputSchema: object({}),
743
743
  annotations: { title: "Describe open effect", ...ANNOTATIONS.read },
744
744
  handler: () => {
@@ -755,9 +755,11 @@ function createEffectAuthoringToolProvider(host, options) {
755
755
  control,
756
756
  keyframes: track.length
757
757
  })),
758
+ time: state.time,
758
759
  duration: state.duration,
759
760
  loop: state.loop,
760
- issues: state.issues
761
+ issues: state.issues,
762
+ previewError: state.previewError ?? null
761
763
  };
762
764
  }
763
765
  };
@@ -1013,7 +1015,7 @@ function createEffectAuthoringToolProvider(host, options) {
1013
1015
  const viewTool = {
1014
1016
  name: "effect_authoring_view",
1015
1017
  title: "View effect preview image",
1016
- description: "Captures an image of the effect preview at the current playhead time or at a specified time in milliseconds.",
1018
+ description: "Captures an image of the effect preview at the current playhead time or at a specified time in milliseconds. Refused, with the reason, when the effect has no pixel preview (see previewError in effect_authoring_describe).",
1017
1019
  inputSchema: object({
1018
1020
  time: { type: "number", minimum: 0, description: "Optional time in milliseconds to view the preview at. Moves playhead to this time before capturing." }
1019
1021
  }),
@@ -1021,6 +1023,10 @@ function createEffectAuthoringToolProvider(host, options) {
1021
1023
  handler: async (args) => {
1022
1024
  const session = requireSession();
1023
1025
  if (!host.capture) throw new Error("Capturing a preview image is not supported by this host.");
1026
+ const previewError = session.getState().previewError;
1027
+ if (previewError) {
1028
+ throw new Error(`${previewError} The other effect authoring tools still work; check values with effect_authoring_describe.`);
1029
+ }
1024
1030
  if (args.time !== void 0) {
1025
1031
  if (typeof args.time !== "number" || !Number.isFinite(args.time) || args.time < 0) {
1026
1032
  throw new Error("time must be a finite non-negative number.");
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7;
2
2
 
3
- var _chunk6DM3PUQDcjs = require('../chunk-6DM3PUQD.cjs');
3
+ var _chunkCYKWYP6Dcjs = require('../chunk-CYKWYP6D.cjs');
4
4
 
5
5
 
6
6
 
@@ -6136,7 +6136,7 @@ async function openVideoClipEffectAuthoring(controller, clip, instance, options
6136
6136
  const at = _chunk3OSXHLITcjs.findVideoClip.call(void 0, controller.getProject(), clip);
6137
6137
  if (!at) throw new Error(`There is no clip "${clip}".`);
6138
6138
  const doc = videoClipEffectDocument(at.clip, instance, provider.id);
6139
- const session = await _chunk6DM3PUQDcjs.createEffectAuthoringSession.call(void 0, { document: doc }, { ...options, provider });
6139
+ const session = await _chunkCYKWYP6Dcjs.createEffectAuthoringSession.call(void 0, { document: doc }, { ...options, provider });
6140
6140
  return {
6141
6141
  clip,
6142
6142
  instance,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createEffectAuthoringSession
3
- } from "../chunk-ZGOHKS3X.js";
3
+ } from "../chunk-HCC2LBCW.js";
4
4
  import {
5
5
  VIDEO_ADJUSTMENT_SCOPES,
6
6
  VIDEO_BLEND_MODES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.167.0",
3
+ "version": "0.168.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -21,7 +21,9 @@ For general error reporting and undo conventions, see `pixerate-agent-tools`.
21
21
 
22
22
  1. **Inspect first.** Run `effect_authoring_describe` to inspect the effect name, kind, source
23
23
  language (`glsl`, `svg`, or null when the effect has no source to edit), control parameter schemas, current
24
- values, existing tracks, and compile issues.
24
+ values, existing tracks, playhead `time`, compile issues and `previewError`.
25
+ A session opens with its playhead at half the effect's length (where entrance-style effects and
26
+ transitions show), so values set on an animated control key that time unless you seek first.
25
27
  2. **Read or update source code.** If `sourceLanguage` is non-null, use `effect_authoring_get_source`
26
28
  to read the shader or script code. Use `effect_authoring_set_source` to recompile with new code
27
29
  and immediately inspect any reported syntax or compilation issues with line numbers.
@@ -38,7 +40,10 @@ For general error reporting and undo conventions, see `pixerate-agent-tools`.
38
40
  6. **Save presets.** When an interesting look is achieved, save it with `effect_authoring_save_preset`
39
41
  or restore known presets with `effect_authoring_apply_preset`.
40
42
  7. **Verify visually.** When `effect_authoring_view` is available, capture rendered preview frames
41
- at specific times to visually confirm effect appearance.
43
+ at specific times to visually confirm effect appearance. When `effect_authoring_describe` reports a
44
+ `previewError` (typically a `vector` effect whose provider only draws it as SVG), there is no pixel
45
+ preview: `effect_authoring_view` is refused with that reason, but values, presets, keyframes and
46
+ timing still work. Judge the result from the values instead of retrying the view.
42
47
 
43
48
  ## Best practices
44
49
 
@@ -56,7 +61,7 @@ For general error reporting and undo conventions, see `pixerate-agent-tools`.
56
61
 
57
62
  | Tool | Description and usage |
58
63
  | --- | --- |
59
- | `effect_authoring_describe` | Reads the currently open effect session: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, duration, loop, and compile issues. |
64
+ | `effect_authoring_describe` | Reads the currently open effect session: name, kind, source language, controls schema and current values, presets, animated tracks with keyframe counts, playhead `time`, duration, loop, compile issues, and `previewError` (why there is no pixel preview, or null). Call it first. |
60
65
  | `effect_authoring_get_source` | Retrieves shader or script source code and language for code-backed effects. Refused if `sourceLanguage` is null. |
61
66
  | `effect_authoring_set_source` | Recompiles the effect with new shader or script source code. Returns compiler issues with line numbers and messages. Available only when supported by the session. |
62
67
  | `effect_authoring_set_values` | Sets one or more control values at the current playhead time as a single undo step. Rejects all changes if any control name or value is invalid. |
@@ -70,11 +75,13 @@ For general error reporting and undo conventions, see `pixerate-agent-tools`.
70
75
  | `effect_authoring_seek` | Moves the preview playhead to a specific timeline position in milliseconds (clamped to 0..duration) and returns values at that time. |
71
76
  | `effect_authoring_undo` | Undoes the most recent edit in the authoring session. |
72
77
  | `effect_authoring_redo` | Redoes the most recently undone edit in the authoring session. |
73
- | `effect_authoring_view` | Captures a preview image of the effect at the current playhead or a specified timestamp. Available when preview capture is supported. |
78
+ | `effect_authoring_view` | Captures a preview image of the effect at the current playhead or a specified timestamp. Available when preview capture is supported. Refused, with the reason, when `effect_authoring_describe` shows a `previewError`. |
74
79
 
75
80
  ## Pitfalls
76
81
 
77
82
  - Calling authoring tools when no authoring session is open returns an error explaining that a session must be opened first.
78
83
  - Animated controls calculate their values dynamically from keyframes; clearing a track reverts the parameter to static behavior.
79
84
  - Compiling invalid shader code produces issues in `effect_authoring_set_source`; inspect the line numbers and messages to correct syntax.
85
+ - A `vector` effect may have no pixel preview (the provider refuses a pixel renderer); check `previewError` rather than reading a blank capture as a broken effect.
86
+ - The playhead does not start at 0. Pass explicit `time`s to `effect_authoring_set_keyframe`, or `effect_authoring_seek` before setting values on an animated control.
80
87
  - Control values must match their schema types and bounds; colours must be `#rrggbb` (or `#rrggbbaa`), and numbers must fall within `[min, max]`.