@pixerate/editor 0.229.0 → 0.231.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 (73) hide show
  1. package/dist/animation-editor/camera-tools.d.cts +10 -0
  2. package/dist/animation-editor/camera-tools.d.ts +10 -0
  3. package/dist/animation-editor/camera.d.cts +67 -0
  4. package/dist/animation-editor/camera.d.ts +67 -0
  5. package/dist/animation-editor/compile.d.cts +4 -0
  6. package/dist/animation-editor/compile.d.ts +4 -0
  7. package/dist/animation-editor/controller.d.cts +34 -2
  8. package/dist/animation-editor/controller.d.ts +34 -2
  9. package/dist/animation-editor/effect-tools.d.cts +2 -1
  10. package/dist/animation-editor/effect-tools.d.ts +2 -1
  11. package/dist/animation-editor/evaluate.d.cts +9 -0
  12. package/dist/animation-editor/evaluate.d.ts +9 -0
  13. package/dist/animation-editor/flair.d.cts +8 -0
  14. package/dist/animation-editor/flair.d.ts +8 -0
  15. package/dist/animation-editor/index.cjs +603 -217
  16. package/dist/animation-editor/index.d.cts +2 -0
  17. package/dist/animation-editor/index.d.ts +2 -0
  18. package/dist/animation-editor/index.js +454 -68
  19. package/dist/animation-editor/issues.d.cts +16 -0
  20. package/dist/animation-editor/issues.d.ts +16 -0
  21. package/dist/animation-editor/tools.d.cts +1 -1
  22. package/dist/animation-editor/tools.d.ts +1 -1
  23. package/dist/animation-editor/types.d.cts +21 -3
  24. package/dist/animation-editor/types.d.ts +21 -3
  25. package/dist/canvas/index.cjs +7 -7
  26. package/dist/canvas/index.js +1 -1
  27. package/dist/{chunk-IGPEBXUD.cjs → chunk-5T3H7CGG.cjs} +21 -11
  28. package/dist/{chunk-K5GXW5TR.cjs → chunk-C73U5UI3.cjs} +14 -14
  29. package/dist/{chunk-LPTFDCJO.js → chunk-CSM5T6SE.js} +14 -4
  30. package/dist/{chunk-EBDZWIOP.cjs → chunk-ERJA5CGT.cjs} +5 -1
  31. package/dist/{chunk-5MQOBTNP.cjs → chunk-OPSK22DL.cjs} +80 -9
  32. package/dist/{chunk-PB6JV62G.js → chunk-SBPGIZQN.js} +1 -1
  33. package/dist/{chunk-UGYUGZE2.js → chunk-TCZ2J7PR.js} +71 -0
  34. package/dist/{chunk-W4KFNAWC.js → chunk-TYCJGFCF.js} +5 -1
  35. package/dist/effects/helpers.d.cts +35 -1
  36. package/dist/effects/helpers.d.ts +35 -1
  37. package/dist/effects/index.cjs +60 -44
  38. package/dist/effects/index.js +18 -2
  39. package/dist/effects/types.d.cts +15 -0
  40. package/dist/effects/types.d.ts +15 -0
  41. package/dist/image-editor/index.cjs +13 -13
  42. package/dist/image-editor/index.js +1 -1
  43. package/dist/paint-editor/index.cjs +7 -7
  44. package/dist/paint-editor/index.js +2 -2
  45. package/dist/vector/index.cjs +6 -6
  46. package/dist/vector/index.js +1 -1
  47. package/dist/video-editor/camera-tools.d.cts +10 -0
  48. package/dist/video-editor/camera-tools.d.ts +10 -0
  49. package/dist/video-editor/camera.d.cts +47 -0
  50. package/dist/video-editor/camera.d.ts +47 -0
  51. package/dist/video-editor/check.d.cts +1 -1
  52. package/dist/video-editor/check.d.ts +1 -1
  53. package/dist/video-editor/controller.d.cts +37 -2
  54. package/dist/video-editor/controller.d.ts +37 -2
  55. package/dist/video-editor/effect-tools.d.cts +2 -1
  56. package/dist/video-editor/effect-tools.d.ts +2 -1
  57. package/dist/video-editor/index.cjs +705 -390
  58. package/dist/video-editor/index.d.cts +2 -0
  59. package/dist/video-editor/index.d.ts +2 -0
  60. package/dist/video-editor/index.js +334 -19
  61. package/dist/video-editor/keyframes.d.cts +10 -3
  62. package/dist/video-editor/keyframes.d.ts +10 -3
  63. package/dist/video-editor/parse.d.cts +5 -3
  64. package/dist/video-editor/parse.d.ts +5 -3
  65. package/dist/video-editor/tools.d.cts +18 -0
  66. package/dist/video-editor/tools.d.ts +18 -0
  67. package/dist/video-editor/types.d.cts +37 -1
  68. package/dist/video-editor/types.d.ts +37 -1
  69. package/package.json +1 -1
  70. package/skills/pixerate-animation-editor/SKILL.md +28 -1
  71. package/skills/pixerate-animation-motion-graphics/SKILL.md +3 -0
  72. package/skills/pixerate-video-editor/SKILL.md +16 -1
  73. package/skills/pixerate-video-montage/SKILL.md +2 -1
@@ -209,6 +209,69 @@ async function sampleEffectCameraMove(provider, id, request) {
209
209
  const { from, to, ms, stage, values } = request;
210
210
  return sampleCameraViews((u) => provider.cameraView(id, { from, to, u, ms, stage }, values), { ms, fps: request.fps, cut: d.camera.cut });
211
211
  }
212
+ var cameraMoveField = (role) => role === "transition" ? "in" : "during";
213
+ function cameraMovesFor(catalog, role) {
214
+ return catalog.filter((e) => e.kind === "camera" && _optionalChain([e, 'access', _2 => _2.camera, 'optionalAccess', _3 => _3.role]) === role);
215
+ }
216
+ function cameraMoveIdList(catalog, role) {
217
+ const ids = cameraMovesFor(catalog, role).map((e) => JSON.stringify(e.id));
218
+ return ids.length ? ids.join(", ") : "none (the provider has no camera moves of that role)";
219
+ }
220
+ function cameraMoveParts(spec) {
221
+ if (typeof spec === "string") return spec ? { move: spec } : void 0;
222
+ if (spec && typeof spec === "object" && !Array.isArray(spec) && typeof spec.move === "string") return spec;
223
+ return void 0;
224
+ }
225
+ var CAMERA_MOVE_MAX_MS = 6e4;
226
+ async function resolveCameraMoveSpec(provider, spec, role) {
227
+ const field = cameraMoveField(role);
228
+ if (!provider.capabilities.supportsCamera || !provider.cameraView) throw new EffectUnsupportedError(`${provider.name} has no camera moves (capabilities.supportsCamera is not set), so camera "${field}" cannot be set.`);
229
+ const parts = cameraMoveParts(spec);
230
+ const catalog = await provider.list({ kind: "camera" });
231
+ if (!parts) throw new EffectUnsupportedError(`Camera "${field}" is a camera move's id, or { move, ms?, preset?, values? }; it takes one of ${cameraMoveIdList(catalog, role)}.`);
232
+ let description;
233
+ try {
234
+ description = await provider.describe(parts.move);
235
+ } catch (error) {
236
+ if (error instanceof UnknownEffectError || error.code === "unknown_effect")
237
+ throw new EffectError("unknown_effect", `There is no camera move "${parts.move}"; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`, parts.move);
238
+ throw error;
239
+ }
240
+ if (description.kind !== "camera" || !description.camera) throw new EffectUnsupportedError(`"${parts.move}" is a ${description.kind} effect, not a camera move; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`, parts.move);
241
+ if (description.camera.role !== role) {
242
+ const other = cameraMoveField(description.camera.role);
243
+ throw new EffectUnsupportedError(
244
+ `"${parts.move}" moves the camera ${description.camera.role === "hold" ? "while a shot holds" : "into a shot"}, so it goes in camera "${other}", not "${field}"; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`,
245
+ parts.move
246
+ );
247
+ }
248
+ if (parts.ms !== void 0) {
249
+ if (role === "hold") throw new EffectUnsupportedError(`A move while the shot holds plays across the shot's hold; set the hold's length instead of "ms".`, parts.move);
250
+ if (!(typeof parts.ms === "number" && Number.isFinite(parts.ms) && parts.ms >= 0 && parts.ms <= CAMERA_MOVE_MAX_MS))
251
+ throw new EffectUnsupportedError(`Camera "in" ms is how long the move takes, 0 to ${CAMERA_MOVE_MAX_MS} (default ${description.camera.durationMs} for "${parts.move}").`, parts.move);
252
+ }
253
+ let presetValues = {};
254
+ if (parts.preset !== void 0) {
255
+ const preset = description.presets.find((p) => p.name === parts.preset);
256
+ if (!preset) throw new EffectUnsupportedError(`"${parts.move}" has no preset ${JSON.stringify(parts.preset)}; its presets are ${description.presets.length ? description.presets.map((p) => JSON.stringify(p.name)).join(", ") : "none"}.`, parts.move);
257
+ presetValues = preset.values;
258
+ }
259
+ const values = { ...presetValues, ..._nullishCoalesce(parts.values, () => ( {})) };
260
+ resolveEffectValues(description, values);
261
+ return {
262
+ spec: { move: description.id, ...parts.ms !== void 0 ? { ms: parts.ms } : {}, ...parts.preset !== void 0 ? { preset: parts.preset } : {}, ...Object.keys(values).length ? { values } : {} },
263
+ description
264
+ };
265
+ }
266
+ function cameraViewOfBox(box, stage) {
267
+ const zoom = Math.min(stage.width / box.width, stage.height / box.height);
268
+ return { zoom, scrollX: stage.width / (2 * zoom) - (box.x + box.width / 2), scrollY: stage.height / (2 * zoom) - (box.y + box.height / 2) };
269
+ }
270
+ function cameraBoxOfView(view, stage) {
271
+ const width = stage.width / view.zoom;
272
+ const height = stage.height / view.zoom;
273
+ return { x: -view.scrollX, y: -view.scrollY, width, height };
274
+ }
212
275
 
213
276
  // src/effects/types.ts
214
277
  var EFFECT_KINDS = ["shader", "vector", "motion", "camera"];
@@ -243,7 +306,7 @@ var summaryOut = (e) => ({
243
306
  category: e.category,
244
307
  uses: e.uses,
245
308
  ...e.description ? { description: e.description } : {},
246
- ..._optionalChain([e, 'access', _2 => _2.tags, 'optionalAccess', _3 => _3.length]) ? { tags: e.tags } : {},
309
+ ..._optionalChain([e, 'access', _4 => _4.tags, 'optionalAccess', _5 => _5.length]) ? { tags: e.tags } : {},
247
310
  transparent: e.transparent,
248
311
  loop: e.loop,
249
312
  ...e.duration !== void 0 ? { duration: e.duration } : {},
@@ -255,7 +318,7 @@ function createEffectToolProvider(host) {
255
318
  const notify = () => listeners.forEach((l) => l());
256
319
  const catalogFor = (provider) => {
257
320
  if (!provider) return null;
258
- if (_optionalChain([catalog, 'optionalAccess', _4 => _4.provider]) !== provider) {
321
+ if (_optionalChain([catalog, 'optionalAccess', _6 => _6.provider]) !== provider) {
259
322
  const entry = { provider, effects: null };
260
323
  catalog = entry;
261
324
  Promise.resolve().then(() => provider.list()).then((effects) => {
@@ -291,7 +354,7 @@ function createEffectToolProvider(host) {
291
354
  description: `${what}: control name \u2192 value, as listed by describe_effect (its "controls" schema: types, ranges, units and defaults). Only the given controls change; colours are "#rrggbb".${keyframes ? " A number control may instead be keyframes { keys: [{ t: ms from the start, v, ease }] }." : ""} Unknown controls and out-of-range values are refused with the valid ones.`
292
355
  });
293
356
  const effectIdSchema = (uses) => {
294
- const effects = _optionalChain([catalogFor, 'call', _5 => _5(host.provider()), 'optionalAccess', _6 => _6.filter, 'call', _7 => _7((e) => effectOffered(e, uses))]);
357
+ const effects = _optionalChain([catalogFor, 'call', _7 => _7(host.provider()), 'optionalAccess', _8 => _8.filter, 'call', _9 => _9((e) => effectOffered(e, uses))]);
295
358
  const base = `An effect id from search_effects (use ${uses.map((u) => `"${u}"`).join(" or ")}).`;
296
359
  return effects && effects.length && effects.length <= ENUM_LIMIT ? { type: "string", enum: effects.map((e) => e.id), description: `${base} One of: ${effects.map((e) => `${e.id} (${e.name})`).join(", ")}.` } : { type: "string", minLength: 1, description: base };
297
360
  };
@@ -322,7 +385,7 @@ function createEffectToolProvider(host) {
322
385
  const found = (await explain(async () => p.search(_nullishCoalesce(args.query, () => ( "")), { kind: args.kind, category: args.category, use: args.use, tags }))).filter((e) => hasEffectTags(e, tags));
323
386
  const limit = _nullishCoalesce(args.limit, () => ( 20));
324
387
  const out = { available: true, provider: { id: p.id, name: p.name, capabilities: p.capabilities }, effects: found.slice(0, limit).map(summaryOut), total: found.length, tags: countEffectTags(found).slice(0, TAG_LIMIT) };
325
- if (_optionalChain([tags, 'optionalAccess', _8 => _8.length]) && !found.length) {
388
+ if (_optionalChain([tags, 'optionalAccess', _10 => _10.length]) && !found.length) {
326
389
  const known = countEffectTags(await explain(async () => p.list()));
327
390
  const have = new Set(known.map((k) => k.tag));
328
391
  const unknown = tags.filter((t) => !have.has(normaliseEffectTag(t)));
@@ -437,16 +500,16 @@ function createEffectToolProvider(host) {
437
500
  ...host.description ? { description: host.description } : {},
438
501
  ...host.skill ? { skill: host.skill } : {},
439
502
  tools: () => {
440
- const extra = _nullishCoalesce(_optionalChain([host, 'access', _9 => _9.extraTools, 'optionalCall', _10 => _10(context)]), () => ( []));
441
- if (host.readOnlyReason()) return [...readTools(), ...extra.filter((t) => _optionalChain([t, 'access', _11 => _11.annotations, 'optionalAccess', _12 => _12.readOnlyHint]))];
503
+ const extra = _nullishCoalesce(_optionalChain([host, 'access', _11 => _11.extraTools, 'optionalCall', _12 => _12(context)]), () => ( []));
504
+ if (host.readOnlyReason()) return [...readTools(), ...extra.filter((t) => _optionalChain([t, 'access', _13 => _13.annotations, 'optionalAccess', _14 => _14.readOnlyHint]))];
442
505
  return [...readTools(), ...writeTools(), ...extra];
443
506
  },
444
507
  subscribe: (l) => {
445
508
  listeners.add(l);
446
- const off = _optionalChain([host, 'access', _13 => _13.subscribe, 'optionalCall', _14 => _14(l)]);
509
+ const off = _optionalChain([host, 'access', _15 => _15.subscribe, 'optionalCall', _16 => _16(l)]);
447
510
  return () => {
448
511
  listeners.delete(l);
449
- _optionalChain([off, 'optionalCall', _15 => _15()]);
512
+ _optionalChain([off, 'optionalCall', _17 => _17()]);
450
513
  };
451
514
  }
452
515
  };
@@ -482,4 +545,12 @@ function createEffectToolProvider(host) {
482
545
 
483
546
 
484
547
 
485
- exports.EFFECT_ERROR_CODES = EFFECT_ERROR_CODES; exports.EffectError = EffectError; exports.UnknownEffectError = UnknownEffectError; exports.EffectControlError = EffectControlError; exports.EffectUnsupportedError = EffectUnsupportedError; exports.EffectDisposedError = EffectDisposedError; exports.NoEffectsProviderError = NoEffectsProviderError; exports.isEffectError = isEffectError; exports.effectValueErrors = effectValueErrors; exports.resolveEffectValues = resolveEffectValues; exports.effectOffered = effectOffered; exports.normaliseEffectTag = normaliseEffectTag; exports.hasEffectTags = hasEffectTags; exports.countEffectTags = countEffectTags; exports.searchEffectSummaries = searchEffectSummaries; exports.createEffectPixels = createEffectPixels; exports.isEffectPixels = isEffectPixels; exports.srgbToLinear = srgbToLinear; exports.linearToSrgb = linearToSrgb; exports.encodeEffectFloat = encodeEffectFloat; exports.applyEffectMask = applyEffectMask; exports.EffectsSlot = EffectsSlot; exports.isCameraView = isCameraView; exports.sampleCameraViews = sampleCameraViews; exports.sampleEffectCameraMove = sampleEffectCameraMove; exports.EFFECT_KINDS = EFFECT_KINDS; exports.EFFECT_USES = EFFECT_USES; exports.CAMERA_MOVE_ROLES = CAMERA_MOVE_ROLES; exports.createEffectToolProvider = createEffectToolProvider;
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+ exports.EFFECT_ERROR_CODES = EFFECT_ERROR_CODES; exports.EffectError = EffectError; exports.UnknownEffectError = UnknownEffectError; exports.EffectControlError = EffectControlError; exports.EffectUnsupportedError = EffectUnsupportedError; exports.EffectDisposedError = EffectDisposedError; exports.NoEffectsProviderError = NoEffectsProviderError; exports.isEffectError = isEffectError; exports.effectValueErrors = effectValueErrors; exports.resolveEffectValues = resolveEffectValues; exports.effectOffered = effectOffered; exports.normaliseEffectTag = normaliseEffectTag; exports.hasEffectTags = hasEffectTags; exports.countEffectTags = countEffectTags; exports.searchEffectSummaries = searchEffectSummaries; exports.createEffectPixels = createEffectPixels; exports.isEffectPixels = isEffectPixels; exports.srgbToLinear = srgbToLinear; exports.linearToSrgb = linearToSrgb; exports.encodeEffectFloat = encodeEffectFloat; exports.applyEffectMask = applyEffectMask; exports.EffectsSlot = EffectsSlot; exports.isCameraView = isCameraView; exports.sampleCameraViews = sampleCameraViews; exports.sampleEffectCameraMove = sampleEffectCameraMove; exports.cameraMoveField = cameraMoveField; exports.cameraMovesFor = cameraMovesFor; exports.cameraMoveIdList = cameraMoveIdList; exports.cameraMoveParts = cameraMoveParts; exports.CAMERA_MOVE_MAX_MS = CAMERA_MOVE_MAX_MS; exports.resolveCameraMoveSpec = resolveCameraMoveSpec; exports.cameraViewOfBox = cameraViewOfBox; exports.cameraBoxOfView = cameraBoxOfView; exports.EFFECT_KINDS = EFFECT_KINDS; exports.EFFECT_USES = EFFECT_USES; exports.CAMERA_MOVE_ROLES = CAMERA_MOVE_ROLES; exports.createEffectToolProvider = createEffectToolProvider;
@@ -3,7 +3,7 @@ import {
3
3
  EffectDisposedError,
4
4
  EffectUnsupportedError,
5
5
  effectValueErrors
6
- } from "./chunk-UGYUGZE2.js";
6
+ } from "./chunk-TCZ2J7PR.js";
7
7
  import {
8
8
  HistoryManager
9
9
  } from "./chunk-RNSANXPT.js";
@@ -209,6 +209,69 @@ async function sampleEffectCameraMove(provider, id, request) {
209
209
  const { from, to, ms, stage, values } = request;
210
210
  return sampleCameraViews((u) => provider.cameraView(id, { from, to, u, ms, stage }, values), { ms, fps: request.fps, cut: d.camera.cut });
211
211
  }
212
+ var cameraMoveField = (role) => role === "transition" ? "in" : "during";
213
+ function cameraMovesFor(catalog, role) {
214
+ return catalog.filter((e) => e.kind === "camera" && e.camera?.role === role);
215
+ }
216
+ function cameraMoveIdList(catalog, role) {
217
+ const ids = cameraMovesFor(catalog, role).map((e) => JSON.stringify(e.id));
218
+ return ids.length ? ids.join(", ") : "none (the provider has no camera moves of that role)";
219
+ }
220
+ function cameraMoveParts(spec) {
221
+ if (typeof spec === "string") return spec ? { move: spec } : void 0;
222
+ if (spec && typeof spec === "object" && !Array.isArray(spec) && typeof spec.move === "string") return spec;
223
+ return void 0;
224
+ }
225
+ var CAMERA_MOVE_MAX_MS = 6e4;
226
+ async function resolveCameraMoveSpec(provider, spec, role) {
227
+ const field = cameraMoveField(role);
228
+ if (!provider.capabilities.supportsCamera || !provider.cameraView) throw new EffectUnsupportedError(`${provider.name} has no camera moves (capabilities.supportsCamera is not set), so camera "${field}" cannot be set.`);
229
+ const parts = cameraMoveParts(spec);
230
+ const catalog = await provider.list({ kind: "camera" });
231
+ if (!parts) throw new EffectUnsupportedError(`Camera "${field}" is a camera move's id, or { move, ms?, preset?, values? }; it takes one of ${cameraMoveIdList(catalog, role)}.`);
232
+ let description;
233
+ try {
234
+ description = await provider.describe(parts.move);
235
+ } catch (error) {
236
+ if (error instanceof UnknownEffectError || error.code === "unknown_effect")
237
+ throw new EffectError("unknown_effect", `There is no camera move "${parts.move}"; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`, parts.move);
238
+ throw error;
239
+ }
240
+ if (description.kind !== "camera" || !description.camera) throw new EffectUnsupportedError(`"${parts.move}" is a ${description.kind} effect, not a camera move; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`, parts.move);
241
+ if (description.camera.role !== role) {
242
+ const other = cameraMoveField(description.camera.role);
243
+ throw new EffectUnsupportedError(
244
+ `"${parts.move}" moves the camera ${description.camera.role === "hold" ? "while a shot holds" : "into a shot"}, so it goes in camera "${other}", not "${field}"; camera "${field}" takes one of ${cameraMoveIdList(catalog, role)}.`,
245
+ parts.move
246
+ );
247
+ }
248
+ if (parts.ms !== void 0) {
249
+ if (role === "hold") throw new EffectUnsupportedError(`A move while the shot holds plays across the shot's hold; set the hold's length instead of "ms".`, parts.move);
250
+ if (!(typeof parts.ms === "number" && Number.isFinite(parts.ms) && parts.ms >= 0 && parts.ms <= CAMERA_MOVE_MAX_MS))
251
+ throw new EffectUnsupportedError(`Camera "in" ms is how long the move takes, 0 to ${CAMERA_MOVE_MAX_MS} (default ${description.camera.durationMs} for "${parts.move}").`, parts.move);
252
+ }
253
+ let presetValues = {};
254
+ if (parts.preset !== void 0) {
255
+ const preset = description.presets.find((p) => p.name === parts.preset);
256
+ if (!preset) throw new EffectUnsupportedError(`"${parts.move}" has no preset ${JSON.stringify(parts.preset)}; its presets are ${description.presets.length ? description.presets.map((p) => JSON.stringify(p.name)).join(", ") : "none"}.`, parts.move);
257
+ presetValues = preset.values;
258
+ }
259
+ const values = { ...presetValues, ...parts.values ?? {} };
260
+ resolveEffectValues(description, values);
261
+ return {
262
+ spec: { move: description.id, ...parts.ms !== void 0 ? { ms: parts.ms } : {}, ...parts.preset !== void 0 ? { preset: parts.preset } : {}, ...Object.keys(values).length ? { values } : {} },
263
+ description
264
+ };
265
+ }
266
+ function cameraViewOfBox(box, stage) {
267
+ const zoom = Math.min(stage.width / box.width, stage.height / box.height);
268
+ return { zoom, scrollX: stage.width / (2 * zoom) - (box.x + box.width / 2), scrollY: stage.height / (2 * zoom) - (box.y + box.height / 2) };
269
+ }
270
+ function cameraBoxOfView(view, stage) {
271
+ const width = stage.width / view.zoom;
272
+ const height = stage.height / view.zoom;
273
+ return { x: -view.scrollX, y: -view.scrollY, width, height };
274
+ }
212
275
 
213
276
  // src/effects/types.ts
214
277
  var EFFECT_KINDS = ["shader", "vector", "motion", "camera"];
@@ -478,6 +541,14 @@ export {
478
541
  isCameraView,
479
542
  sampleCameraViews,
480
543
  sampleEffectCameraMove,
544
+ cameraMoveField,
545
+ cameraMovesFor,
546
+ cameraMoveIdList,
547
+ cameraMoveParts,
548
+ CAMERA_MOVE_MAX_MS,
549
+ resolveCameraMoveSpec,
550
+ cameraViewOfBox,
551
+ cameraBoxOfView,
481
552
  EFFECT_KINDS,
482
553
  EFFECT_USES,
483
554
  CAMERA_MOVE_ROLES,
@@ -33,7 +33,11 @@ var MOTION_ISSUE_CODES = {
33
33
  "scene-too-short": { severity: "warning", wording: "The scene ends before its target length." },
34
34
  "unknown-control-color": { severity: "warning", wording: "A control stands for a colour the scene never uses." },
35
35
  "empty-shot": { severity: "note", wording: "A shot neither moves the camera nor runs a command." },
36
- "camera-aspect": { severity: "note", wording: "A camera rectangle has a different shape from the artwork, so it is letterboxed." }
36
+ "camera-aspect": { severity: "note", wording: "A camera rectangle has a different shape from the artwork, so it is letterboxed." },
37
+ "camera-move-first-shot": { severity: "note", wording: "The first shot cuts to its framing, so the move its camera gets in with does not play." },
38
+ "camera-move-not-played": { severity: "note", wording: "A shot names a camera move, but there is no effects provider with camera moves to play it, so the camera eases instead." },
39
+ "camera-move-unknown": { severity: "error", wording: "A shot names a camera move the effects provider does not have, or one of the wrong role." },
40
+ "camera-move-values": { severity: "error", wording: "A camera move's preset or values do not fit its controls." }
37
41
  };
38
42
  function motionIssue(code, message, extra = {}) {
39
43
  return { code, severity: MOTION_ISSUE_CODES[code].severity, message, ...extra };
@@ -3,7 +3,7 @@
3
3
  * and a provider slot editors hold.
4
4
  */
5
5
  import { type SchemaValidationError } from '../tools/schema.cjs';
6
- import type { CameraMoveSample, CameraMoveSampleRequest, CameraView, EffectDescription, EffectImageSource, EffectPixels, EffectProvider, EffectSearchOptions, EffectSummary, EffectUse, EffectValues } from './types.cjs';
6
+ import type { CameraMoveRole, CameraMoveSpec, CameraMoveSample, CameraMoveSampleRequest, CameraStage, CameraView, EffectDescription, EffectImageSource, EffectPixels, EffectProvider, EffectSearchOptions, EffectSummary, EffectUse, EffectValues } from './types.cjs';
7
7
  /** Problems with `values` against an effect's control schema (unknown controls, types, ranges). Partial values are fine. */
8
8
  export declare function effectValueErrors(description: Pick<EffectDescription, 'controls'>, values: unknown): SchemaValidationError[];
9
9
  /**
@@ -82,3 +82,37 @@ export declare function sampleCameraViews(view: (u: number) => CameraView, optio
82
82
  * `EffectUnsupportedError` when the provider has no camera support.
83
83
  */
84
84
  export declare function sampleEffectCameraMove(provider: EffectProvider, id: string, request: CameraMoveSampleRequest): Promise<CameraMoveSample>;
85
+ /** The field a shot names a move of `role` in: `in` for a transition, `during` for a hold. */
86
+ export declare const cameraMoveField: (role: CameraMoveRole) => "in" | "during";
87
+ /** The camera moves of `role` in a catalog, in its order. */
88
+ export declare function cameraMovesFor<T extends Pick<EffectSummary, 'kind' | 'camera'>>(catalog: readonly T[], role: CameraMoveRole): T[];
89
+ /** The ids of a catalog's camera moves of `role` as a sentence's list: `"a", "b"` (or `none`). */
90
+ export declare function cameraMoveIdList(catalog: readonly Pick<EffectSummary, 'id' | 'kind' | 'camera'>[], role: CameraMoveRole): string;
91
+ /** A camera move spec as its parts (`"id"` → `{ move: "id" }`); undefined when it is neither form. */
92
+ export declare function cameraMoveParts(spec: unknown): Exclude<CameraMoveSpec, string> | undefined;
93
+ /** Longest `ms` a transition move takes (ms). */
94
+ export declare const CAMERA_MOVE_MAX_MS = 60000;
95
+ /**
96
+ * A camera move spec checked against a provider for a role, with its preset's values written out
97
+ * into `values`, so a document plays it without asking the provider for the preset again.
98
+ * Throws an error that says what to do: an unknown id or a move of the other role names the
99
+ * moves the role takes, an unknown preset names the presets, and bad values name the controls.
100
+ */
101
+ export declare function resolveCameraMoveSpec(provider: EffectProvider, spec: CameraMoveSpec, role: CameraMoveRole): Promise<{
102
+ spec: Exclude<CameraMoveSpec, string>;
103
+ description: EffectDescription;
104
+ }>;
105
+ /** A box of the scene, in its units. */
106
+ export interface CameraBox {
107
+ x: number;
108
+ y: number;
109
+ width: number;
110
+ height: number;
111
+ }
112
+ /**
113
+ * The view that shows `box` on `stage`: the box's centre in the middle, at the zoom that fits it
114
+ * whole (as SVG's `xMidYMid meet`).
115
+ */
116
+ export declare function cameraViewOfBox(box: CameraBox, stage: CameraStage): CameraView;
117
+ /** The box of the scene a view shows on `stage` (its tilt, turn, roll and blur aside). */
118
+ export declare function cameraBoxOfView(view: CameraView, stage: CameraStage): CameraBox;
@@ -3,7 +3,7 @@
3
3
  * and a provider slot editors hold.
4
4
  */
5
5
  import { type SchemaValidationError } from '../tools/schema.js';
6
- import type { CameraMoveSample, CameraMoveSampleRequest, CameraView, EffectDescription, EffectImageSource, EffectPixels, EffectProvider, EffectSearchOptions, EffectSummary, EffectUse, EffectValues } from './types.js';
6
+ import type { CameraMoveRole, CameraMoveSpec, CameraMoveSample, CameraMoveSampleRequest, CameraStage, CameraView, EffectDescription, EffectImageSource, EffectPixels, EffectProvider, EffectSearchOptions, EffectSummary, EffectUse, EffectValues } from './types.js';
7
7
  /** Problems with `values` against an effect's control schema (unknown controls, types, ranges). Partial values are fine. */
8
8
  export declare function effectValueErrors(description: Pick<EffectDescription, 'controls'>, values: unknown): SchemaValidationError[];
9
9
  /**
@@ -82,3 +82,37 @@ export declare function sampleCameraViews(view: (u: number) => CameraView, optio
82
82
  * `EffectUnsupportedError` when the provider has no camera support.
83
83
  */
84
84
  export declare function sampleEffectCameraMove(provider: EffectProvider, id: string, request: CameraMoveSampleRequest): Promise<CameraMoveSample>;
85
+ /** The field a shot names a move of `role` in: `in` for a transition, `during` for a hold. */
86
+ export declare const cameraMoveField: (role: CameraMoveRole) => "in" | "during";
87
+ /** The camera moves of `role` in a catalog, in its order. */
88
+ export declare function cameraMovesFor<T extends Pick<EffectSummary, 'kind' | 'camera'>>(catalog: readonly T[], role: CameraMoveRole): T[];
89
+ /** The ids of a catalog's camera moves of `role` as a sentence's list: `"a", "b"` (or `none`). */
90
+ export declare function cameraMoveIdList(catalog: readonly Pick<EffectSummary, 'id' | 'kind' | 'camera'>[], role: CameraMoveRole): string;
91
+ /** A camera move spec as its parts (`"id"` → `{ move: "id" }`); undefined when it is neither form. */
92
+ export declare function cameraMoveParts(spec: unknown): Exclude<CameraMoveSpec, string> | undefined;
93
+ /** Longest `ms` a transition move takes (ms). */
94
+ export declare const CAMERA_MOVE_MAX_MS = 60000;
95
+ /**
96
+ * A camera move spec checked against a provider for a role, with its preset's values written out
97
+ * into `values`, so a document plays it without asking the provider for the preset again.
98
+ * Throws an error that says what to do: an unknown id or a move of the other role names the
99
+ * moves the role takes, an unknown preset names the presets, and bad values name the controls.
100
+ */
101
+ export declare function resolveCameraMoveSpec(provider: EffectProvider, spec: CameraMoveSpec, role: CameraMoveRole): Promise<{
102
+ spec: Exclude<CameraMoveSpec, string>;
103
+ description: EffectDescription;
104
+ }>;
105
+ /** A box of the scene, in its units. */
106
+ export interface CameraBox {
107
+ x: number;
108
+ y: number;
109
+ width: number;
110
+ height: number;
111
+ }
112
+ /**
113
+ * The view that shows `box` on `stage`: the box's centre in the middle, at the zoom that fits it
114
+ * whole (as SVG's `xMidYMid meet`).
115
+ */
116
+ export declare function cameraViewOfBox(box: CameraBox, stage: CameraStage): CameraView;
117
+ /** The box of the scene a view shows on `stage` (its tilt, turn, roll and blur aside). */
118
+ export declare function cameraBoxOfView(view: CameraView, stage: CameraStage): CameraBox;