flomotion 0.2.0 → 0.4.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 (129) hide show
  1. package/CHANGELOG.md +58 -2
  2. package/LICENSE +1 -1
  3. package/README.md +29 -20
  4. package/dist/bin.mjs +6279 -2582
  5. package/dist/chunks/{chunk-QG2MOGKO.mjs → chunk-IGG2VZB6.mjs} +178 -14
  6. package/dist/chunks/{chunk-AVP5XX4G.mjs → chunk-PEC2UVQY.mjs} +138 -108
  7. package/dist/chunks/{chunk-IUSYVGP6.mjs → chunk-TTHAZGRG.mjs} +7 -7
  8. package/dist/chunks/{chunk-JCLRAREG.mjs → chunk-XWY6CUY6.mjs} +16 -16
  9. package/dist/chunks/{lock-MLQUU7X3.mjs → lock-WGPR7CJ2.mjs} +3 -3
  10. package/dist/components.mjs +19 -13
  11. package/dist/core.mjs +12 -12
  12. package/dist/hooks.mjs +8 -12
  13. package/dist/jsx-dev-runtime.mjs +1 -1
  14. package/dist/jsx-runtime.mjs +1 -1
  15. package/docs/components/Adjustment.md +2 -2
  16. package/docs/components/Audio.md +2 -2
  17. package/docs/components/B.md +3 -3
  18. package/docs/components/Captions.md +2 -2
  19. package/docs/components/Card.md +2 -2
  20. package/docs/components/Center.md +2 -2
  21. package/docs/components/Chart.md +2 -2
  22. package/docs/components/Chip.md +2 -2
  23. package/docs/components/Circle.md +2 -2
  24. package/docs/components/Clip.md +2 -2
  25. package/docs/components/CodeBlock.md +2 -2
  26. package/docs/components/Composition.md +2 -2
  27. package/docs/components/Counter.md +2 -2
  28. package/docs/components/Cursor.md +2 -2
  29. package/docs/components/Fonts.md +2 -2
  30. package/docs/components/GlassCard.md +2 -2
  31. package/docs/components/Grid.md +2 -2
  32. package/docs/components/Group.md +2 -2
  33. package/docs/components/Highlight.md +3 -3
  34. package/docs/components/I.md +3 -3
  35. package/docs/components/Image.md +2 -2
  36. package/docs/components/Line.md +2 -2
  37. package/docs/components/Marker.md +2 -2
  38. package/docs/components/Path.md +2 -2
  39. package/docs/components/Polygon.md +2 -2
  40. package/docs/components/Precomp.md +2 -2
  41. package/docs/components/ProgressRing.md +2 -2
  42. package/docs/components/Rect.md +2 -2
  43. package/docs/components/RoundRect.md +2 -2
  44. package/docs/components/SafeArea.md +2 -2
  45. package/docs/components/Scene.md +2 -2
  46. package/docs/components/Sequence.md +2 -2
  47. package/docs/components/Span.md +3 -3
  48. package/docs/components/SplitText.md +2 -2
  49. package/docs/components/Stack.md +2 -2
  50. package/docs/components/Stagger.md +2 -2
  51. package/docs/components/Strike.md +3 -3
  52. package/docs/components/Svg.md +2 -2
  53. package/docs/components/Text.md +2 -2
  54. package/docs/components/Title.md +2 -2
  55. package/docs/components/Track.md +2 -2
  56. package/docs/components/UIMock.md +2 -2
  57. package/docs/components/Underline.md +3 -3
  58. package/docs/components/Video.md +2 -2
  59. package/docs/gate2-manual-checklist.md +10 -9
  60. package/docs/hyperframes-notes.md +20 -20
  61. package/docs/later.md +23 -16
  62. package/docs/spec.md +83 -22
  63. package/package.json +1 -2
  64. package/skills/flomotion-studio/CHANGELOG.md +39 -0
  65. package/skills/flomotion-studio/README.md +81 -0
  66. package/skills/flomotion-studio/SKILL.md +90 -0
  67. package/skills/flomotion-studio/config/thresholds.md +191 -0
  68. package/skills/flomotion-studio/dataset/annotations/ansarada.md +53 -0
  69. package/skills/flomotion-studio/dataset/annotations/canva.md +49 -0
  70. package/skills/flomotion-studio/dataset/annotations/clickup.md +60 -0
  71. package/skills/flomotion-studio/dataset/annotations/gemini-stub.md +39 -0
  72. package/skills/flomotion-studio/dataset/annotations/monday.md +51 -0
  73. package/skills/flomotion-studio/dataset/annotations/phantom.md +53 -0
  74. package/skills/flomotion-studio/dataset/annotations/slack.md +54 -0
  75. package/skills/flomotion-studio/dataset/annotations/unknown-7.md +39 -0
  76. package/skills/flomotion-studio/dataset/annotations/vaylens.md +53 -0
  77. package/skills/flomotion-studio/dataset/brief-template.md +110 -0
  78. package/skills/flomotion-studio/dataset/rating-sheet.md +28 -0
  79. package/skills/flomotion-studio/dataset/schema.md +44 -0
  80. package/skills/flomotion-studio/evals/README.md +33 -0
  81. package/skills/flomotion-studio/evals/briefs/briefs.md +25 -0
  82. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/kinetic.scene.tsx +1 -1
  83. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/minimal.scene.tsx +1 -1
  84. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/sketch.scene.tsx +1 -1
  85. package/skills/flomotion-studio/examples/flomotion-ad/LOG.md +39 -0
  86. package/skills/flomotion-studio/examples/flomotion-ad/brief.md +41 -0
  87. package/skills/flomotion-studio/examples/flomotion-ad/ideas.md +12 -0
  88. package/skills/flomotion-studio/examples/flomotion-ad/project.tsx +1694 -0
  89. package/skills/flomotion-studio/examples/flomotion-ad/script.md +28 -0
  90. package/skills/flomotion-studio/examples/flomotion-ad/storyboard.md +93 -0
  91. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/README.md +1 -1
  92. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/make-assets.sh +1 -1
  93. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/project.tsx +3 -3
  94. package/skills/flomotion-studio/looks/bold-kinetic.md +122 -0
  95. package/skills/flomotion-studio/looks/clean-light.md +122 -0
  96. package/skills/flomotion-studio/looks/dark-product.md +120 -0
  97. package/skills/flomotion-studio/references/anti-patterns.md +36 -0
  98. package/skills/flomotion-studio/references/assets.md +42 -0
  99. package/skills/flomotion-studio/references/block-recipes.md +249 -0
  100. package/skills/flomotion-studio/references/blocks.md +114 -0
  101. package/skills/flomotion-studio/references/catalogue.md +53 -0
  102. package/skills/flomotion-studio/references/checks.md +87 -0
  103. package/skills/flomotion-studio/references/clean-styles.md +56 -0
  104. package/skills/{motion-studio → flomotion-studio}/references/components.md +94 -94
  105. package/skills/flomotion-studio/references/copywriting.md +64 -0
  106. package/skills/flomotion-studio/references/decision-tables.md +80 -0
  107. package/skills/flomotion-studio/references/interview.md +145 -0
  108. package/skills/flomotion-studio/references/looks.md +45 -0
  109. package/skills/flomotion-studio/references/mcp-tools.md +70 -0
  110. package/skills/flomotion-studio/references/motion.md +68 -0
  111. package/skills/flomotion-studio/references/patterns.md +45 -0
  112. package/skills/flomotion-studio/references/review.md +56 -0
  113. package/skills/flomotion-studio/references/script-craft.md +59 -0
  114. package/skills/flomotion-studio/references/sound.md +57 -0
  115. package/skills/flomotion-studio/references/story-templates.md +52 -0
  116. package/skills/flomotion-studio/references/storyboard.md +62 -0
  117. package/skills/flomotion-studio/references/styles.md +70 -0
  118. package/skills/flomotion-studio/references/transitions.md +62 -0
  119. package/skills/flomotion-studio/references/typography.md +46 -0
  120. package/skills/flomotion-studio/references/workflow.md +96 -0
  121. package/skills/motion-studio/SKILL.md +0 -87
  122. package/skills/motion-studio/looks/kinetic.json +0 -89
  123. package/skills/motion-studio/looks/minimal.json +0 -91
  124. package/skills/motion-studio/looks/sketch.json +0 -83
  125. package/skills/motion-studio/references/motion.md +0 -73
  126. package/skills/motion-studio/references/review.md +0 -32
  127. package/skills/motion-studio/references/saas-promo.md +0 -29
  128. package/skills/motion-studio/references/sound.md +0 -47
  129. package/skills/motion-studio/references/typography.md +0 -50
@@ -1,19 +1,19 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
- CodeCutError,
3
+ FlomotionError,
4
4
  __export,
5
5
  cloneNode,
6
6
  findById,
7
7
  flattenChildren,
8
8
  isNode,
9
9
  walk
10
- } from "./chunk-IUSYVGP6.mjs";
10
+ } from "./chunk-TTHAZGRG.mjs";
11
11
 
12
12
  // packages/core/src/config.ts
13
- var CODECUT_NAME = "CodeCut";
14
- var CODECUT_SCOPE = "@codecut";
15
- var CODECUT_DIR = ".codecut";
16
- var ID_PREFIX = "cc_";
13
+ var FLOMOTION_NAME = "flomotion";
14
+ var FLOMOTION_SCOPE = "@flomotion";
15
+ var FLOMOTION_DIR = ".flomotion";
16
+ var ID_PREFIX = "fm_";
17
17
 
18
18
  // packages/core/src/values/time.ts
19
19
  var round6 = (n) => Math.round(n * 1e6) / 1e6;
@@ -45,7 +45,7 @@ function parseTimeLiteral(input2, fps) {
45
45
  throw bad(input2);
46
46
  }
47
47
  function bad(input2) {
48
- return new CodeCutError("invalid_time", `Invalid time: ${JSON.stringify(input2)}`, {
48
+ return new FlomotionError("invalid_time", `Invalid time: ${JSON.stringify(input2)}`, {
49
49
  fix: 'Use seconds (1.5), "1.5s", "36f" or "00:00:01:12".'
50
50
  });
51
51
  }
@@ -89,7 +89,7 @@ function parseLength(input2) {
89
89
  if (typeof input2 === "number") return { unit: "px", value: input2 };
90
90
  const m = input2.trim().match(/^(-?\d+(?:\.\d+)?|-?\.\d+)\s*(px|%|vw|vh)?$/);
91
91
  if (!m) {
92
- throw new CodeCutError("invalid_value", `Invalid length: ${JSON.stringify(input2)}`, {
92
+ throw new FlomotionError("invalid_value", `Invalid length: ${JSON.stringify(input2)}`, {
93
93
  fix: 'Use pixels (120), "50%", "10vw" or "10vh".'
94
94
  });
95
95
  }
@@ -114,7 +114,7 @@ function parseAngle(input2) {
114
114
  if (typeof input2 === "number") return input2;
115
115
  const m = input2.trim().match(/^(-?\d+(?:\.\d+)?|-?\.\d+)\s*(deg|turn|rad|grad)?$/);
116
116
  if (!m) {
117
- throw new CodeCutError("invalid_value", `Invalid angle: ${JSON.stringify(input2)}`, {
117
+ throw new FlomotionError("invalid_value", `Invalid angle: ${JSON.stringify(input2)}`, {
118
118
  fix: 'Use degrees (45) or "0.25turn".'
119
119
  });
120
120
  }
@@ -136,7 +136,7 @@ var clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
136
136
  function parseColor(input2) {
137
137
  const s = input2.trim().toLowerCase();
138
138
  if (s.startsWith("$")) {
139
- throw new CodeCutError("invalid_value", `Unresolved color token ${input2}`, {
139
+ throw new FlomotionError("invalid_value", `Unresolved color token ${input2}`, {
140
140
  fix: "Define the token in the Theme/Look or resolve the project first."
141
141
  });
142
142
  }
@@ -188,7 +188,7 @@ var NAMED = {
188
188
  grey: "#808080"
189
189
  };
190
190
  function badColor(input2) {
191
- return new CodeCutError("invalid_value", `Invalid color: ${JSON.stringify(input2)}`, {
191
+ return new FlomotionError("invalid_value", `Invalid color: ${JSON.stringify(input2)}`, {
192
192
  fix: 'Use "#rrggbb", "rgb(...)", "oklch(L C H)" or a "$token".'
193
193
  });
194
194
  }
@@ -333,7 +333,7 @@ function parseEase(spec) {
333
333
  }
334
334
  var evalEase = (spec, p) => parseEase(spec)(clamp01(p));
335
335
  function badEase(spec) {
336
- throw new CodeCutError("invalid_value", `Unknown ease: ${JSON.stringify(spec)}`, {
336
+ throw new FlomotionError("invalid_value", `Unknown ease: ${JSON.stringify(spec)}`, {
337
337
  fix: 'Use e.g. "expo.out", "back.out(1.7)", "bezier(.2,.8,.2,1)" or "spring(180,18)".'
338
338
  });
339
339
  }
@@ -539,7 +539,7 @@ function normalizeTrack(raw, opts) {
539
539
  keys.sort((a, b) => a.t - b.t);
540
540
  for (let i = 1; i < keys.length; i++) {
541
541
  if (keys[i].t === keys[i - 1].t) {
542
- throw new CodeCutError(
542
+ throw new FlomotionError(
543
543
  "duplicate_keyframe",
544
544
  `Two keyframes share time ${keys[i].t}s on one property`,
545
545
  { fix: "Give each keyframe on a property a unique time (move one by at least one frame)." }
@@ -653,7 +653,7 @@ function numSlopes(track, comp, mode) {
653
653
  }
654
654
  function evalNumber(track, tIn) {
655
655
  const ks = track.keys;
656
- if (ks.length === 0) throw new CodeCutError("invalid_value", "Keyframe track has no keys");
656
+ if (ks.length === 0) throw new FlomotionError("invalid_value", "Keyframe track has no keys");
657
657
  const t = loopTime(track, tIn);
658
658
  if (t <= ks[0].t || ks.length === 1) return ks[0].v;
659
659
  const last = ks[ks.length - 1];
@@ -673,7 +673,7 @@ function evalNumber(track, tIn) {
673
673
  }
674
674
  function evalVec(track, tIn) {
675
675
  const ks = track.keys;
676
- if (ks.length === 0) throw new CodeCutError("invalid_value", "Keyframe track has no keys");
676
+ if (ks.length === 0) throw new FlomotionError("invalid_value", "Keyframe track has no keys");
677
677
  const t = loopTime(track, tIn);
678
678
  if (t <= ks[0].t || ks.length === 1) return [...ks[0].v];
679
679
  const last = ks[ks.length - 1];
@@ -752,7 +752,7 @@ function makeCtx(base, t, value) {
752
752
  value,
753
753
  prop: (ref2) => {
754
754
  if (!base.prop) {
755
- throw new CodeCutError(
755
+ throw new FlomotionError(
756
756
  "unresolved_ref",
757
757
  `ctx.prop(${JSON.stringify(ref2)}) is not available here`
758
758
  );
@@ -762,12 +762,12 @@ function makeCtx(base, t, value) {
762
762
  noise: (seed = 1, freq = 1) => noise1D(t * freq, seed),
763
763
  beat: (n) => {
764
764
  if (!base.beat)
765
- throw new CodeCutError("unresolved_ref", "ctx.beat needs a tempo or beat map");
765
+ throw new FlomotionError("unresolved_ref", "ctx.beat needs a tempo or beat map");
766
766
  return base.beat(n);
767
767
  },
768
768
  word: (voiceId, i) => {
769
769
  if (!base.word)
770
- throw new CodeCutError("unresolved_ref", "ctx.word needs a Voiceover with timings");
770
+ throw new FlomotionError("unresolved_ref", "ctx.word needs a Voiceover with timings");
771
771
  return base.word(voiceId, i);
772
772
  },
773
773
  lerp,
@@ -20973,7 +20973,7 @@ function group(fields, o = {}) {
20973
20973
  function parseControlValue(c, v, name = "value") {
20974
20974
  const r = c.prop.safeParse(v);
20975
20975
  if (!r.success) {
20976
- throw new CodeCutError(
20976
+ throw new FlomotionError(
20977
20977
  "schema_violation",
20978
20978
  `${name}: ${r.error.issues.map((i) => i.message).join("; ")}`
20979
20979
  );
@@ -21022,7 +21022,7 @@ var BLEND_MODES = [
21022
21022
  "add"
21023
21023
  ];
21024
21024
  var timingControls = () => ({
21025
- id: text({ label: "Id", description: "Stable unique id. Written back as cc_\u2026 when missing." }),
21025
+ id: text({ label: "Id", description: "Stable unique id. Written back as fm_\u2026 when missing." }),
21026
21026
  label: text({ label: "Label" }),
21027
21027
  start: time3({
21028
21028
  label: "Start",
@@ -21144,10 +21144,10 @@ function zodShape(controls, form) {
21144
21144
  }
21145
21145
  function makeDef(kind, name, base) {
21146
21146
  if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) {
21147
- throw new CodeCutError("schema_violation", `Component name "${name}" must be PascalCase`);
21147
+ throw new FlomotionError("schema_violation", `Component name "${name}" must be PascalCase`);
21148
21148
  }
21149
21149
  if (!base.own || typeof base.own !== "object") {
21150
- throw new CodeCutError(
21150
+ throw new FlomotionError(
21151
21151
  "schema_violation",
21152
21152
  `${name}: components without a schema are rejected`,
21153
21153
  {
@@ -21159,7 +21159,7 @@ function makeDef(kind, name, base) {
21159
21159
  if (!controls.id)
21160
21160
  controls.id = text({
21161
21161
  label: "Id",
21162
- description: "Stable unique id. Written back as cc_\u2026 when missing."
21162
+ description: "Stable unique id. Written back as fm_\u2026 when missing."
21163
21163
  });
21164
21164
  const def = {
21165
21165
  kind,
@@ -21233,7 +21233,7 @@ function defineEffect(name, spec) {
21233
21233
  });
21234
21234
  return makeTag(def);
21235
21235
  }
21236
- var Fragment = /* @__PURE__ */ Symbol.for("codecut.fragment");
21236
+ var Fragment = /* @__PURE__ */ Symbol.for("flomotion.fragment");
21237
21237
  function lev(a, b) {
21238
21238
  const d = Array.from({ length: a.length + 1 }, (_, i) => [
21239
21239
  i,
@@ -21321,7 +21321,7 @@ function assertProps(def, props, id) {
21321
21321
  const issues = validateProps(def, props);
21322
21322
  if (issues.length) {
21323
21323
  const head = issues[0];
21324
- throw new CodeCutError("schema_violation", `${id ? `#${id} ` : ""}${head.message}`, {
21324
+ throw new FlomotionError("schema_violation", `${id ? `#${id} ` : ""}${head.message}`, {
21325
21325
  fix: head.fix,
21326
21326
  details: issues
21327
21327
  });
@@ -21380,7 +21380,7 @@ function mcpToolSchemas(reg) {
21380
21380
  type: { type: "string", enum: comps.map((d) => d.name) },
21381
21381
  props: {
21382
21382
  type: "object",
21383
- description: "Validated against the component schema (see codecut://schema/{component})."
21383
+ description: "Validated against the component schema (see flomotion://schema/{component})."
21384
21384
  },
21385
21385
  at: { type: "integer", description: "Child index to insert at (default: append)." }
21386
21386
  },
@@ -21613,7 +21613,7 @@ var transition = () => group(
21613
21613
  }
21614
21614
  );
21615
21615
  var ident = () => ({
21616
- id: text({ label: "Id", description: "Stable unique id. Written back as cc_\u2026 when missing." })
21616
+ id: text({ label: "Id", description: "Stable unique id. Written back as fm_\u2026 when missing." })
21617
21617
  });
21618
21618
  var Composition = defineComponent("Composition", {
21619
21619
  category: "structure",
@@ -21833,7 +21833,7 @@ var err = (env, i) => env.issues.push(i);
21833
21833
  function resolveProject(source, opts = {}) {
21834
21834
  const reg = opts.registry ?? registry2;
21835
21835
  if (source.name !== "Composition") {
21836
- throw new CodeCutError(
21836
+ throw new FlomotionError(
21837
21837
  "schema_violation",
21838
21838
  `Project root must be <Composition>, got <${source.name}>`,
21839
21839
  {
@@ -21885,7 +21885,7 @@ function resolveProject(source, opts = {}) {
21885
21885
  function build3(env, node2, parent, depth, generatedIds) {
21886
21886
  const def = env.reg.get(node2.name);
21887
21887
  if (!def) {
21888
- throw new CodeCutError("unknown_component", `Unknown component <${node2.name}>`, {
21888
+ throw new FlomotionError("unknown_component", `Unknown component <${node2.name}>`, {
21889
21889
  fix: `Known: ${env.reg.names().slice(0, 40).join(", ")}\u2026`
21890
21890
  });
21891
21891
  }
@@ -22150,7 +22150,7 @@ var timed = /* @__PURE__ */ new WeakSet();
22150
22150
  function timeNode(env, n, visiting) {
22151
22151
  if (timed.has(n)) return;
22152
22152
  if (visiting.has(n.id)) {
22153
- throw new CodeCutError("unresolved_ref", `Timing reference cycle through #${n.id}`, {
22153
+ throw new FlomotionError("unresolved_ref", `Timing reference cycle through #${n.id}`, {
22154
22154
  fix: "Break the cycle: a start/end cannot depend on itself."
22155
22155
  });
22156
22156
  }
@@ -22314,7 +22314,7 @@ function resolveProps(env, n) {
22314
22314
  const words = env.opts.words?.(voice);
22315
22315
  const w = words?.[i];
22316
22316
  if (!w)
22317
- throw new CodeCutError(
22317
+ throw new FlomotionError(
22318
22318
  "unresolved_ref",
22319
22319
  `ctx.word(${JSON.stringify(voice)}, ${i}) has no timing`,
22320
22320
  { fix: "Run transcribe for this voice first." }
@@ -22474,7 +22474,7 @@ function resolveKeyTime(env, n, t) {
22474
22474
  case "marker": {
22475
22475
  const m = env.markers.find((x) => x.id === spec.name || x.label === spec.name);
22476
22476
  if (!m)
22477
- throw new CodeCutError("unresolved_ref", `Unknown marker "${spec.name}"`, {
22477
+ throw new FlomotionError("unresolved_ref", `Unknown marker "${spec.name}"`, {
22478
22478
  fix: "Add a <Marker label=\u2026/>."
22479
22479
  });
22480
22480
  return m.at + spec.offset - n.parentStart;
@@ -22482,7 +22482,7 @@ function resolveKeyTime(env, n, t) {
22482
22482
  case "ref": {
22483
22483
  const target = env.byId.get(spec.id);
22484
22484
  if (!target)
22485
- throw new CodeCutError("unresolved_ref", `Unknown element #${spec.id}`, {
22485
+ throw new FlomotionError("unresolved_ref", `Unknown element #${spec.id}`, {
22486
22486
  fix: "Check the id."
22487
22487
  });
22488
22488
  const v = spec.edge === "start" ? target.start : spec.edge === "end" ? target.end : target.duration;
@@ -22520,11 +22520,11 @@ function normFill(v, tok) {
22520
22520
  function readRef(env, ref2, t) {
22521
22521
  const m = ref2.match(/^#([\w-]+)\.([\w.]+)$/);
22522
22522
  if (!m)
22523
- throw new CodeCutError("unresolved_ref", `Bad ref ${JSON.stringify(ref2)}`, {
22523
+ throw new FlomotionError("unresolved_ref", `Bad ref ${JSON.stringify(ref2)}`, {
22524
22524
  fix: 'Use "#id.prop".'
22525
22525
  });
22526
22526
  const node2 = env.byId.get(m[1]);
22527
- if (!node2) throw new CodeCutError("unresolved_ref", `Unknown element #${m[1]}`);
22527
+ if (!node2) throw new FlomotionError("unresolved_ref", `Unknown element #${m[1]}`);
22528
22528
  const v = node2.props[m[2]];
22529
22529
  if (v && typeof v === "object" && "kind" in v) return evalSignal(v, t);
22530
22530
  return v;
@@ -22709,7 +22709,7 @@ function transitionPlan(scene, prev, spec, comp) {
22709
22709
  const overlay = (suffix, color2, opacityAt) => {
22710
22710
  const id = `${scene.id}-${suffix}`;
22711
22711
  plan.overlays.push({
22712
- html: `<div id="${id}" class="cc-tx" style="position:absolute;inset:0;background:${color2};opacity:0;z-index:9000;pointer-events:none"></div>`,
22712
+ html: `<div id="${id}" class="fm-tx" style="position:absolute;inset:0;background:${color2};opacity:0;z-index:9000;pointer-events:none"></div>`,
22713
22713
  channels: [{ target: `#${id}`, prop: "opacity", signal: num4(opacityAt), span }]
22714
22714
  });
22715
22715
  };
@@ -23085,7 +23085,7 @@ function buildIR(project, opts = {}) {
23085
23085
  else html += kids;
23086
23086
  layer.html = html;
23087
23087
  if (n === rootNode) {
23088
- return `<div id="${n.id}-xf" class="cc-xf" style="position:absolute;inset:0">${layer.html}${layer.overlays.join("")}</div>`;
23088
+ return `<div id="${n.id}-xf" class="fm-xf" style="position:absolute;inset:0">${layer.html}${layer.overlays.join("")}</div>`;
23089
23089
  }
23090
23090
  return hostHtml(layer, n);
23091
23091
  };
@@ -23306,21 +23306,21 @@ function hostHtml(layer, node2) {
23306
23306
  const host = styleAttr(
23307
23307
  layer.inFlow ? { position: "relative", "z-index": String(z2), ...layer.hostStyle } : { position: "absolute", inset: "0", "z-index": String(z2), ...layer.hostStyle }
23308
23308
  );
23309
- const attrs = `id="${node2.id}" class="clip cc-l cc-${node2.name.toLowerCase()}" data-start="${layer.start}" data-duration="${Math.round(dur * 1e6) / 1e6}"${layer.trackIndex !== void 0 ? ` data-track-index="${layer.trackIndex}"` : ""} data-cc="${node2.name}"`;
23309
+ const attrs = `id="${node2.id}" class="clip fm-l fm-${node2.name.toLowerCase()}" data-start="${layer.start}" data-duration="${Math.round(dur * 1e6) / 1e6}"${layer.trackIndex !== void 0 ? ` data-track-index="${layer.trackIndex}"` : ""} data-cc="${node2.name}"`;
23310
23310
  if (!layer.visual) {
23311
23311
  return `<div ${attrs} style="${host}">${layer.html}${layer.overlays.join("")}</div>`;
23312
23312
  }
23313
23313
  const xfBase = layer.inFlow ? { position: "relative" } : layer.xfStyle["left"] || layer.xfStyle["top"] || layer.xfStyle["width"] ? { position: "absolute" } : { position: "absolute", inset: "0" };
23314
23314
  const xf = styleAttr({ ...xfBase, ...layer.xfStyle });
23315
- return `<div ${attrs} style="${host}"><div id="${node2.id}-xf" class="cc-xf" style="${xf}">${layer.html}${layer.overlays.join("")}</div></div>`;
23315
+ return `<div ${attrs} style="${host}"><div id="${node2.id}-xf" class="fm-xf" style="${xf}">${layer.html}${layer.overlays.join("")}</div></div>`;
23316
23316
  }
23317
23317
 
23318
23318
  // packages/core/src/compile/html.ts
23319
23319
  var BASE_CSS = `*{margin:0;padding:0;box-sizing:border-box}
23320
23320
  html,body{margin:0;overflow:hidden}
23321
- .cc-l{pointer-events:none}
23322
- .cc-xf{will-change:auto}
23323
- .cc-xf>*{max-width:none}`;
23321
+ .fm-l{pointer-events:none}
23322
+ .fm-xf{will-change:auto}
23323
+ .fm-xf>*{max-width:none}`;
23324
23324
  function fontFaceCss(fonts) {
23325
23325
  const rules = [];
23326
23326
  for (const f of fonts) {
@@ -23353,7 +23353,7 @@ function walkAll(layer, fn) {
23353
23353
  layer.children.forEach((c) => walkAll(c, fn));
23354
23354
  }
23355
23355
  var RUNTIME = `(function(){
23356
- var G=window.gsap, S=window.__ccStatic||[], B=window.__ccBaked||[], D=window.__ccDur||1, els={};
23356
+ var G=window.gsap, S=window.__fmStatic||[], B=window.__fmBaked||[], D=window.__fmDur||1, els={};
23357
23357
  function el(sel){return els[sel]||(els[sel]=document.querySelector(sel));}
23358
23358
  function put(target,props){var e=el(target); if(!e)return; if(props.__text!==undefined){e.textContent=props.__text; delete props.__text;} var at=props.__attr; if(at){for(var k in at)e.setAttribute(k,at[k]); delete props.__attr;} if(Object.keys(props).length)G.set(e,props);}
23359
23359
  function groupBy(list){var m={};list.forEach(function(c){(m[c[0]]=m[c[0]]||[]).push(c);});return m;}
@@ -23381,9 +23381,9 @@ var RUNTIME = `(function(){
23381
23381
  var tl=G.timeline({paused:true});
23382
23382
  tl.to(proxy,{t:D,duration:D,ease:"none",onUpdate:function(){renderAt(proxy.t);}},0);
23383
23383
  renderAt(0);
23384
- window.__ccRenderAt=renderAt;
23384
+ window.__fmRenderAt=renderAt;
23385
23385
  window.__timelines=window.__timelines||{};
23386
- window.__timelines[window.__ccId]=tl;
23386
+ window.__timelines[window.__fmId]=tl;
23387
23387
  tl.seek(0);
23388
23388
  })();`;
23389
23389
  function compileProject(project, opts = {}) {
@@ -23415,10 +23415,10 @@ function compileProject(project, opts = {}) {
23415
23415
  const bakedRows = acc.baked.map((b) => [b.target, b.prop, b.t0, b.hz, b.samples, b.unit ?? ""]);
23416
23416
  const gsap = opts.gsapPath ?? "vendor/gsap.min.js";
23417
23417
  const res = comp.width >= comp.height ? comp.width === comp.height ? "square" : "landscape" : "portrait";
23418
- const mix = opts.mix ? `<audio id="cc-mix" src="${opts.mix.src}" data-start="0" data-duration="${numFmt(opts.mix.duration ?? comp.duration)}" data-volume="1"></audio>` : "";
23418
+ const mix = opts.mix ? `<audio id="fm-mix" src="${opts.mix.src}" data-start="0" data-duration="${numFmt(opts.mix.duration ?? comp.duration)}" data-volume="1"></audio>` : "";
23419
23419
  const defs = acc.defs.length ? `<svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs>${acc.defs.join("")}</defs></svg>` : "";
23420
23420
  const html = `<!doctype html>
23421
- <html lang="en" data-resolution="${res}" data-generator="${CODECUT_NAME}">
23421
+ <html lang="en" data-resolution="${res}" data-generator="${FLOMOTION_NAME}">
23422
23422
  <head>
23423
23423
  <meta charset="UTF-8">
23424
23424
  <meta name="viewport" content="width=${comp.width}, height=${comp.height}">
@@ -23437,10 +23437,10 @@ ${root.html}
23437
23437
  ${mix}
23438
23438
  </div>
23439
23439
  <script>
23440
- window.__ccId=${JSON.stringify(comp.id)};
23441
- window.__ccDur=${numFmt(comp.duration)};
23442
- window.__ccStatic=${JSON.stringify(staticRows)};
23443
- window.__ccBaked=${JSON.stringify(bakedRows)};
23440
+ window.__fmId=${JSON.stringify(comp.id)};
23441
+ window.__fmDur=${numFmt(comp.duration)};
23442
+ window.__fmStatic=${JSON.stringify(staticRows)};
23443
+ window.__fmBaked=${JSON.stringify(bakedRows)};
23444
23444
  </script>
23445
23445
  <script>
23446
23446
  ${RUNTIME}
@@ -23608,7 +23608,7 @@ function lintProject(project, ctx = {}) {
23608
23608
  rule: "font-no-ledger",
23609
23609
  message: `Font "${f.id}" (${f.family}) has no ledger entry`,
23610
23610
  id: f.id,
23611
- fix: "Run `codecut fonts sync`."
23611
+ fix: "Run `flomotion fonts sync`."
23612
23612
  });
23613
23613
  else {
23614
23614
  const lic = ctx.ledger.entries.find(
@@ -23630,7 +23630,7 @@ function lintProject(project, ctx = {}) {
23630
23630
  rule: "font-network-url",
23631
23631
  message: `Font "${f.id}" is loaded from a URL at render time`,
23632
23632
  id: f.id,
23633
- fix: "Run `codecut fonts sync` so the file is local."
23633
+ fix: "Run `flomotion fonts sync` so the file is local."
23634
23634
  });
23635
23635
  }
23636
23636
  for (const m of ctx.fontLockProblems?.(declIds) ?? [])
@@ -23638,7 +23638,7 @@ function lintProject(project, ctx = {}) {
23638
23638
  severity: "error",
23639
23639
  rule: "font-lock",
23640
23640
  message: m,
23641
- fix: "Run `codecut fonts sync`."
23641
+ fix: "Run `flomotion fonts sync`."
23642
23642
  });
23643
23643
  const minSize = Math.min(comp.width, comp.height) * cfg.minTextSize;
23644
23644
  const safePreset = cfg.safe ?? (comp.height > comp.width ? "reels" : "none");
@@ -23720,8 +23720,8 @@ function lintProject(project, ctx = {}) {
23720
23720
  });
23721
23721
  else if (ctx.ledger) {
23722
23722
  const e = ctx.ledger.entries.find((x) => `${x.source}:${x.id}` === src);
23723
- const family = /^CC0/i.test(e?.license ?? "") ? "CC0" : /^CC-BY(-\d|$)/i.test(e?.license ?? "") ? "CC-BY" : e?.license;
23724
- if (e && !cfg.soundLicenses.includes(family))
23723
+ const family = /^CC0/i.test(e?.license ?? "") ? "CC0" : /^CC-BY(-\d|$)/i.test(e?.license ?? "") ? "CC-BY" : e?.source === "local" || e?.source === "own" || /^(user-supplied|owned|licensed|used with permission)/i.test(e?.license ?? "") ? "own" : e?.license;
23724
+ if (e && family !== "own" && !cfg.soundLicenses.includes(family))
23725
23725
  out.push({
23726
23726
  severity: "error",
23727
23727
  rule: "license-blocked",
@@ -23742,17 +23742,42 @@ function lintProject(project, ctx = {}) {
23742
23742
  });
23743
23743
  }
23744
23744
  }
23745
- for (const n of nodes.filter((x) => ["Image", "Video", "Clip"].includes(x.name))) {
23745
+ const MANAGED = /^(\.\/)?assets\/(third-party|captures|brand|imported)\//;
23746
+ for (const n of nodes.filter((x) => ["Image", "Svg", "Video", "Clip"].includes(x.name))) {
23746
23747
  const src = String(n.raw.src ?? "");
23747
- if (src && ctx.fileExists && !ctx.fileExists(src))
23748
+ if (!src || /^data:|^</.test(src.trim())) continue;
23749
+ if (ctx.fileExists && !ctx.fileExists(src)) {
23748
23750
  out.push({
23749
23751
  severity: "error",
23750
23752
  rule: "asset-missing",
23751
23753
  message: `#${n.id}: file ${src} does not exist`,
23752
23754
  id: n.id,
23753
23755
  prop: "src",
23754
- fix: "Add the file to the project."
23756
+ fix: "Add the file to the project, or fetch it with asset_get / asset_capture / asset_import."
23755
23757
  });
23758
+ continue;
23759
+ }
23760
+ if (ctx.ledger && MANAGED.test(src)) {
23761
+ const rel = src.replace(/^\.\//, "");
23762
+ const e = ctx.ledger.entries.find((x) => x.file === rel);
23763
+ if (!e)
23764
+ out.push({
23765
+ severity: "error",
23766
+ rule: "asset-no-ledger",
23767
+ message: `#${n.id}: ${src} has no ledger entry`,
23768
+ id: n.id,
23769
+ prop: "src",
23770
+ fix: "Fetch it with asset_get, asset_capture or asset_import so its licence is recorded."
23771
+ });
23772
+ else if (!e.commercialOk)
23773
+ out.push({
23774
+ severity: "error",
23775
+ rule: "license-blocked",
23776
+ message: `#${n.id}: ${src} (${e.license}) is not cleared for commercial use`,
23777
+ id: n.id,
23778
+ fix: "Pick an asset with a licence that allows it, or get permission and re-import it."
23779
+ });
23780
+ }
23756
23781
  }
23757
23782
  return unique(out);
23758
23783
  }
@@ -23888,7 +23913,7 @@ __export(edit_exports, {
23888
23913
  function elementOrThrow(root, id) {
23889
23914
  const hit = findById(root, id);
23890
23915
  if (!hit)
23891
- throw new CodeCutError("unknown_element", `No element with id "${id}"`, {
23916
+ throw new FlomotionError("unknown_element", `No element with id "${id}"`, {
23892
23917
  fix: "Use project_read to list ids."
23893
23918
  });
23894
23919
  return hit;
@@ -23925,7 +23950,7 @@ function applyPatches(root, patches) {
23925
23950
  }
23926
23951
  case "remove": {
23927
23952
  const { node: node2, parent, index } = elementOrThrow(project, p.id);
23928
- if (!parent) throw new CodeCutError("invalid_edit", "Cannot remove the root element");
23953
+ if (!parent) throw new FlomotionError("invalid_edit", "Cannot remove the root element");
23929
23954
  parent.children.splice(index, 1);
23930
23955
  inverse.unshift({
23931
23956
  op: "insert",
@@ -23967,14 +23992,14 @@ var fmt = (t) => `${Math.round(t * 1e6) / 1e6}s`;
23967
23992
  var snap = (root, t) => snapToFrame(t, fpsOf(root));
23968
23993
  function lit(root, v, what, id) {
23969
23994
  if (v === void 0)
23970
- throw new CodeCutError("invalid_edit", `#${id} has no explicit ${what}`, {
23995
+ throw new FlomotionError("invalid_edit", `#${id} has no explicit ${what}`, {
23971
23996
  fix: `Give #${id} a literal ${what} (e.g. ${what}="2s") before editing its timing.`
23972
23997
  });
23973
23998
  try {
23974
23999
  if (typeof v === "string" && /^[@#]/.test(v)) throw new Error("reference");
23975
24000
  return parseTimeLiteral(v, fpsOf(root));
23976
24001
  } catch {
23977
- throw new CodeCutError(
24002
+ throw new FlomotionError(
23978
24003
  "opaque_expression",
23979
24004
  `#${id}.${what} is ${JSON.stringify(v)}, which is not a literal time`,
23980
24005
  { fix: "Replace the reference/expression with a literal time first." }
@@ -23988,7 +24013,7 @@ function timingOf(root, node2) {
23988
24013
  if (node2.props.duration !== void 0) duration3 = lit(root, node2.props.duration, "duration", id);
23989
24014
  else if (node2.props.end !== void 0) duration3 = lit(root, node2.props.end, "end", id) - start;
23990
24015
  else
23991
- throw new CodeCutError("invalid_edit", `#${id} has no explicit duration`, {
24016
+ throw new FlomotionError("invalid_edit", `#${id} has no explicit duration`, {
23992
24017
  fix: `Give #${id} a duration (e.g. duration="2s") before editing its timing.`
23993
24018
  });
23994
24019
  return { node: node2, id, start, duration: duration3, end: start + duration3 };
@@ -24002,7 +24027,7 @@ function itemsOf(root, container) {
24002
24027
  function trackOf(root, id) {
24003
24028
  const { node: node2 } = elementOrThrow(root, id);
24004
24029
  if (node2.name !== "Track" && node2.name !== "Scene" && node2.name !== "Composition" && node2.name !== "Group") {
24005
- throw new CodeCutError("invalid_edit", `#${id} is a ${node2.name}, not a Track`, {
24030
+ throw new FlomotionError("invalid_edit", `#${id} is a ${node2.name}, not a Track`, {
24006
24031
  fix: "Pass the id of a Track."
24007
24032
  });
24008
24033
  }
@@ -24010,14 +24035,14 @@ function trackOf(root, id) {
24010
24035
  }
24011
24036
  function assertWritable(track) {
24012
24037
  if (track.name === "Track" && track.props.locked === true) {
24013
- throw new CodeCutError("track_locked", `Track #${track.props.id} is locked`, {
24038
+ throw new FlomotionError("track_locked", `Track #${track.props.id} is locked`, {
24014
24039
  fix: `Unlock it first with edit lockTrack {track:"${track.props.id}", value:false}.`
24015
24040
  });
24016
24041
  }
24017
24042
  }
24018
24043
  function parentTrackOf(root, id) {
24019
24044
  const { parent } = elementOrThrow(root, id);
24020
- if (!parent) throw new CodeCutError("invalid_edit", "The root has no track");
24045
+ if (!parent) throw new FlomotionError("invalid_edit", "The root has no track");
24021
24046
  return parent;
24022
24047
  }
24023
24048
  function overlapCheck(items, ignore, start, end, allow) {
@@ -24025,7 +24050,7 @@ function overlapCheck(items, ignore, start, end, allow) {
24025
24050
  for (const o of items) {
24026
24051
  if (ignore.includes(o.id)) continue;
24027
24052
  if (start < o.end - 1e-9 && end > o.start + 1e-9) {
24028
- throw new CodeCutError(
24053
+ throw new FlomotionError(
24029
24054
  "overlap_rejected",
24030
24055
  `[${fmt(start)}, ${fmt(end)}) overlaps #${o.id} [${fmt(o.start)}, ${fmt(o.end)})`,
24031
24056
  { fix: "Move it, trim the neighbour, or pass overlap:true." }
@@ -24131,7 +24156,7 @@ function overwrite(root, a) {
24131
24156
  }
24132
24157
  function replace(root, a) {
24133
24158
  const { node: old, parent, index } = elementOrThrow(root, a.id);
24134
- if (!parent) throw new CodeCutError("invalid_edit", "Cannot replace the root");
24159
+ if (!parent) throw new FlomotionError("invalid_edit", "Cannot replace the root");
24135
24160
  assertWritable(parent);
24136
24161
  const node2 = cloneNode(a.node);
24137
24162
  const keep = {};
@@ -24170,7 +24195,7 @@ function extract(root, a) {
24170
24195
  assertWritable(track);
24171
24196
  const from = snap(root, lit(root, a.from, "from", a.track));
24172
24197
  const to = snap(root, lit(root, a.to, "to", a.track));
24173
- if (to <= from) throw new CodeCutError("invalid_edit", "extract needs to > from");
24198
+ if (to <= from) throw new FlomotionError("invalid_edit", "extract needs to > from");
24174
24199
  const span = to - from;
24175
24200
  const fps = fpsOf(root);
24176
24201
  const patches = [];
@@ -24216,7 +24241,7 @@ function split(root, a) {
24216
24241
  const it = timingOf(root, elementOrThrow(root, a.id).node);
24217
24242
  const at = snap(root, lit(root, a.at, "at", a.id));
24218
24243
  if (at <= it.start + 1e-9 || at >= it.end - 1e-9)
24219
- throw new CodeCutError(
24244
+ throw new FlomotionError(
24220
24245
  "invalid_edit",
24221
24246
  `split time ${fmt(at)} is outside #${a.id} (${fmt(it.start)} to ${fmt(it.end)})`
24222
24247
  );
@@ -24232,7 +24257,7 @@ function trim(root, a) {
24232
24257
  const fps = fpsOf(root);
24233
24258
  const start = a.start === void 0 ? it.start : snap(root, lit(root, a.start, "start", a.id));
24234
24259
  const end = a.end === void 0 ? it.end : snap(root, lit(root, a.end, "end", a.id));
24235
- if (end <= start) throw new CodeCutError("invalid_edit", "trim would make the clip empty");
24260
+ if (end <= start) throw new FlomotionError("invalid_edit", "trim would make the clip empty");
24236
24261
  overlapCheck(itemsOf(root, parent), [a.id], start, end, a.overlap);
24237
24262
  const patches = [setTime(a.id, "start", start), setTime(a.id, "duration", end - start)];
24238
24263
  if (it.node.props.end !== void 0) patches.push(dropProp(a.id, "end"));
@@ -24252,12 +24277,12 @@ function roll(root, a) {
24252
24277
  const A = timingOf(root, elementOrThrow(root, a.a).node);
24253
24278
  const B = timingOf(root, elementOrThrow(root, a.b).node);
24254
24279
  if (Math.abs(A.end - B.start) > 1e-6)
24255
- throw new CodeCutError("invalid_edit", `#${a.a} and #${a.b} are not adjacent`, {
24280
+ throw new FlomotionError("invalid_edit", `#${a.a} and #${a.b} are not adjacent`, {
24256
24281
  fix: "Roll needs clips that touch."
24257
24282
  });
24258
24283
  const d = snap(root, lit(root, a.delta, "delta", a.a));
24259
24284
  if (A.duration + d <= 0 || B.duration - d <= 0)
24260
- throw new CodeCutError("invalid_edit", "roll would collapse a clip");
24285
+ throw new FlomotionError("invalid_edit", "roll would collapse a clip");
24261
24286
  const fps = fpsOf(root);
24262
24287
  const patches = [
24263
24288
  setTime(a.a, "duration", A.duration + d),
@@ -24286,7 +24311,8 @@ function slide(root, a) {
24286
24311
  assertWritable(parent);
24287
24312
  const items = itemsOf(root, parent);
24288
24313
  const i = items.findIndex((x) => x.id === a.id);
24289
- if (i < 0) throw new CodeCutError("unknown_element", `#${a.id} is not a timed item of its track`);
24314
+ if (i < 0)
24315
+ throw new FlomotionError("unknown_element", `#${a.id} is not a timed item of its track`);
24290
24316
  const it = items[i];
24291
24317
  const d = snap(root, lit(root, a.delta, "delta", a.id));
24292
24318
  const prev = items[i - 1];
@@ -24295,12 +24321,12 @@ function slide(root, a) {
24295
24321
  const patches = [setTime(a.id, "start", it.start + d)];
24296
24322
  if (prev && Math.abs(prev.end - it.start) < 1e-6) {
24297
24323
  if (prev.duration + d <= 0)
24298
- throw new CodeCutError("invalid_edit", "slide would collapse the previous clip");
24324
+ throw new FlomotionError("invalid_edit", "slide would collapse the previous clip");
24299
24325
  patches.push(setTime(prev.id, "duration", prev.duration + d));
24300
24326
  }
24301
24327
  if (next && Math.abs(it.end - next.start) < 1e-6) {
24302
24328
  if (next.duration - d <= 0)
24303
- throw new CodeCutError("invalid_edit", "slide would collapse the next clip");
24329
+ throw new FlomotionError("invalid_edit", "slide would collapse the next clip");
24304
24330
  patches.push(
24305
24331
  setTime(next.id, "start", next.start + d),
24306
24332
  setTime(next.id, "duration", next.duration - d)
@@ -24314,7 +24340,7 @@ function slide(root, a) {
24314
24340
  }
24315
24341
  function move(root, a) {
24316
24342
  const { node: node2, parent, index } = elementOrThrow(root, a.id);
24317
- if (!parent) throw new CodeCutError("invalid_edit", "Cannot move the root");
24343
+ if (!parent) throw new FlomotionError("invalid_edit", "Cannot move the root");
24318
24344
  assertWritable(parent);
24319
24345
  const it = timingOf(root, node2);
24320
24346
  const to = snap(root, lit(root, a.to, "to", a.id));
@@ -24356,11 +24382,11 @@ function unlink(root, a) {
24356
24382
  }
24357
24383
  function wrap(root, ids, name, id) {
24358
24384
  if (!ids.length)
24359
- throw new CodeCutError("invalid_edit", `${name.toLowerCase()} needs at least one id`);
24385
+ throw new FlomotionError("invalid_edit", `${name.toLowerCase()} needs at least one id`);
24360
24386
  const els = ids.map((i) => elementOrThrow(root, i));
24361
24387
  const parent = els[0].parent;
24362
24388
  if (els.some((e) => e.parent !== parent))
24363
- throw new CodeCutError("invalid_edit", "All elements must share one parent");
24389
+ throw new FlomotionError("invalid_edit", "All elements must share one parent");
24364
24390
  assertWritable(parent);
24365
24391
  const times = els.map((e) => timingOf(root, e.node));
24366
24392
  const start = Math.min(...times.map((t) => t.start));
@@ -24393,10 +24419,10 @@ var groupItems = (root, a) => wrap(root, a.ids, "Group", a.id);
24393
24419
  var nest = (root, a) => wrap(root, a.ids, "Precomp", a.id);
24394
24420
  function ungroup(root, a) {
24395
24421
  const { node: node2, parent, index } = elementOrThrow(root, a.id);
24396
- if (!parent) throw new CodeCutError("invalid_edit", "Cannot ungroup the root");
24422
+ if (!parent) throw new FlomotionError("invalid_edit", "Cannot ungroup the root");
24397
24423
  assertWritable(parent);
24398
24424
  if (node2.name !== "Group" && node2.name !== "Precomp")
24399
- throw new CodeCutError("invalid_edit", `#${a.id} is a ${node2.name}, not a Group`);
24425
+ throw new FlomotionError("invalid_edit", `#${a.id} is a ${node2.name}, not a Group`);
24400
24426
  const gs = timingOf(root, node2).start;
24401
24427
  const patches = [{ op: "remove", id: a.id }];
24402
24428
  node2.children.filter(isNode).forEach((c, k) => {
@@ -24411,7 +24437,7 @@ function ungroup(root, a) {
24411
24437
  }
24412
24438
  function setSpeed(root, a) {
24413
24439
  assertWritable(parentTrackOf(root, a.id));
24414
- if (!(a.speed > 0)) throw new CodeCutError("invalid_edit", "speed must be > 0");
24440
+ if (!(a.speed > 0)) throw new FlomotionError("invalid_edit", "speed must be > 0");
24415
24441
  const it = timingOf(root, elementOrThrow(root, a.id).node);
24416
24442
  const old = speedOf(it.node);
24417
24443
  const dur = snap(root, it.duration * old / a.speed);
@@ -24423,7 +24449,7 @@ function setSpeed(root, a) {
24423
24449
  }
24424
24450
  function snapOp(root, a) {
24425
24451
  const { node: node2, parent } = elementOrThrow(root, a.id);
24426
- if (!parent) throw new CodeCutError("invalid_edit", "Cannot snap the root");
24452
+ if (!parent) throw new FlomotionError("invalid_edit", "Cannot snap the root");
24427
24453
  assertWritable(parent);
24428
24454
  const it = timingOf(root, node2);
24429
24455
  const fps = fpsOf(root);
@@ -24490,7 +24516,7 @@ function addMarker(root, a) {
24490
24516
  }
24491
24517
  function removeMarker(root, a) {
24492
24518
  const { node: node2 } = elementOrThrow(root, a.id);
24493
- if (node2.name !== "Marker") throw new CodeCutError("invalid_edit", `#${a.id} is not a Marker`);
24519
+ if (node2.name !== "Marker") throw new FlomotionError("invalid_edit", `#${a.id} is not a Marker`);
24494
24520
  return makeResult(root, [{ op: "remove", id: a.id }], `remove marker #${a.id}`);
24495
24521
  }
24496
24522
  var EDIT_OPS = {
@@ -24522,7 +24548,7 @@ var EDIT_OPS = {
24522
24548
  function runEdit(root, op, args) {
24523
24549
  const fn = EDIT_OPS[op];
24524
24550
  if (!fn)
24525
- throw new CodeCutError("invalid_edit", `Unknown edit op "${op}"`, {
24551
+ throw new FlomotionError("invalid_edit", `Unknown edit op "${op}"`, {
24526
24552
  fix: `Ops: ${Object.keys(EDIT_OPS).join(", ")}`
24527
24553
  });
24528
24554
  return fn(root, args);
@@ -24535,7 +24561,7 @@ var num2 = (t, id) => {
24535
24561
  if (typeof t === "number") return t;
24536
24562
  const m = /^(-?\d+(?:\.\d+)?)s?$/.exec(t.trim());
24537
24563
  if (!m)
24538
- throw new CodeCutError(
24564
+ throw new FlomotionError(
24539
24565
  "opaque_expression",
24540
24566
  `Keyframe time ${JSON.stringify(t)} on #${id} is a reference; structured keyframe edits need literal times`,
24541
24567
  { fix: "Replace it with a literal time first." }
@@ -24547,20 +24573,20 @@ function read(root, id, prop, create = false) {
24547
24573
  const raw = node2.props[prop];
24548
24574
  if (raw === void 0) {
24549
24575
  if (!create)
24550
- throw new CodeCutError("invalid_edit", `#${id}.${prop} has no keyframes`, {
24576
+ throw new FlomotionError("invalid_edit", `#${id}.${prop} has no keyframes`, {
24551
24577
  fix: "Use keyAdd to create the first key."
24552
24578
  });
24553
24579
  return { set: { keys: [], opts: {} }, node: node2, raw };
24554
24580
  }
24555
24581
  if (typeof raw === "function")
24556
- throw new CodeCutError(
24582
+ throw new FlomotionError(
24557
24583
  "opaque_expression",
24558
24584
  `#${id}.${prop} is an expression; it cannot be edited as keyframes`,
24559
24585
  { fix: "Replace the expression with keyframes first." }
24560
24586
  );
24561
24587
  if (!isKeyframes(raw)) {
24562
24588
  if (!create)
24563
- throw new CodeCutError("invalid_edit", `#${id}.${prop} is a static value, not keyframes`, {
24589
+ throw new FlomotionError("invalid_edit", `#${id}.${prop} is a static value, not keyframes`, {
24564
24590
  fix: "Use keyAdd to turn it into keyframes."
24565
24591
  });
24566
24592
  return { set: { keys: [], opts: {} }, node: node2, raw };
@@ -24584,7 +24610,7 @@ function write(root, id, prop, set2, desc, data) {
24584
24610
  const keys = [...set2.keys].sort((a, b) => a.t - b.t);
24585
24611
  for (let i = 1; i < keys.length; i++) {
24586
24612
  if (keys[i].t === keys[i - 1].t)
24587
- throw new CodeCutError(
24613
+ throw new FlomotionError(
24588
24614
  "duplicate_keyframe",
24589
24615
  `Two keyframes share time ${keys[i].t}s on #${id}.${prop}`,
24590
24616
  { fix: "Give each key a unique time (at least one frame apart)." }
@@ -24610,9 +24636,13 @@ function keyAdd(root, a) {
24610
24636
  if (t > 0) set2.keys.push({ t: 0, v: node2.props[a.prop] });
24611
24637
  }
24612
24638
  if (set2.keys.some((k) => same(k.t, t)))
24613
- throw new CodeCutError("duplicate_keyframe", `#${a.id}.${a.prop} already has a key at ${t}s`, {
24614
- fix: "Use keySet to change it."
24615
- });
24639
+ throw new FlomotionError(
24640
+ "duplicate_keyframe",
24641
+ `#${a.id}.${a.prop} already has a key at ${t}s`,
24642
+ {
24643
+ fix: "Use keySet to change it."
24644
+ }
24645
+ );
24616
24646
  set2.keys.push({ t, v: a.value, ...a.ease ? { ease: a.ease } : {} });
24617
24647
  return write(root, a.id, a.prop, set2, `add key ${a.prop} @ ${t}s on #${a.id}`);
24618
24648
  }
@@ -24621,7 +24651,7 @@ function keySet(root, a) {
24621
24651
  const t = snap2(root, num2(a.t, a.id));
24622
24652
  const k = set2.keys.find((x) => same(x.t, t));
24623
24653
  if (!k)
24624
- throw new CodeCutError("invalid_edit", `#${a.id}.${a.prop} has no key at ${t}s`, {
24654
+ throw new FlomotionError("invalid_edit", `#${a.id}.${a.prop} has no key at ${t}s`, {
24625
24655
  fix: "Use keyAdd to create one."
24626
24656
  });
24627
24657
  if (a.value !== void 0) k.v = a.value;
@@ -24635,9 +24665,9 @@ function keyMove(root, a) {
24635
24665
  const f = snap2(root, num2(a.from, a.id));
24636
24666
  const t = snap2(root, num2(a.to, a.id));
24637
24667
  const k = set2.keys.find((x) => same(x.t, f));
24638
- if (!k) throw new CodeCutError("invalid_edit", `#${a.id}.${a.prop} has no key at ${f}s`);
24668
+ if (!k) throw new FlomotionError("invalid_edit", `#${a.id}.${a.prop} has no key at ${f}s`);
24639
24669
  if (set2.keys.some((x) => x !== k && same(x.t, t)))
24640
- throw new CodeCutError("duplicate_keyframe", `#${a.id}.${a.prop} already has a key at ${t}s`);
24670
+ throw new FlomotionError("duplicate_keyframe", `#${a.id}.${a.prop} already has a key at ${t}s`);
24641
24671
  k.t = t;
24642
24672
  return write(root, a.id, a.prop, set2, `move key ${a.prop} ${f}s \u2192 ${t}s on #${a.id}`);
24643
24673
  }
@@ -24647,7 +24677,7 @@ function keyDelete(root, a) {
24647
24677
  const before = set2.keys.length;
24648
24678
  set2.keys = set2.keys.filter((x) => !same(x.t, t));
24649
24679
  if (set2.keys.length === before)
24650
- throw new CodeCutError("invalid_edit", `#${a.id}.${a.prop} has no key at ${t}s`);
24680
+ throw new FlomotionError("invalid_edit", `#${a.id}.${a.prop} has no key at ${t}s`);
24651
24681
  if (set2.keys.length === 0)
24652
24682
  return makeResult(
24653
24683
  root,
@@ -24664,13 +24694,13 @@ function keyCopy(root, a) {
24664
24694
  }
24665
24695
  function keyPaste(root, a) {
24666
24696
  const { set: set2 } = read(root, a.id, a.prop, true);
24667
- if (!a.keys.length) throw new CodeCutError("invalid_edit", "nothing to paste");
24697
+ if (!a.keys.length) throw new FlomotionError("invalid_edit", "nothing to paste");
24668
24698
  const base = Math.min(...a.keys.map((k) => num2(k.t, a.id)));
24669
24699
  const at = snap2(root, num2(a.at, a.id));
24670
24700
  for (const k of a.keys) {
24671
24701
  const t = snap2(root, at + num2(k.t, a.id) - base);
24672
24702
  if (set2.keys.some((x) => same(x.t, t)))
24673
- throw new CodeCutError(
24703
+ throw new FlomotionError(
24674
24704
  "duplicate_keyframe",
24675
24705
  `paste would put two keys at ${t}s on #${a.id}.${a.prop}`
24676
24706
  );
@@ -24685,7 +24715,7 @@ function keyPaste(root, a) {
24685
24715
  );
24686
24716
  }
24687
24717
  function keyScale(root, a) {
24688
- if (!(a.factor > 0)) throw new CodeCutError("invalid_edit", "factor must be > 0");
24718
+ if (!(a.factor > 0)) throw new FlomotionError("invalid_edit", "factor must be > 0");
24689
24719
  const { set: set2 } = read(root, a.id, a.prop);
24690
24720
  const origin = a.origin === void 0 ? set2.keys[0].t : num2(a.origin, a.id);
24691
24721
  for (const k of set2.keys) k.t = snap2(root, origin + (k.t - origin) * a.factor);
@@ -24788,7 +24818,7 @@ function keySimplify(root, a) {
24788
24818
  const tol = a.tolerance ?? 0.01;
24789
24819
  const vecs = set2.keys.map((k) => Array.isArray(k.v) ? k.v : [k.v]);
24790
24820
  if (vecs.some((v) => v.some((x) => typeof x !== "number")))
24791
- throw new CodeCutError("invalid_edit", "keySimplify works on numeric or vector keys");
24821
+ throw new FlomotionError("invalid_edit", "keySimplify works on numeric or vector keys");
24792
24822
  const t = set2.keys.map((k) => k.t);
24793
24823
  const keep = /* @__PURE__ */ new Set([0, set2.keys.length - 1]);
24794
24824
  const rec = (i, j) => {
@@ -24825,7 +24855,7 @@ var AXES = ["x", "y", "z"];
24825
24855
  function keySeparate(root, a) {
24826
24856
  const { set: set2 } = read(root, a.id, a.prop);
24827
24857
  const dim = Array.isArray(set2.keys[0].v) ? set2.keys[0].v.length : 0;
24828
- if (!dim) throw new CodeCutError("invalid_edit", `#${a.id}.${a.prop} is not a vector property`);
24858
+ if (!dim) throw new FlomotionError("invalid_edit", `#${a.id}.${a.prop} is not a vector property`);
24829
24859
  const value = {};
24830
24860
  for (let c = 0; c < dim; c++) {
24831
24861
  value[AXES[c]] = set2.keys.map(
@@ -24842,7 +24872,7 @@ function keyCombine(root, a) {
24842
24872
  const { node: node2 } = elementOrThrow(root, a.id);
24843
24873
  const raw = node2.props[a.prop];
24844
24874
  if (!raw || Array.isArray(raw) || typeof raw !== "object")
24845
- throw new CodeCutError("invalid_edit", `#${a.id}.${a.prop} is not per-axis`);
24875
+ throw new FlomotionError("invalid_edit", `#${a.id}.${a.prop} is not per-axis`);
24846
24876
  const axes = AXES.filter((x) => raw[x]);
24847
24877
  const lists = axes.map(
24848
24878
  (x) => raw[x].map(
@@ -24886,16 +24916,16 @@ var KEY_OPS = {
24886
24916
  function runKeyOp(root, op, args) {
24887
24917
  const fn = KEY_OPS[op];
24888
24918
  if (!fn)
24889
- throw new CodeCutError("invalid_edit", `Unknown keyframe op "${op}"`, {
24919
+ throw new FlomotionError("invalid_edit", `Unknown keyframe op "${op}"`, {
24890
24920
  fix: `Ops: ${Object.keys(KEY_OPS).join(", ")}`
24891
24921
  });
24892
24922
  return fn(root, args);
24893
24923
  }
24894
24924
 
24895
24925
  export {
24896
- CODECUT_NAME,
24897
- CODECUT_SCOPE,
24898
- CODECUT_DIR,
24926
+ FLOMOTION_NAME,
24927
+ FLOMOTION_SCOPE,
24928
+ FLOMOTION_DIR,
24899
24929
  ID_PREFIX,
24900
24930
  snapToFrame,
24901
24931
  secondsToFrames,