videobook 0.2.1 → 0.2.3

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 (42) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +7 -8
  3. package/dist/book-manager.js +40 -2
  4. package/dist/chat-router.js +1 -1
  5. package/dist/env-secrets.js +1 -0
  6. package/dist/guides/seedance_2_prompting_guide.md +1 -1
  7. package/dist/image-edit-models.js +2 -0
  8. package/dist/jobs/generate-media.js +18 -6
  9. package/dist/jobs/run-notebook.js +23 -4
  10. package/dist/media/adapters/fal.js +7 -0
  11. package/dist/media/catalog.js +17 -2
  12. package/dist/media/cost.js +80 -7
  13. package/dist/media/json-schema.js +7 -0
  14. package/dist/media/ref-fields.js +11 -3
  15. package/dist/media/refs.js +13 -0
  16. package/dist/media/request.js +56 -0
  17. package/dist/media/seedance-edit.js +9 -0
  18. package/dist/provider-usage.js +22 -8
  19. package/dist/tools/estimate-cost.js +8 -5
  20. package/dist/tools/generate-media.js +2 -1
  21. package/dist/tools/provider-key-status.js +2 -0
  22. package/dist/tools/reconcile-project-work.js +2 -1
  23. package/package.json +13 -13
  24. package/ui/assets/{alive-captions-e-n3xmCd.js → alive-captions-4QySEGdt.js} +1 -1
  25. package/ui/assets/confirm-bodies-Bw818V9J.js +1 -0
  26. package/ui/assets/{fullscreen-VY7f4mJ-.js → fullscreen-CzTnPPG5.js} +1 -1
  27. package/ui/assets/{goal-ui-B__NgZYz.js → goal-ui-CosrK_ko.js} +2 -2
  28. package/ui/assets/index-C9xjFEGL.js +37 -0
  29. package/ui/assets/{inspector-BBuZIaqg.js → inspector-BN2fezh4.js} +1 -1
  30. package/ui/assets/{jobs-ui-vmEH4zBT.js → jobs-ui-C4Wgy6I1.js} +1 -1
  31. package/ui/assets/{music-video-CklLKD1R.js → music-video-BSj8SgbQ.js} +1 -1
  32. package/ui/assets/ui-Cpr6zMTA.js +2 -0
  33. package/ui/assets/{vendor-flow-DY81i6dC.js → vendor-flow-zBavaNEW.js} +1 -1
  34. package/ui/assets/{vendor-mcp-BsGNAD4I.js → vendor-mcp-DQ7EusT9.js} +1 -1
  35. package/ui/assets/vendor-yctIZ9Dz.js +19 -0
  36. package/ui/assets/videobook-B5G0jMoi.js +20 -0
  37. package/ui/index.html +11 -11
  38. package/ui/assets/confirm-bodies-DS6jh0Kb.js +0 -1
  39. package/ui/assets/index-BPco0HoT.js +0 -37
  40. package/ui/assets/ui-CtYXY_po.js +0 -2
  41. package/ui/assets/vendor-OClqq_Da.js +0 -19
  42. package/ui/assets/videobook-lhLK6e6Q.js +0 -20
@@ -1,3 +1,4 @@
1
+ import { isSeedanceEdit } from "./seedance-edit.js";
1
2
  import { insertVideoTimingError, isInsertVideoModel } from "./insert-video-timing.js";
2
3
  function clone(value) {
3
4
  return value === undefined ? value : structuredClone(value);
@@ -11,6 +12,15 @@ function childContainer(current, key, nextIsIndex) {
11
12
  holder[key] = created;
12
13
  return created;
13
14
  }
15
+ function getPath(target, path) {
16
+ let current = target;
17
+ for (const segment of path.split(".")) {
18
+ if (current === null || typeof current !== "object")
19
+ return undefined;
20
+ current = current[segment];
21
+ }
22
+ return current;
23
+ }
14
24
  function setPath(target, path, value) {
15
25
  const segments = path.split(".");
16
26
  let current = target;
@@ -66,12 +76,51 @@ function checkRefs(model, refs, mode) {
66
76
  function refValue(field, url, item) {
67
77
  return field.urlObject ? { ...item, url } : url;
68
78
  }
79
+ function keyframeIndexes(count, lastFrame) {
80
+ if (count <= 1)
81
+ return [0];
82
+ return Array.from({ length: count }, (_, index) => Math.round((index * lastFrame) / (count - 1)));
83
+ }
84
+ function retimeKeyframeField(model, value, field) {
85
+ const fps = model.entry.keyframeFps;
86
+ if (!fps)
87
+ return;
88
+ const current = getPath(value, field.path);
89
+ if (!Array.isArray(current) || current.length === 0)
90
+ return;
91
+ const duration = typeof value.duration === "number" && Number.isFinite(value.duration) && value.duration > 0
92
+ ? value.duration
93
+ : 5;
94
+ const indexes = keyframeIndexes(current.length, Math.round(duration * fps));
95
+ setPath(value, field.path, current.map((frame, index) => {
96
+ const imageUrl = typeof frame === "object" && frame !== null && "image_url" in frame
97
+ ? frame.image_url
98
+ : frame;
99
+ return { image_url: imageUrl, frame_index: indexes[index] };
100
+ }));
101
+ }
102
+ function retimeKeyframes(model, value) {
103
+ if (!model.entry.keyframeFps)
104
+ return;
105
+ for (const slot of model.slots) {
106
+ for (const field of slot.fields) {
107
+ if (field.keyframe)
108
+ retimeKeyframeField(model, value, field);
109
+ }
110
+ }
111
+ }
69
112
  function placeSlot(model, slot, value, urls) {
70
113
  const item = model.entry.refItem?.[slot.role];
71
114
  let cursor = 0;
72
115
  for (const field of slot.fields) {
73
116
  if (cursor >= urls.length)
74
117
  return;
118
+ if (field.keyframe) {
119
+ const taken = field.max === null ? urls.slice(cursor) : urls.slice(cursor, cursor + field.max);
120
+ setPath(value, field.path, taken.map((url) => ({ image_url: url, frame_index: 0 })));
121
+ cursor += taken.length;
122
+ continue;
123
+ }
75
124
  if (!field.multi) {
76
125
  setPath(value, field.path, refValue(field, urls[cursor], item));
77
126
  cursor += 1;
@@ -162,6 +211,8 @@ export function buildWireRequest(model, call) {
162
211
  const refError = checkRefs(model, refs, call.mode);
163
212
  if (refError)
164
213
  return { ok: false, error: refError };
214
+ if (isSeedanceEdit(model.id, call.mode) && refs.video?.length !== 1)
215
+ return { ok: false, error: "Seedance Edit video requires exactly one source video (4–30 seconds)." };
165
216
  const promptError = checkPrompt(model, call.prompt);
166
217
  if (promptError)
167
218
  return { ok: false, error: promptError };
@@ -172,6 +223,11 @@ export function buildWireRequest(model, call) {
172
223
  if (optionError)
173
224
  return { ok: false, error: optionError };
174
225
  applyFrameOptions(model, value, refs, call.mode);
226
+ retimeKeyframes(model, value);
227
+ if (isSeedanceEdit(model.id, call.mode)) {
228
+ value.aspect_ratio = "adaptive";
229
+ value.duration = -1;
230
+ }
175
231
  const prompt = call.prompt?.trim();
176
232
  if (model.promptField && prompt)
177
233
  setPath(value, model.promptField, prompt);
@@ -0,0 +1,9 @@
1
+ export const SEEDANCE_EDIT_DESCRIPTION = "Edit video follows the source aspect ratio and duration. Connect one 4–30 second video plus optional image or audio references.";
2
+ export function isSeedanceEdit(model, mode) {
3
+ return model === "kie:bytedance/seedance-2-5" && mode === "v2v";
4
+ }
5
+ export function seedanceEditFailure(model, message) {
6
+ if (model !== "kie:bytedance/seedance-2-5" || !/video edit/i.test(message))
7
+ return message;
8
+ return `${message} Select Edit video (mode v2v) with one 4–30 second source video; this sets aspect_ratio=adaptive and duration=-1. Review the preview before retrying.`;
9
+ }
@@ -3,6 +3,8 @@ import { readFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { createCost, PRICING, PRICING_AS_OF } from "@apicity/cost";
6
+ import { modelEntry } from "./media/catalog.js";
7
+ import { estimateFalRequest } from "./media/cost.js";
6
8
  import { currentBookContext } from "./book-context.js";
7
9
  function installedPackageVersion(name) {
8
10
  let dir = dirname(fileURLToPath(import.meta.resolve(name)));
@@ -90,16 +92,27 @@ function tokenPrice(provider, model, tokens) {
90
92
  const usd = ((tokens.inputTokens - cached) * rate.rate.input + cached * (rate.rate.cacheRead ?? rate.rate.input) + tokens.outputTokens * rate.rate.output) / 1e6;
91
93
  return { ...unknownPrice([]), costUsd: usd, basis: "estimated", rateSource: rate.source.url, unit: "tokens", units: tokens.inputTokens + tokens.outputTokens };
92
94
  }
93
- function priceRequest(provider, model, payload, endpoint, hints) {
95
+ function historicalAverage(warnings) {
96
+ return warnings.length > 0 && warnings.every((warning) => warning.includes("historical average per call"));
97
+ }
98
+ async function priceRequest(provider, model, payload, endpoint, hints) {
94
99
  try {
95
100
  const request = { provider, payload, ...(provider === "fal" ? { endpoint } : {}), ...(hints ? { costHints: hints } : {}) };
96
- const estimate = cost.estimate(request);
97
- if (estimate.warnings.length || estimate.source === "tokens-heuristic+table")
101
+ const estimate = provider === "fal"
102
+ ? await estimateFalRequest(endpoint, payload, hints)
103
+ : cost.estimate(request);
104
+ const historical = estimate.usd > 0 && historicalAverage(estimate.warnings);
105
+ if (!historical && (estimate.warnings.length || estimate.source === "tokens-heuristic+table")) {
98
106
  return unknownPrice(estimate.warnings.length ? estimate.warnings : ["Waiting for reported token usage"]);
107
+ }
99
108
  return {
100
- ...unknownPrice([]), costUsd: estimate.usd, basis: estimate.source === "free" ? "free" : "estimated",
101
- rateSource: rateFor(provider, model)?.source.url ?? null, pricingVersion: `apicity-${COST_PACKAGE_VERSION}:${estimate.rateAsOf}`,
102
- units: estimate.breakdown.units ?? null, unit: estimate.breakdown.unit ?? null,
109
+ ...unknownPrice(historical ? estimate.warnings : []),
110
+ costUsd: estimate.usd,
111
+ basis: estimate.source === "free" ? "free" : "estimated",
112
+ rateSource: rateFor(provider, model)?.source.url ?? null,
113
+ pricingVersion: `apicity-${COST_PACKAGE_VERSION}:${estimate.rateAsOf ?? (historical ? "fal-historical" : PRICING_AS_OF)}`,
114
+ units: estimate.breakdown.units ?? null,
115
+ unit: estimate.breakdown.unit ?? null,
103
116
  };
104
117
  }
105
118
  catch {
@@ -127,7 +140,8 @@ function isBillable(provider, path, method) {
127
140
  if (provider === "kie")
128
141
  return /\/(createTask|veo\/(generate|extend))$/u.test(path);
129
142
  if (provider === "fal")
130
- return /^\/(fal-ai|alibaba)\//u.test(path) && !/\/requests\//u.test(path);
143
+ return !/\/requests\//u.test(path)
144
+ && (/^\/(fal-ai|alibaba)\//u.test(path) || modelEntry(`fal:${path.slice(1)}`) !== undefined);
131
145
  if (provider === "alibaba")
132
146
  return path.includes("/services/aigc/");
133
147
  if (provider === "elevenlabs")
@@ -238,7 +252,7 @@ export function providerUsageFetch(provider, transport = fetch) {
238
252
  id: randomUUID(), provider, model, activity, status: "pending",
239
253
  tokenBased: /\/(responses|completions|embeddings)$/u.test(url.pathname) || rateFor(provider, model)?.kind === "tokens",
240
254
  operation: context.operation ?? null, artifactId: context.artifactId ?? null,
241
- ...priceRequest(provider, model, payload, endpoint, hints),
255
+ ...await priceRequest(provider, model, payload, endpoint, hints),
242
256
  };
243
257
  safeRecord(engine, entry);
244
258
  }
@@ -5,7 +5,7 @@ import { previewPlaceholderUrl } from "../preview-payload.js";
5
5
  import { DEFAULT_IMAGE_EDIT_MODEL_ID, findImageEditModel } from "../image-edit-models.js";
6
6
  import { tryResolveModel } from "../media/descriptor.js";
7
7
  import { estimateGeneration } from "../media/cost.js";
8
- import { normalizeRefs } from "../media/refs.js";
8
+ import { checkSeedanceEditSource, normalizeRefs } from "../media/refs.js";
9
9
  import { REF_ROLES } from "../media/types.js";
10
10
  const GENERATION_TOOLS = new Set(["generate_image", "generate_video", "generate_audio"]);
11
11
  const REWRITE_MODEL = "gpt-5.6-sol";
@@ -67,7 +67,10 @@ async function estimateMedia(engine, input) {
67
67
  const options = input.options !== null && typeof input.options === "object" && !Array.isArray(input.options)
68
68
  ? input.options
69
69
  : {};
70
- const result = estimateGeneration(model, {
70
+ const sourceError = await checkSeedanceEditSource(engine, model, refs, input.mode);
71
+ if (sourceError)
72
+ return unavailable(sourceError);
73
+ const result = await estimateGeneration(model, {
71
74
  prompt: text(input.prompt),
72
75
  refUrls: placeholderRefs(refs),
73
76
  options,
@@ -75,7 +78,7 @@ async function estimateMedia(engine, input) {
75
78
  }, await mediaHints(engine, refs));
76
79
  return result.ok ? result.estimate : unavailable(result.error);
77
80
  }
78
- function estimateImageEdit(input) {
81
+ async function estimateImageEdit(input) {
79
82
  if (input.model === "sharp/layer-composite" && input.operation === "remove")
80
83
  return { ...FREE_ESTIMATE };
81
84
  const editModel = findImageEditModel(text(input.model) ?? DEFAULT_IMAGE_EDIT_MODEL_ID);
@@ -83,7 +86,7 @@ function estimateImageEdit(input) {
83
86
  if (!model)
84
87
  return unavailable(`unknown image edit model '${String(input.model)}'`);
85
88
  const imageCount = Array.isArray(input.image_refs) && input.image_refs.length > 0 ? input.image_refs.length : 1;
86
- const result = estimateGeneration(model, {
89
+ const result = await estimateGeneration(model, {
87
90
  prompt: text(input.prompt) ?? "edit",
88
91
  refUrls: { image: Array.from({ length: imageCount }, (_, index) => `https://example.test/edit-${index + 1}.png`) },
89
92
  });
@@ -142,7 +145,7 @@ export function estimateCostDef(engine, books) {
142
145
  };
143
146
  return {
144
147
  name: "estimate_cost",
145
- description: "Estimate the USD cost of one or more generate_image, generate_video or generate_audio calls, given as {tool_name, input}, before running them. Models without published rates return $0 with a warning.",
148
+ description: "Estimate the USD cost of one or more generate_image, generate_video or generate_audio calls, given as {tool_name, input}, before running them. Dynamically billed fal models use fal's historical average per call when FAL_ADMIN_API_KEY is set, and that estimate warns that it ignores the request. Without that key, or without a published rate, the estimate is $0 with a warning.",
146
149
  schema,
147
150
  handler: async (args) => {
148
151
  const calls = args.calls;
@@ -4,7 +4,7 @@ import { generationLabel } from "../artifact-label.js";
4
4
  import { previewPlaceholderUrl } from "../preview-payload.js";
5
5
  import { resolveModel, UnknownModelError } from "../media/descriptor.js";
6
6
  import { buildWireRequest } from "../media/request.js";
7
- import { checkInsertVideoTiming, checkRefDurations, checkRefs, normalizeRefs } from "../media/refs.js";
7
+ import { checkSeedanceEditSource, checkInsertVideoTiming, checkRefDurations, checkRefs, normalizeRefs } from "../media/refs.js";
8
8
  import { PROVIDER_ENV_KEYS } from "../media/adapters/index.js";
9
9
  import { listModels, modelListing } from "../media/listing.js";
10
10
  import { OPERATIONS_BY_MEDIA, REF_ROLES } from "../media/types.js";
@@ -80,6 +80,7 @@ async function validate(engine, model, args, refs) {
80
80
  return built.error;
81
81
  return (await checkRefs(engine, refs))
82
82
  ?? (await checkInsertVideoTiming(engine, model, refs, optionsOf(args.options)))
83
+ ?? (await checkSeedanceEditSource(engine, model, refs, args.mode))
83
84
  ?? checkRefDurations(engine, model, refs);
84
85
  }
85
86
  async function enqueueGeneration(engine, model, args, refs) {
@@ -13,6 +13,7 @@ const KEY_REGISTRY = {
13
13
  DROPBOX_CLIENT_SECRET: { provider: "dropbox", label: "Dropbox OAuth" },
14
14
  KIMI_CODING_API_KEY: { provider: "kimicoding", label: "Kimi Coding" },
15
15
  FAL_API_KEY: { provider: "fal", label: "FAL" },
16
+ FAL_ADMIN_API_KEY: { provider: "fal", label: "FAL admin" },
16
17
  DASHSCOPE_API_KEY: { provider: "dashscope", label: "DashScope" },
17
18
  B2_ACCESS_KEY_ID: { provider: "b2", label: "Backblaze B2" },
18
19
  B2_SECRET_ACCESS_KEY: { provider: "b2", label: "Backblaze B2" },
@@ -32,6 +33,7 @@ const ROW_ORDER = [
32
33
  "DROPBOX_CLIENT_SECRET",
33
34
  "KIMI_CODING_API_KEY",
34
35
  "FAL_API_KEY",
36
+ "FAL_ADMIN_API_KEY",
35
37
  "DASHSCOPE_API_KEY",
36
38
  "B2_ACCESS_KEY_ID",
37
39
  "B2_SECRET_ACCESS_KEY",
@@ -1,3 +1,4 @@
1
+ import { seedanceEditFailure } from "../media/seedance-edit.js";
1
2
  import { createKie, createXai, createAlibaba, createFal } from "../usage-providers.js";
2
3
  import { describeFalError } from "../jobs/_fal-shared.js";
3
4
  import { currentBookContext, withBookContext } from "../book-context.js";
@@ -1276,7 +1277,7 @@ async function processKieTaskResult(engine, task, taskInfo, result, bookId) {
1276
1277
  result.completed.push({ assetId: task.artifactId, taskType: task.taskType, jobId });
1277
1278
  }
1278
1279
  else if (data?.state === "fail") {
1279
- const failMsg = data.failMsg ?? "unknown error";
1280
+ const failMsg = seedanceEditFailure(task.meta?.model, data.failMsg ?? "unknown error");
1280
1281
  // A kie 500 is only retryable while the task is still in flight; once it
1281
1282
  // has terminally completed, surface the failure instead of stranding the
1282
1283
  // asset as "working" until the 30m reconciliation timeout. See isTransientKieFailure.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "videobook",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Local-first MCP server and web UI for AI video creation: notebooks, generation, editing, rendering and publishing.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -36,18 +36,18 @@
36
36
  "start": "node dist/index.js"
37
37
  },
38
38
  "dependencies": {
39
- "@apicity/alibaba": "^0.16.1",
40
- "@apicity/b2": "^0.16.1",
41
- "@apicity/cost": "^0.16.1",
42
- "@apicity/dropbox": "^0.16.1",
43
- "@apicity/elevenlabs": "^0.16.1",
44
- "@apicity/fal": "^0.16.1",
45
- "@apicity/free-media-upload": "^0.16.1",
46
- "@apicity/kie": "^0.16.1",
47
- "@apicity/kimicoding": "^0.16.1",
48
- "@apicity/openai": "^0.16.1",
49
- "@apicity/x": "^0.16.1",
50
- "@apicity/xai": "^0.16.1",
39
+ "@apicity/alibaba": "^0.16.3",
40
+ "@apicity/b2": "^0.16.3",
41
+ "@apicity/cost": "^0.16.3",
42
+ "@apicity/dropbox": "^0.16.3",
43
+ "@apicity/elevenlabs": "^0.16.3",
44
+ "@apicity/fal": "^0.16.3",
45
+ "@apicity/free-media-upload": "^0.16.3",
46
+ "@apicity/kie": "^0.16.3",
47
+ "@apicity/kimicoding": "^0.16.3",
48
+ "@apicity/openai": "^0.16.3",
49
+ "@apicity/x": "^0.16.3",
50
+ "@apicity/xai": "^0.16.3",
51
51
  "@devmehq/open-graph-extractor": "^1.1.1",
52
52
  "@ffprobe-installer/ffprobe": "2.1.2",
53
53
  "@modelcontextprotocol/client": "^2.2.0",
@@ -1 +1 @@
1
- import{c as F,j as t,a as A}from"./vendor-react-Dj7D1fD4.js";import{u as be,a as xe,V as Se,A as pe,P as Ne}from"./vendor-remotion-CH1HXrlc.js";import{ea as Ce,eb as ke,ec as we,ed as $e,ee as Pe,ef as de,eg as Te,eh as me,ei as Re,ej as Ae,ek as Me,el as _e,em as Ee,en as Oe,eo as fe,bu as We}from"./videobook-lhLK6e6Q.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-CGqhCIXV.js";import"./vendor-OClqq_Da.js";import"./vendor-mcp-BsGNAD4I.js";const Be={face:"#63c7d8",text:"#f0a860",graphic:"#f0a860"};function De(a){const e=F.c(25),{phrase:s,cue:n,settings:o,sourceWidth:c,sourceHeight:l}=a,{width:i,height:h}=xe();let r,f,m,d;if(e[0]!==h||e[1]!==s.id||e[2]!==s.regions||e[3]!==o||e[4]!==l||e[5]!==c||e[6]!==i){const j={sourceWidth:c,sourceHeight:l,targetWidth:i,targetHeight:h};let v;e[11]!==s.regions||e[12]!==o?(v=new Set($e(s.regions,o)),e[11]=s.regions,e[12]=o,e[13]=v):v=e[13];const C=v;let y;e[14]!==i?(y=Math.round(i/480),e[14]=i,e[15]=y):y=e[15],f=Math.max(2,y),r=pe,e[16]===Symbol.for("react.memo_cache_sentinel")?(m={pointerEvents:"none"},e[16]=m):m=e[16],d=s.regions.map((w,$)=>{const b=Pe(w,j);return t.jsx("div",{style:{position:"absolute",left:b.x*i,top:b.y*h,width:b.width*i,height:b.height*h,border:`${f}px dashed ${Be[w.kind]}`,opacity:C.has(w)?1:.4,borderRadius:f*2}},`${s.id}-${$}`)}),e[0]=h,e[1]=s.id,e[2]=s.regions,e[3]=o,e[4]=l,e[5]=c,e[6]=i,e[7]=r,e[8]=f,e[9]=m,e[10]=d}else r=e[7],f=e[8],m=e[9],d=e[10];let g;e[17]!==n.column||e[18]!==f?(g=t.jsx(Ue,{column:n.column,stroke:f}),e[17]=n.column,e[18]=f,e[19]=g):g=e[19];let u;return e[20]!==r||e[21]!==m||e[22]!==d||e[23]!==g?(u=t.jsxs(r,{style:m,children:[d,g]}),e[20]=r,e[21]=m,e[22]=d,e[23]=g,e[24]=u):u=e[24],u}function Ue(a){const e=F.c(7),{column:s,stroke:n}=a,o=`${Math.max(1,n/2)}px dashed rgba(114, 231, 170, 0.6)`,c=n*2;let l;return e[0]!==s.height||e[1]!==s.width||e[2]!==s.x||e[3]!==s.y||e[4]!==o||e[5]!==c?(l=t.jsx("div",{style:{position:"absolute",left:s.x,top:s.y,width:s.width,height:s.height,border:o,borderRadius:c}}),e[0]=s.height,e[1]=s.width,e[2]=s.x,e[3]=s.y,e[4]=o,e[5]=c,e[6]=l):l=e[6],l}function Ke(a){const e=F.c(34),{mediaUrl:s,sourceWidth:n,sourceHeight:o,cues:c,phrases:l,settings:i,showRegions:h}=a,r=be(),{fps:f,width:m,height:d}=xe();let g;e[0]!==d||e[1]!==o||e[2]!==n||e[3]!==m?(g=ke({sourceWidth:n,sourceHeight:o,targetWidth:m,targetHeight:d}),e[0]=d,e[1]=o,e[2]=n,e[3]=m,e[4]=g):g=e[4];const u=g,j=r/f;let v;e[5]!==c||e[6]!==j?(v=Ce(c,j),e[5]=c,e[6]=j,e[7]=v):v=e[7];const C=v;let y;e[8]!==C||e[9]!==l?(y=C?l.find(M=>M.id===C.id):void 0,e[8]=C,e[9]=l,e[10]=y):y=e[10];const w=y;let $;e[11]===Symbol.for("react.memo_cache_sentinel")?($={background:"#000000"},e[11]=$):$=e[11];let b;e[12]!==u.height||e[13]!==u.width||e[14]!==u.x||e[15]!==u.y?(b={position:"absolute",left:u.x,top:u.y,width:u.width,height:u.height},e[12]=u.height,e[13]=u.width,e[14]=u.x,e[15]=u.y,e[16]=b):b=e[16];let N;e[17]!==s||e[18]!==b?(N=t.jsx(Se,{src:s,style:b}),e[17]=s,e[18]=b,e[19]=N):N=e[19];let P;e[20]!==C||e[21]!==w||e[22]!==i||e[23]!==h||e[24]!==o||e[25]!==n?(P=h&&C&&w&&t.jsx(De,{phrase:w,cue:C,settings:i,sourceWidth:n,sourceHeight:o}),e[20]=C,e[21]=w,e[22]=i,e[23]=h,e[24]=o,e[25]=n,e[26]=P):P=e[26];let x;e[27]!==c||e[28]!==i?(x=t.jsx(we,{cues:c,settings:i,strokeWidth:6,strokeColor:"#000000",shadowBlur:6,shadowOpacity:60}),e[27]=c,e[28]=i,e[29]=x):x=e[29];let k;return e[30]!==N||e[31]!==P||e[32]!==x?(k=t.jsxs(pe,{style:$,children:[N,P,x]}),e[30]=N,e[31]=P,e[32]=x,e[33]=k):k=e[33],k}const ue=[{id:"stack",label:"Stack",hint:"Words land one by one and build a stacked block beside the subject, each line sized to fill the column."},{id:"punch",label:"Punch",hint:"One word at a time, as big as the free space allows. Best on fast verses."},{id:"karaoke",label:"Karaoke",hint:"The whole stacked phrase shows dimmed and lights up word by word."}],Ve=[{id:"pop",label:"Pop"},{id:"slam",label:"Slam"},{id:"rise",label:"Rise"}],Ge=[{name:"Green",color:"#72E7AA"},{name:"Pink",color:"#F0B9D0"},{name:"Cyan",color:"#63C7D8"},{name:"Amber",color:"#E7C372"}];function Xe(a,e){if(!a.drifted)return de(a.start);const s=a.driftMs>0?"+":"";return e?`${de(a.start)} · snapped`:`${de(a.start)} · ${s}${a.driftMs}ms`}function qe(a){const e=F.c(21),{rows:s,phraseLabels:n,activePhrase:o,time:c,snapped:l,onSeek:i}=a;let h;e[0]===Symbol.for("react.memo_cache_sentinel")?(h=t.jsx("h3",{children:"Transcript"}),e[0]=h):h=e[0];let r;e[1]!==s.length?(r=t.jsxs("header",{className:"alive-panel-header",children:[h,t.jsxs("p",{children:[s.length," words · timed to the vocal"]})]}),e[1]=s.length,e[2]=r):r=e[2];let f;if(e[3]!==o||e[4]!==i||e[5]!==n||e[6]!==s||e[7]!==l||e[8]!==c){let g;e[10]!==o||e[11]!==i||e[12]!==s||e[13]!==l||e[14]!==c?(g=(u,j)=>t.jsxs("div",{className:"alive-phrase","data-active":j===o||void 0,children:[t.jsxs("div",{className:"alive-phrase-head",children:[t.jsxs("span",{children:["Phrase ",j+1]}),t.jsx("span",{children:u})]}),t.jsx("div",{className:"alive-phrase-words",children:s.filter(v=>v.phraseIndex===j).map(v=>t.jsxs("button",{type:"button",className:"alive-word","data-active":c>=v.start&&c<v.end||void 0,"data-drifted":v.drifted&&!l||void 0,onClick:()=>i(v.start+.03),children:[t.jsx("span",{children:v.text}),t.jsx("small",{children:Xe(v,l)})]},v.key))})]},`${j}-${u}`),e[10]=o,e[11]=i,e[12]=s,e[13]=l,e[14]=c,e[15]=g):g=e[15],f=n.map(g),e[3]=o,e[4]=i,e[5]=n,e[6]=s,e[7]=l,e[8]=c,e[9]=f}else f=e[9];let m;e[16]!==f?(m=t.jsx("div",{className:"alive-transcript-list",children:f}),e[16]=f,e[17]=m):m=e[17];let d;return e[18]!==r||e[19]!==m?(d=t.jsxs("section",{className:"alive-panel alive-transcript","aria-label":"Transcript",children:[r,m]}),e[18]=r,e[19]=m,e[20]=d):d=e[20],d}function ve(a){const e=F.c(10),{label:s,options:n,value:o,onChange:c}=a;let l;if(e[0]!==c||e[1]!==n||e[2]!==o){let h;e[4]!==c||e[5]!==o?(h=r=>t.jsx("button",{type:"button","aria-pressed":r.id===o,onClick:()=>c(r.id),children:r.label},r.id),e[4]=c,e[5]=o,e[6]=h):h=e[6],l=n.map(h),e[0]=c,e[1]=n,e[2]=o,e[3]=l}else l=e[3];let i;return e[7]!==s||e[8]!==l?(i=t.jsx("div",{className:"alive-segmented",role:"group","aria-label":s,children:l}),e[7]=s,e[8]=l,e[9]=i):i=e[9],i}function re(a){const e=F.c(8),{checked:s,onChange:n,children:o}=a;let c;e[0]!==n?(c=h=>n(h.target.checked),e[0]=n,e[1]=c):c=e[1];let l;e[2]!==s||e[3]!==c?(l=t.jsx("input",{type:"checkbox",checked:s,onChange:c}),e[2]=s,e[3]=c,e[4]=l):l=e[4];let i;return e[5]!==o||e[6]!==l?(i=t.jsxs("label",{className:"alive-toggle",children:[l,o]}),e[5]=o,e[6]=l,e[7]=i):i=e[7],i}function Ye(a){const e=F.c(69),{settings:s,showRegions:n,regionsAnalyzed:o,working:c,onChange:l,onShowRegions:i,onReanalyze:h}=a;let r;e[0]!==s.style?(r=ue.find(S=>S.id===s.style)?.hint,e[0]=s.style,e[1]=r):r=e[1];const f=r;let m;e[2]===Symbol.for("react.memo_cache_sentinel")?(m=t.jsx("h4",{children:"Style"}),e[2]=m):m=e[2];let d;e[3]!==l?(d=S=>l({style:S}),e[3]=l,e[4]=d):d=e[4];let g;e[5]!==s.style||e[6]!==d?(g=t.jsx(ve,{label:"Caption style",options:ue,value:s.style,onChange:d}),e[5]=s.style,e[6]=d,e[7]=g):g=e[7];let u;e[8]!==f?(u=t.jsx("p",{className:"alive-hint",children:f}),e[8]=f,e[9]=u):u=e[9];let j;e[10]!==g||e[11]!==u?(j=t.jsxs("div",{className:"alive-field",children:[m,g,u]}),e[10]=g,e[11]=u,e[12]=j):j=e[12];let v;e[13]===Symbol.for("react.memo_cache_sentinel")?(v=t.jsx("h4",{children:"Word entrance"}),e[13]=v):v=e[13];let C;e[14]!==l?(C=S=>l({motion:S}),e[14]=l,e[15]=C):C=e[15];let y;e[16]!==s.motion||e[17]!==C?(y=t.jsxs("div",{className:"alive-field",children:[v,t.jsx(ve,{label:"Word entrance",options:Ve,value:s.motion,onChange:C})]}),e[16]=s.motion,e[17]=C,e[18]=y):y=e[18];let w;e[19]===Symbol.for("react.memo_cache_sentinel")?(w=t.jsx("h4",{children:"Frame awareness"}),e[19]=w):w=e[19];let $;e[20]!==l?($=S=>l({avoidFaces:S}),e[20]=l,e[21]=$):$=e[21];let b;e[22]!==s.avoidFaces||e[23]!==$?(b=t.jsx(re,{checked:s.avoidFaces,onChange:$,children:"Keep words off faces"}),e[22]=s.avoidFaces,e[23]=$,e[24]=b):b=e[24];let N;e[25]!==l?(N=S=>l({avoidText:S}),e[25]=l,e[26]=N):N=e[26];let P;e[27]!==s.avoidText||e[28]!==N?(P=t.jsx(re,{checked:s.avoidText,onChange:N,children:"Keep words off on-screen text"}),e[27]=s.avoidText,e[28]=N,e[29]=P):P=e[29];let x;e[30]!==i||e[31]!==n?(x=t.jsx(re,{checked:n,onChange:i,children:"Show detected regions"}),e[30]=i,e[31]=n,e[32]=x):x=e[32];let k;e[33]!==o?(k=!o&&t.jsx("p",{className:"alive-hint alive-warning",children:"Face and text detection did not run, so stacks use the default columns. Set OPENAI_API_KEY and re-run the analysis."}),e[33]=o,e[34]=k):k=e[34];let M;e[35]!==b||e[36]!==P||e[37]!==x||e[38]!==k?(M=t.jsxs("div",{className:"alive-field",children:[w,b,P,x,k]}),e[35]=b,e[36]=P,e[37]=x,e[38]=k,e[39]=M):M=e[39];let D;e[40]===Symbol.for("react.memo_cache_sentinel")?(D=t.jsx("h4",{children:"Audio"}),e[40]=D):D=e[40];let O;e[41]!==l?(O=S=>l({energySizing:S}),e[41]=l,e[42]=O):O=e[42];let _;e[43]!==s.energySizing||e[44]!==O?(_=t.jsxs("div",{className:"alive-field",children:[D,t.jsx(re,{checked:s.energySizing,onChange:O,children:"Size words by vocal energy"})]}),e[43]=s.energySizing,e[44]=O,e[45]=_):_=e[45];let H;e[46]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("h4",{children:"Hit color"}),e[46]=H):H=e[46];let W;e[47]!==l||e[48]!==s.hitColor?(W=Ge.map(S=>t.jsx("button",{type:"button","aria-label":S.name,"aria-pressed":s.hitColor.toUpperCase()===S.color,onClick:()=>l({hitColor:S.color}),children:t.jsx("span",{style:{background:S.color}})},S.color)),e[47]=l,e[48]=s.hitColor,e[49]=W):W=e[49];let R;e[50]===Symbol.for("react.memo_cache_sentinel")?(R=t.jsx("span",{children:"Text"}),e[50]=R):R=e[50];let p;e[51]!==l?(p=S=>l({textColor:S.target.value.toUpperCase()}),e[51]=l,e[52]=p):p=e[52];let L;e[53]!==s.textColor||e[54]!==p?(L=t.jsxs("label",{className:"alive-color-input",children:[R,t.jsx("input",{type:"color",value:s.textColor,onChange:p})]}),e[53]=s.textColor,e[54]=p,e[55]=L):L=e[55];let I;e[56]!==W||e[57]!==L?(I=t.jsxs("div",{className:"alive-field",children:[H,t.jsxs("div",{className:"alive-swatches",children:[W,L]})]}),e[56]=W,e[57]=L,e[58]=I):I=e[58];let z;e[59]!==h||e[60]!==c?(z=t.jsx("div",{className:"alive-field",children:t.jsx("button",{type:"button",className:"alive-secondary",disabled:c,onClick:h,children:"Re-run analysis"})}),e[59]=h,e[60]=c,e[61]=z):z=e[61];let B;return e[62]!==M||e[63]!==_||e[64]!==I||e[65]!==z||e[66]!==j||e[67]!==y?(B=t.jsxs("section",{className:"alive-panel alive-settings","aria-label":"Caption settings",children:[j,y,M,_,I,z]}),e[62]=M,e[63]=_,e[64]=I,e[65]=z,e[66]=j,e[67]=y,e[68]=B):B=e[68],B}const Je=90;function U(a,e){return`${Math.max(0,a)/e*100}%`}function Qe(a,e,s){if(e.count===0)return`All ${s} words already sit on their vocal onsets`;if(a)return`${e.count} words snapped to their vocal onsets`;const n=e.minMs===e.maxMs?`${e.maxMs}`:`${e.minMs}–${e.maxMs}`;return`${e.count} words start ${n} ms off the vocal`}function Ze(a){const e=a>120?10:a>30?5:1,s=[];for(let n=0;n<=a;n+=e)s.push(n);return s}function et(a,e,s){const n=F.c(5),o=A.useRef(null);let c,l;return n[0]!==e||n[1]!==s||n[2]!==a?(c=()=>{const i=o.current;if(!i||!s)return;const h=a/e*i.scrollWidth;(h<i.scrollLeft||h>i.scrollLeft+i.clientWidth*.85)&&(i.scrollLeft=Math.max(0,h-i.clientWidth*.2))},l=[a,e,s],n[0]=e,n[1]=s,n[2]=a,n[3]=c,n[4]=l):(c=n[3],l=n[4]),A.useEffect(c,l),o}function tt(a){const e=F.c(105),{duration:s,fps:n,time:o,playing:c,envelope:l,rows:i,cues:h,activeCue:r,snapped:f,drift:m}=a,d=Math.max(s,.1),g=et(o,d,c);let u;e[0]!==a||e[1]!==d?(u=T=>{const E=T.currentTarget.getBoundingClientRect();a.onSeek((T.clientX-E.left)/E.width*d)},e[0]=a,e[1]=d,e[2]=u):u=e[2];const j=u;let v;e[3]!==a?(v=()=>a.onStep(-1),e[3]=a,e[4]=v):v=e[4];let C;e[5]===Symbol.for("react.memo_cache_sentinel")?(C=t.jsx(Le,{size:16}),e[5]=C):C=e[5];let y;e[6]!==v?(y=t.jsx("button",{type:"button","aria-label":"Previous frame",onClick:v,children:C}),e[6]=v,e[7]=y):y=e[7];const w=c?"Pause":"Play";let $;e[8]!==c?($=c?t.jsx(ze,{size:16}):t.jsx(Fe,{size:16}),e[8]=c,e[9]=$):$=e[9];let b;e[10]!==a.onTogglePlay||e[11]!==w||e[12]!==$?(b=t.jsx("button",{type:"button",className:"alive-play","aria-label":w,onClick:a.onTogglePlay,children:$}),e[10]=a.onTogglePlay,e[11]=w,e[12]=$,e[13]=b):b=e[13];let N;e[14]!==a?(N=()=>a.onStep(1),e[14]=a,e[15]=N):N=e[15];let P;e[16]===Symbol.for("react.memo_cache_sentinel")?(P=t.jsx(He,{size:16}),e[16]=P):P=e[16];let x;e[17]!==N?(x=t.jsx("button",{type:"button","aria-label":"Next frame",onClick:N,children:P}),e[17]=N,e[18]=x):x=e[18];let k;e[19]!==o?(k=de(o),e[19]=o,e[20]=k):k=e[20];let M;e[21]!==k?(M=t.jsx("strong",{className:"alive-clock",children:k}),e[21]=k,e[22]=M):M=e[22];const D=Math.floor(o*n),O=Math.floor(d*n);let _;e[23]!==D||e[24]!==O?(_=t.jsxs("span",{className:"alive-muted",children:["frame ",D," / ",O]}),e[23]=D,e[24]=O,e[25]=_):_=e[25];let H;e[26]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("span",{className:"alive-spacer"}),e[26]=H):H=e[26];const W=m.count>0&&!f||void 0;let R;e[27]!==m||e[28]!==i.length||e[29]!==f?(R=Qe(f,m,i.length),e[27]=m,e[28]=i.length,e[29]=f,e[30]=R):R=e[30];let p;e[31]!==W||e[32]!==R?(p=t.jsx("span",{className:"alive-drift","data-drifted":W,children:R}),e[31]=W,e[32]=R,e[33]=p):p=e[33];const L=f?"alive-secondary":"alive-primary alive-warn",I=m.count===0,z=f?"Use transcript timing":"Snap words to audio";let B;e[34]!==a.onToggleSnap||e[35]!==L||e[36]!==I||e[37]!==z?(B=t.jsx("button",{type:"button",className:L,disabled:I,onClick:a.onToggleSnap,children:z}),e[34]=a.onToggleSnap,e[35]=L,e[36]=I,e[37]=z,e[38]=B):B=e[38];let S;e[39]!==M||e[40]!==_||e[41]!==p||e[42]!==B||e[43]!==y||e[44]!==b||e[45]!==x?(S=t.jsxs("div",{className:"alive-transport",children:[y,b,x,M,_,H,p,B]}),e[39]=M,e[40]=_,e[41]=p,e[42]=B,e[43]=y,e[44]=b,e[45]=x,e[46]=S):S=e[46];let ne;e[47]===Symbol.for("react.memo_cache_sentinel")?(ne=t.jsxs("div",{className:"alive-lane-labels","aria-hidden":"true",children:[t.jsx("span",{className:"alive-lane-ruler"}),t.jsx("span",{className:"alive-lane-audio",children:"Audio"}),t.jsx("span",{className:"alive-lane-words",children:"Words"}),t.jsx("span",{className:"alive-lane-stacks",children:"Stacks"})]}),e[47]=ne):ne=e[47];const he=d*Je;let K;e[48]!==he?(K={minWidth:he},e[48]=he,e[49]=K):K=e[49];let V;e[50]!==d?(V=Ze(d).map(T=>t.jsxs("span",{style:{left:U(T,d)},children:[T,"s"]},T)),e[50]=d,e[51]=V):V=e[51];let G;e[52]!==V?(G=t.jsx("div",{className:"alive-lane-ruler",children:V}),e[52]=V,e[53]=G):G=e[53];let X;e[54]!==l?(X=Te(l),e[54]=l,e[55]=X):X=e[55];let q;e[56]!==X?(q=t.jsx("svg",{viewBox:"0 0 1000 100",preserveAspectRatio:"none","aria-hidden":"true",children:t.jsx("path",{d:X})}),e[56]=X,e[57]=q):q=e[57];let Y;e[58]!==i||e[59]!==d||e[60]!==f?(Y=!f&&i.filter(st).map(T=>t.jsx("span",{className:"alive-onset",style:{left:U(T.onset,d)}},T.key)),e[58]=i,e[59]=d,e[60]=f,e[61]=Y):Y=e[61];let J;e[62]!==q||e[63]!==Y?(J=t.jsxs("div",{className:"alive-lane-audio",children:[q,Y]}),e[62]=q,e[63]=Y,e[64]=J):J=e[64];let Q;if(e[65]!==i||e[66]!==d||e[67]!==f||e[68]!==o){let T;e[70]!==d||e[71]!==f||e[72]!==o?(T=E=>t.jsx("span",{className:"alive-chip","data-active":o>=E.start&&o<E.end||void 0,"data-drifted":E.drifted&&!f||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:E.text},E.key),e[70]=d,e[71]=f,e[72]=o,e[73]=T):T=e[73],Q=i.map(T),e[65]=i,e[66]=d,e[67]=f,e[68]=o,e[69]=Q}else Q=e[69];let Z;e[74]!==Q?(Z=t.jsx("div",{className:"alive-lane-words",children:Q}),e[74]=Q,e[75]=Z):Z=e[75];let ee;if(e[76]!==r||e[77]!==h||e[78]!==d){let T;e[80]!==r||e[81]!==d?(T=(E,ye)=>t.jsx("span",{className:"alive-stack-bar","data-active":ye===r||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:me(E)},E.id),e[80]=r,e[81]=d,e[82]=T):T=e[82],ee=h.map(T),e[76]=r,e[77]=h,e[78]=d,e[79]=ee}else ee=e[79];let te;e[83]!==ee?(te=t.jsx("div",{className:"alive-lane-stacks",children:ee}),e[83]=ee,e[84]=te):te=e[84];let se;e[85]!==d||e[86]!==o?(se=U(o,d),e[85]=d,e[86]=o,e[87]=se):se=e[87];let le;e[88]!==se?(le=t.jsx("span",{className:"alive-playhead",style:{left:se}}),e[88]=se,e[89]=le):le=e[89];let ae;e[90]!==j||e[91]!==K||e[92]!==G||e[93]!==J||e[94]!==Z||e[95]!==te||e[96]!==le?(ae=t.jsxs("div",{className:"alive-lane-tracks",style:K,onClick:j,role:"presentation",children:[G,J,Z,te,le]}),e[90]=j,e[91]=K,e[92]=G,e[93]=J,e[94]=Z,e[95]=te,e[96]=le,e[97]=ae):ae=e[97];let ie;e[98]!==g||e[99]!==ae?(ie=t.jsxs("div",{className:"alive-lanes",children:[ne,t.jsx("div",{className:"alive-lane-scroll",ref:g,children:ae})]}),e[98]=g,e[99]=ae,e[100]=ie):ie=e[100];let oe;e[101]===Symbol.for("react.memo_cache_sentinel")?(oe=t.jsxs("div",{className:"alive-legend","aria-hidden":"true",children:[t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-chip"}),"Transcript word"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-drift"}),"Word off its vocal onset"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-onset"}),"Detected vocal onset"]})]}),e[101]=oe):oe=e[101];let ce;return e[102]!==S||e[103]!==ie?(ce=t.jsxs("section",{className:"alive-panel alive-timeline","aria-label":"Caption timeline",children:[S,ie,oe]}),e[102]=S,e[103]=ie,e[104]=ce):ce=e[104],ce}function st(a){return a.drifted}const ge=30;function lt(a){const e=F.c(3),s=A.useRef(null);let n,o;return e[0]!==a?(n=()=>{const c=s.current;return c?.showModal(),c?.querySelector(".alive-close")?.focus(),()=>{c?.close(),We(a)}},o=[a],e[0]=a,e[1]=n,e[2]=o):(n=e[1],o=e[2]),A.useEffect(n,o),s}function at(a){const e=F.c(6),[s,n]=A.useState(0),[o,c]=A.useState(!1);let l,i;e[0]!==a?(l=()=>{const r=a.current;if(!r)return;const f=g=>n(g.detail.frame),m=()=>c(!0),d=()=>c(!1);return r.addEventListener("frameupdate",f),r.addEventListener("play",m),r.addEventListener("pause",d),()=>{r.removeEventListener("frameupdate",f),r.removeEventListener("play",m),r.removeEventListener("pause",d)}},i=[a],e[0]=a,e[1]=l,e[2]=i):(l=e[1],i=e[2]),A.useEffect(l,i);let h;return e[3]!==s||e[4]!==o?(h={frame:s,playing:o},e[3]=s,e[4]=o,e[5]=h):h=e[5],h}function ft(a){const e=F.c(14),{asset:s,state:n,returnFocus:o,onClose:c}=a,l=lt(o),i=`Alive captions for ${s.label}`;let h;e[0]!==c?(h=m=>{m.preventDefault(),c()},e[0]=c,e[1]=h):h=e[1];let r;e[2]!==s.label||e[3]!==c||e[4]!==a||e[5]!==n.data||e[6]!==n.message||e[7]!==n.status?(r=n.status==="ready"?t.jsx(it,{...a,data:n.data}):t.jsxs("div",{className:"alive-studio-message",children:[t.jsx(je,{label:s.label,detail:null,onClose:c}),t.jsx("p",{role:n.status==="error"?"alert":"status",children:n.status==="error"?n.message:"Analysing vocals, phrases and faces…"})]}),e[2]=s.label,e[3]=c,e[4]=a,e[5]=n.data,e[6]=n.message,e[7]=n.status,e[8]=r):r=e[8];let f;return e[9]!==l||e[10]!==i||e[11]!==h||e[12]!==r?(f=t.jsx("dialog",{className:"alive-studio","aria-label":i,onCancel:h,ref:l,children:r}),e[9]=l,e[10]=i,e[11]=h,e[12]=r,e[13]=f):f=e[13],f}function je(a){const e=F.c(12),{label:s,detail:n,onClose:o,children:c}=a;let l;e[0]===Symbol.for("react.memo_cache_sentinel")?(l=t.jsx("h2",{children:"Alive captions"}),e[0]=l):l=e[0];const i=n?` · ${n}`:"";let h;e[1]!==s||e[2]!==i?(h=t.jsxs("span",{className:"alive-muted",children:[s,i]}),e[1]=s,e[2]=i,e[3]=h):h=e[3];let r;e[4]===Symbol.for("react.memo_cache_sentinel")?(r=t.jsx("span",{className:"alive-spacer"}),e[4]=r):r=e[4];let f;e[5]===Symbol.for("react.memo_cache_sentinel")?(f=t.jsx(Ie,{size:16}),e[5]=f):f=e[5];let m;e[6]!==o?(m=t.jsx("button",{type:"button",className:"alive-close","aria-label":"Close alive captions",onClick:o,children:f}),e[6]=o,e[7]=m):m=e[7];let d;return e[8]!==c||e[9]!==h||e[10]!==m?(d=t.jsxs("header",{className:"alive-header",children:[l,h,r,c,m]}),e[8]=c,e[9]=h,e[10]=m,e[11]=d):d=e[11],d}function it({asset:a,data:e,onClose:s,onSave:n,onRender:o,onReanalyze:c}){const{analysis:l}=e,i=Math.round(a.fps??ge)||ge,h=Math.max(1,Math.round(l.durationSeconds*i)),[r,f]=A.useState(e.settings),[m,d]=A.useState(()=>Re(a.width,a.height)),[g,u]=A.useState(!0),[j,v]=A.useState(null),[C,y]=A.useState(null),w=A.useRef(null),{frame:$,playing:b}=at(w),N=$/i,P=A.useMemo(()=>Ae(l,m),[l,m]),x=A.useMemo(()=>Me(l.phrases,r,P),[l.phrases,r,P]),k=A.useMemo(()=>_e(l,r),[l,r]),M=A.useMemo(()=>Ee(k),[k]),D=A.useMemo(()=>({mediaUrl:a.mediaUrl,sourceWidth:l.sourceWidth,sourceHeight:l.sourceHeight,cues:x,phrases:l.phrases,settings:r,showRegions:g}),[a.mediaUrl,l,x,r,g]),O=Oe(x,N),_=p=>w.current?.seekTo(Math.max(0,Math.min(h-1,Math.round(p*i)))),H=p=>f(L=>({...L,...p})),W=async(p,L,I)=>{v(p),y(null);try{await L(),y(I)}catch(z){y(z instanceof Error?z.message:String(z))}finally{v(null)}},R=fe.find(p=>p.id===m)??fe[0];return t.jsxs("div",{className:"alive-studio-body",children:[t.jsxs(je,{label:a.label,detail:`${l.sourceWidth}×${l.sourceHeight} · ${i} fps`,onClose:s,children:[t.jsx("div",{className:"alive-segmented",role:"group","aria-label":"Preview orientation",children:fe.map(p=>t.jsx("button",{type:"button","aria-pressed":p.id===m,onClick:()=>d(p.id),children:p.label},p.id))}),t.jsx("button",{type:"button",className:"alive-secondary",disabled:j!==null,onClick:()=>{W("Saving",()=>n(r),"Saved. Renders of this video now use alive captions.")},children:"Save"}),t.jsxs("button",{type:"button",className:"alive-primary",disabled:j!==null,onClick:()=>{W("Rendering",()=>o(r,m),`Saved and queued a ${R.label} render.`)},children:["Render ",R.label]})]}),t.jsxs("div",{className:"alive-main",children:[t.jsx(qe,{rows:k,phraseLabels:x.map(me),activePhrase:O,time:N,snapped:r.snapToOnsets,onSeek:_}),t.jsxs("div",{className:"alive-stage",children:[t.jsx("div",{className:"alive-player",style:{aspectRatio:`${R.width} / ${R.height}`},children:t.jsx(Ne,{ref:w,component:Ke,inputProps:D,durationInFrames:h,fps:i,compositionWidth:R.width,compositionHeight:R.height,style:{width:"100%",height:"100%"},clickToPlay:!0,spaceKeyToPlayOrPause:!0})}),t.jsx("p",{className:"alive-status",role:"status",children:j?`${j}…`:C??(O>=0?`${me(x[O])} · ${x[O].lines.length} lines`:"Between phrases")})]}),t.jsx(Ye,{settings:r,showRegions:g,regionsAnalyzed:l.regionsAnalyzed,working:j!==null,onChange:H,onShowRegions:u,onReanalyze:()=>{W("Re-running analysis",c,"Analysis refreshed.")}})]}),t.jsx(tt,{duration:l.durationSeconds,fps:i,time:N,playing:b,envelope:l.envelope,rows:k,cues:x,activeCue:O,snapped:r.snapToOnsets,drift:M,onSeek:_,onStep:p=>_(N+p/i),onTogglePlay:()=>w.current?.toggle(),onToggleSnap:()=>H({snapToOnsets:!r.snapToOnsets})})]})}export{ft as AliveCaptionsStudio};
1
+ import{c as F,j as t,a as A}from"./vendor-react-Dj7D1fD4.js";import{u as be,a as pe,V as Se,A as xe,P as Ne}from"./vendor-remotion-CH1HXrlc.js";import{ed as Ce,ee as ke,ef as we,eg as $e,eh as Pe,ei as de,ej as Te,ek as me,el as Re,em as Ae,en as Me,eo as _e,ep as Ee,eq as Oe,er as fe,bw as We}from"./videobook-B5G0jMoi.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-CGqhCIXV.js";import"./vendor-yctIZ9Dz.js";import"./vendor-mcp-DQ7EusT9.js";const Be={face:"#63c7d8",text:"#f0a860",graphic:"#f0a860"};function De(a){const e=F.c(25),{phrase:s,cue:n,settings:o,sourceWidth:c,sourceHeight:l}=a,{width:i,height:h}=pe();let r,f,m,d;if(e[0]!==h||e[1]!==s.id||e[2]!==s.regions||e[3]!==o||e[4]!==l||e[5]!==c||e[6]!==i){const j={sourceWidth:c,sourceHeight:l,targetWidth:i,targetHeight:h};let v;e[11]!==s.regions||e[12]!==o?(v=new Set($e(s.regions,o)),e[11]=s.regions,e[12]=o,e[13]=v):v=e[13];const C=v;let y;e[14]!==i?(y=Math.round(i/480),e[14]=i,e[15]=y):y=e[15],f=Math.max(2,y),r=xe,e[16]===Symbol.for("react.memo_cache_sentinel")?(m={pointerEvents:"none"},e[16]=m):m=e[16],d=s.regions.map((w,$)=>{const b=Pe(w,j);return t.jsx("div",{style:{position:"absolute",left:b.x*i,top:b.y*h,width:b.width*i,height:b.height*h,border:`${f}px dashed ${Be[w.kind]}`,opacity:C.has(w)?1:.4,borderRadius:f*2}},`${s.id}-${$}`)}),e[0]=h,e[1]=s.id,e[2]=s.regions,e[3]=o,e[4]=l,e[5]=c,e[6]=i,e[7]=r,e[8]=f,e[9]=m,e[10]=d}else r=e[7],f=e[8],m=e[9],d=e[10];let g;e[17]!==n.column||e[18]!==f?(g=t.jsx(Ue,{column:n.column,stroke:f}),e[17]=n.column,e[18]=f,e[19]=g):g=e[19];let u;return e[20]!==r||e[21]!==m||e[22]!==d||e[23]!==g?(u=t.jsxs(r,{style:m,children:[d,g]}),e[20]=r,e[21]=m,e[22]=d,e[23]=g,e[24]=u):u=e[24],u}function Ue(a){const e=F.c(7),{column:s,stroke:n}=a,o=`${Math.max(1,n/2)}px dashed rgba(114, 231, 170, 0.6)`,c=n*2;let l;return e[0]!==s.height||e[1]!==s.width||e[2]!==s.x||e[3]!==s.y||e[4]!==o||e[5]!==c?(l=t.jsx("div",{style:{position:"absolute",left:s.x,top:s.y,width:s.width,height:s.height,border:o,borderRadius:c}}),e[0]=s.height,e[1]=s.width,e[2]=s.x,e[3]=s.y,e[4]=o,e[5]=c,e[6]=l):l=e[6],l}function Ke(a){const e=F.c(34),{mediaUrl:s,sourceWidth:n,sourceHeight:o,cues:c,phrases:l,settings:i,showRegions:h}=a,r=be(),{fps:f,width:m,height:d}=pe();let g;e[0]!==d||e[1]!==o||e[2]!==n||e[3]!==m?(g=ke({sourceWidth:n,sourceHeight:o,targetWidth:m,targetHeight:d}),e[0]=d,e[1]=o,e[2]=n,e[3]=m,e[4]=g):g=e[4];const u=g,j=r/f;let v;e[5]!==c||e[6]!==j?(v=Ce(c,j),e[5]=c,e[6]=j,e[7]=v):v=e[7];const C=v;let y;e[8]!==C||e[9]!==l?(y=C?l.find(M=>M.id===C.id):void 0,e[8]=C,e[9]=l,e[10]=y):y=e[10];const w=y;let $;e[11]===Symbol.for("react.memo_cache_sentinel")?($={background:"#000000"},e[11]=$):$=e[11];let b;e[12]!==u.height||e[13]!==u.width||e[14]!==u.x||e[15]!==u.y?(b={position:"absolute",left:u.x,top:u.y,width:u.width,height:u.height},e[12]=u.height,e[13]=u.width,e[14]=u.x,e[15]=u.y,e[16]=b):b=e[16];let N;e[17]!==s||e[18]!==b?(N=t.jsx(Se,{src:s,style:b}),e[17]=s,e[18]=b,e[19]=N):N=e[19];let P;e[20]!==C||e[21]!==w||e[22]!==i||e[23]!==h||e[24]!==o||e[25]!==n?(P=h&&C&&w&&t.jsx(De,{phrase:w,cue:C,settings:i,sourceWidth:n,sourceHeight:o}),e[20]=C,e[21]=w,e[22]=i,e[23]=h,e[24]=o,e[25]=n,e[26]=P):P=e[26];let p;e[27]!==c||e[28]!==i?(p=t.jsx(we,{cues:c,settings:i,strokeWidth:6,strokeColor:"#000000",shadowBlur:6,shadowOpacity:60}),e[27]=c,e[28]=i,e[29]=p):p=e[29];let k;return e[30]!==N||e[31]!==P||e[32]!==p?(k=t.jsxs(xe,{style:$,children:[N,P,p]}),e[30]=N,e[31]=P,e[32]=p,e[33]=k):k=e[33],k}const ue=[{id:"stack",label:"Stack",hint:"Words land one by one and build a stacked block beside the subject, each line sized to fill the column."},{id:"punch",label:"Punch",hint:"One word at a time, as big as the free space allows. Best on fast verses."},{id:"karaoke",label:"Karaoke",hint:"The whole stacked phrase shows dimmed and lights up word by word."}],Ve=[{id:"pop",label:"Pop"},{id:"slam",label:"Slam"},{id:"rise",label:"Rise"}],qe=[{name:"Green",color:"#72E7AA"},{name:"Pink",color:"#F0B9D0"},{name:"Cyan",color:"#63C7D8"},{name:"Amber",color:"#E7C372"}];function Ge(a,e){if(!a.drifted)return de(a.start);const s=a.driftMs>0?"+":"";return e?`${de(a.start)} · snapped`:`${de(a.start)} · ${s}${a.driftMs}ms`}function Xe(a){const e=F.c(21),{rows:s,phraseLabels:n,activePhrase:o,time:c,snapped:l,onSeek:i}=a;let h;e[0]===Symbol.for("react.memo_cache_sentinel")?(h=t.jsx("h3",{children:"Transcript"}),e[0]=h):h=e[0];let r;e[1]!==s.length?(r=t.jsxs("header",{className:"alive-panel-header",children:[h,t.jsxs("p",{children:[s.length," words · timed to the vocal"]})]}),e[1]=s.length,e[2]=r):r=e[2];let f;if(e[3]!==o||e[4]!==i||e[5]!==n||e[6]!==s||e[7]!==l||e[8]!==c){let g;e[10]!==o||e[11]!==i||e[12]!==s||e[13]!==l||e[14]!==c?(g=(u,j)=>t.jsxs("div",{className:"alive-phrase","data-active":j===o||void 0,children:[t.jsxs("div",{className:"alive-phrase-head",children:[t.jsxs("span",{children:["Phrase ",j+1]}),t.jsx("span",{children:u})]}),t.jsx("div",{className:"alive-phrase-words",children:s.filter(v=>v.phraseIndex===j).map(v=>t.jsxs("button",{type:"button",className:"alive-word","data-active":c>=v.start&&c<v.end||void 0,"data-drifted":v.drifted&&!l||void 0,onClick:()=>i(v.start+.03),children:[t.jsx("span",{children:v.text}),t.jsx("small",{children:Ge(v,l)})]},v.key))})]},`${j}-${u}`),e[10]=o,e[11]=i,e[12]=s,e[13]=l,e[14]=c,e[15]=g):g=e[15],f=n.map(g),e[3]=o,e[4]=i,e[5]=n,e[6]=s,e[7]=l,e[8]=c,e[9]=f}else f=e[9];let m;e[16]!==f?(m=t.jsx("div",{className:"alive-transcript-list",children:f}),e[16]=f,e[17]=m):m=e[17];let d;return e[18]!==r||e[19]!==m?(d=t.jsxs("section",{className:"alive-panel alive-transcript","aria-label":"Transcript",children:[r,m]}),e[18]=r,e[19]=m,e[20]=d):d=e[20],d}function ve(a){const e=F.c(10),{label:s,options:n,value:o,onChange:c}=a;let l;if(e[0]!==c||e[1]!==n||e[2]!==o){let h;e[4]!==c||e[5]!==o?(h=r=>t.jsx("button",{type:"button","aria-pressed":r.id===o,onClick:()=>c(r.id),children:r.label},r.id),e[4]=c,e[5]=o,e[6]=h):h=e[6],l=n.map(h),e[0]=c,e[1]=n,e[2]=o,e[3]=l}else l=e[3];let i;return e[7]!==s||e[8]!==l?(i=t.jsx("div",{className:"alive-segmented",role:"group","aria-label":s,children:l}),e[7]=s,e[8]=l,e[9]=i):i=e[9],i}function re(a){const e=F.c(8),{checked:s,onChange:n,children:o}=a;let c;e[0]!==n?(c=h=>n(h.target.checked),e[0]=n,e[1]=c):c=e[1];let l;e[2]!==s||e[3]!==c?(l=t.jsx("input",{type:"checkbox",checked:s,onChange:c}),e[2]=s,e[3]=c,e[4]=l):l=e[4];let i;return e[5]!==o||e[6]!==l?(i=t.jsxs("label",{className:"alive-toggle",children:[l,o]}),e[5]=o,e[6]=l,e[7]=i):i=e[7],i}function Ye(a){const e=F.c(69),{settings:s,showRegions:n,regionsAnalyzed:o,working:c,onChange:l,onShowRegions:i,onReanalyze:h}=a;let r;e[0]!==s.style?(r=ue.find(S=>S.id===s.style)?.hint,e[0]=s.style,e[1]=r):r=e[1];const f=r;let m;e[2]===Symbol.for("react.memo_cache_sentinel")?(m=t.jsx("h4",{children:"Style"}),e[2]=m):m=e[2];let d;e[3]!==l?(d=S=>l({style:S}),e[3]=l,e[4]=d):d=e[4];let g;e[5]!==s.style||e[6]!==d?(g=t.jsx(ve,{label:"Caption style",options:ue,value:s.style,onChange:d}),e[5]=s.style,e[6]=d,e[7]=g):g=e[7];let u;e[8]!==f?(u=t.jsx("p",{className:"alive-hint",children:f}),e[8]=f,e[9]=u):u=e[9];let j;e[10]!==g||e[11]!==u?(j=t.jsxs("div",{className:"alive-field",children:[m,g,u]}),e[10]=g,e[11]=u,e[12]=j):j=e[12];let v;e[13]===Symbol.for("react.memo_cache_sentinel")?(v=t.jsx("h4",{children:"Word entrance"}),e[13]=v):v=e[13];let C;e[14]!==l?(C=S=>l({motion:S}),e[14]=l,e[15]=C):C=e[15];let y;e[16]!==s.motion||e[17]!==C?(y=t.jsxs("div",{className:"alive-field",children:[v,t.jsx(ve,{label:"Word entrance",options:Ve,value:s.motion,onChange:C})]}),e[16]=s.motion,e[17]=C,e[18]=y):y=e[18];let w;e[19]===Symbol.for("react.memo_cache_sentinel")?(w=t.jsx("h4",{children:"Frame awareness"}),e[19]=w):w=e[19];let $;e[20]!==l?($=S=>l({avoidFaces:S}),e[20]=l,e[21]=$):$=e[21];let b;e[22]!==s.avoidFaces||e[23]!==$?(b=t.jsx(re,{checked:s.avoidFaces,onChange:$,children:"Keep words off faces"}),e[22]=s.avoidFaces,e[23]=$,e[24]=b):b=e[24];let N;e[25]!==l?(N=S=>l({avoidText:S}),e[25]=l,e[26]=N):N=e[26];let P;e[27]!==s.avoidText||e[28]!==N?(P=t.jsx(re,{checked:s.avoidText,onChange:N,children:"Keep words off on-screen text"}),e[27]=s.avoidText,e[28]=N,e[29]=P):P=e[29];let p;e[30]!==i||e[31]!==n?(p=t.jsx(re,{checked:n,onChange:i,children:"Show detected regions"}),e[30]=i,e[31]=n,e[32]=p):p=e[32];let k;e[33]!==o?(k=!o&&t.jsx("p",{className:"alive-hint alive-warning",children:"Face and text detection did not run, so stacks use the default columns. Set OPENAI_API_KEY and re-run the analysis."}),e[33]=o,e[34]=k):k=e[34];let M;e[35]!==b||e[36]!==P||e[37]!==p||e[38]!==k?(M=t.jsxs("div",{className:"alive-field",children:[w,b,P,p,k]}),e[35]=b,e[36]=P,e[37]=p,e[38]=k,e[39]=M):M=e[39];let D;e[40]===Symbol.for("react.memo_cache_sentinel")?(D=t.jsx("h4",{children:"Audio"}),e[40]=D):D=e[40];let O;e[41]!==l?(O=S=>l({energySizing:S}),e[41]=l,e[42]=O):O=e[42];let _;e[43]!==s.energySizing||e[44]!==O?(_=t.jsxs("div",{className:"alive-field",children:[D,t.jsx(re,{checked:s.energySizing,onChange:O,children:"Size words by vocal energy"})]}),e[43]=s.energySizing,e[44]=O,e[45]=_):_=e[45];let H;e[46]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("h4",{children:"Hit color"}),e[46]=H):H=e[46];let W;e[47]!==l||e[48]!==s.hitColor?(W=qe.map(S=>t.jsx("button",{type:"button","aria-label":S.name,"aria-pressed":s.hitColor.toUpperCase()===S.color,onClick:()=>l({hitColor:S.color}),children:t.jsx("span",{style:{background:S.color}})},S.color)),e[47]=l,e[48]=s.hitColor,e[49]=W):W=e[49];let R;e[50]===Symbol.for("react.memo_cache_sentinel")?(R=t.jsx("span",{children:"Text"}),e[50]=R):R=e[50];let x;e[51]!==l?(x=S=>l({textColor:S.target.value.toUpperCase()}),e[51]=l,e[52]=x):x=e[52];let L;e[53]!==s.textColor||e[54]!==x?(L=t.jsxs("label",{className:"alive-color-input",children:[R,t.jsx("input",{type:"color",value:s.textColor,onChange:x})]}),e[53]=s.textColor,e[54]=x,e[55]=L):L=e[55];let I;e[56]!==W||e[57]!==L?(I=t.jsxs("div",{className:"alive-field",children:[H,t.jsxs("div",{className:"alive-swatches",children:[W,L]})]}),e[56]=W,e[57]=L,e[58]=I):I=e[58];let z;e[59]!==h||e[60]!==c?(z=t.jsx("div",{className:"alive-field",children:t.jsx("button",{type:"button",className:"alive-secondary",disabled:c,onClick:h,children:"Re-run analysis"})}),e[59]=h,e[60]=c,e[61]=z):z=e[61];let B;return e[62]!==M||e[63]!==_||e[64]!==I||e[65]!==z||e[66]!==j||e[67]!==y?(B=t.jsxs("section",{className:"alive-panel alive-settings","aria-label":"Caption settings",children:[j,y,M,_,I,z]}),e[62]=M,e[63]=_,e[64]=I,e[65]=z,e[66]=j,e[67]=y,e[68]=B):B=e[68],B}const Je=90;function U(a,e){return`${Math.max(0,a)/e*100}%`}function Qe(a,e,s){if(e.count===0)return`All ${s} words already sit on their vocal onsets`;if(a)return`${e.count} words snapped to their vocal onsets`;const n=e.minMs===e.maxMs?`${e.maxMs}`:`${e.minMs}–${e.maxMs}`;return`${e.count} words start ${n} ms off the vocal`}function Ze(a){const e=a>120?10:a>30?5:1,s=[];for(let n=0;n<=a;n+=e)s.push(n);return s}function et(a,e,s){const n=F.c(5),o=A.useRef(null);let c,l;return n[0]!==e||n[1]!==s||n[2]!==a?(c=()=>{const i=o.current;if(!i||!s)return;const h=a/e*i.scrollWidth;(h<i.scrollLeft||h>i.scrollLeft+i.clientWidth*.85)&&(i.scrollLeft=Math.max(0,h-i.clientWidth*.2))},l=[a,e,s],n[0]=e,n[1]=s,n[2]=a,n[3]=c,n[4]=l):(c=n[3],l=n[4]),A.useEffect(c,l),o}function tt(a){const e=F.c(105),{duration:s,fps:n,time:o,playing:c,envelope:l,rows:i,cues:h,activeCue:r,snapped:f,drift:m}=a,d=Math.max(s,.1),g=et(o,d,c);let u;e[0]!==a||e[1]!==d?(u=T=>{const E=T.currentTarget.getBoundingClientRect();a.onSeek((T.clientX-E.left)/E.width*d)},e[0]=a,e[1]=d,e[2]=u):u=e[2];const j=u;let v;e[3]!==a?(v=()=>a.onStep(-1),e[3]=a,e[4]=v):v=e[4];let C;e[5]===Symbol.for("react.memo_cache_sentinel")?(C=t.jsx(Le,{size:16}),e[5]=C):C=e[5];let y;e[6]!==v?(y=t.jsx("button",{type:"button","aria-label":"Previous frame",onClick:v,children:C}),e[6]=v,e[7]=y):y=e[7];const w=c?"Pause":"Play";let $;e[8]!==c?($=c?t.jsx(ze,{size:16}):t.jsx(Fe,{size:16}),e[8]=c,e[9]=$):$=e[9];let b;e[10]!==a.onTogglePlay||e[11]!==w||e[12]!==$?(b=t.jsx("button",{type:"button",className:"alive-play","aria-label":w,onClick:a.onTogglePlay,children:$}),e[10]=a.onTogglePlay,e[11]=w,e[12]=$,e[13]=b):b=e[13];let N;e[14]!==a?(N=()=>a.onStep(1),e[14]=a,e[15]=N):N=e[15];let P;e[16]===Symbol.for("react.memo_cache_sentinel")?(P=t.jsx(He,{size:16}),e[16]=P):P=e[16];let p;e[17]!==N?(p=t.jsx("button",{type:"button","aria-label":"Next frame",onClick:N,children:P}),e[17]=N,e[18]=p):p=e[18];let k;e[19]!==o?(k=de(o),e[19]=o,e[20]=k):k=e[20];let M;e[21]!==k?(M=t.jsx("strong",{className:"alive-clock",children:k}),e[21]=k,e[22]=M):M=e[22];const D=Math.floor(o*n),O=Math.floor(d*n);let _;e[23]!==D||e[24]!==O?(_=t.jsxs("span",{className:"alive-muted",children:["frame ",D," / ",O]}),e[23]=D,e[24]=O,e[25]=_):_=e[25];let H;e[26]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("span",{className:"alive-spacer"}),e[26]=H):H=e[26];const W=m.count>0&&!f||void 0;let R;e[27]!==m||e[28]!==i.length||e[29]!==f?(R=Qe(f,m,i.length),e[27]=m,e[28]=i.length,e[29]=f,e[30]=R):R=e[30];let x;e[31]!==W||e[32]!==R?(x=t.jsx("span",{className:"alive-drift","data-drifted":W,children:R}),e[31]=W,e[32]=R,e[33]=x):x=e[33];const L=f?"alive-secondary":"alive-primary alive-warn",I=m.count===0,z=f?"Use transcript timing":"Snap words to audio";let B;e[34]!==a.onToggleSnap||e[35]!==L||e[36]!==I||e[37]!==z?(B=t.jsx("button",{type:"button",className:L,disabled:I,onClick:a.onToggleSnap,children:z}),e[34]=a.onToggleSnap,e[35]=L,e[36]=I,e[37]=z,e[38]=B):B=e[38];let S;e[39]!==M||e[40]!==_||e[41]!==x||e[42]!==B||e[43]!==y||e[44]!==b||e[45]!==p?(S=t.jsxs("div",{className:"alive-transport",children:[y,b,p,M,_,H,x,B]}),e[39]=M,e[40]=_,e[41]=x,e[42]=B,e[43]=y,e[44]=b,e[45]=p,e[46]=S):S=e[46];let ne;e[47]===Symbol.for("react.memo_cache_sentinel")?(ne=t.jsxs("div",{className:"alive-lane-labels","aria-hidden":"true",children:[t.jsx("span",{className:"alive-lane-ruler"}),t.jsx("span",{className:"alive-lane-audio",children:"Audio"}),t.jsx("span",{className:"alive-lane-words",children:"Words"}),t.jsx("span",{className:"alive-lane-stacks",children:"Stacks"})]}),e[47]=ne):ne=e[47];const he=d*Je;let K;e[48]!==he?(K={minWidth:he},e[48]=he,e[49]=K):K=e[49];let V;e[50]!==d?(V=Ze(d).map(T=>t.jsxs("span",{style:{left:U(T,d)},children:[T,"s"]},T)),e[50]=d,e[51]=V):V=e[51];let q;e[52]!==V?(q=t.jsx("div",{className:"alive-lane-ruler",children:V}),e[52]=V,e[53]=q):q=e[53];let G;e[54]!==l?(G=Te(l),e[54]=l,e[55]=G):G=e[55];let X;e[56]!==G?(X=t.jsx("svg",{viewBox:"0 0 1000 100",preserveAspectRatio:"none","aria-hidden":"true",children:t.jsx("path",{d:G})}),e[56]=G,e[57]=X):X=e[57];let Y;e[58]!==i||e[59]!==d||e[60]!==f?(Y=!f&&i.filter(st).map(T=>t.jsx("span",{className:"alive-onset",style:{left:U(T.onset,d)}},T.key)),e[58]=i,e[59]=d,e[60]=f,e[61]=Y):Y=e[61];let J;e[62]!==X||e[63]!==Y?(J=t.jsxs("div",{className:"alive-lane-audio",children:[X,Y]}),e[62]=X,e[63]=Y,e[64]=J):J=e[64];let Q;if(e[65]!==i||e[66]!==d||e[67]!==f||e[68]!==o){let T;e[70]!==d||e[71]!==f||e[72]!==o?(T=E=>t.jsx("span",{className:"alive-chip","data-active":o>=E.start&&o<E.end||void 0,"data-drifted":E.drifted&&!f||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:E.text},E.key),e[70]=d,e[71]=f,e[72]=o,e[73]=T):T=e[73],Q=i.map(T),e[65]=i,e[66]=d,e[67]=f,e[68]=o,e[69]=Q}else Q=e[69];let Z;e[74]!==Q?(Z=t.jsx("div",{className:"alive-lane-words",children:Q}),e[74]=Q,e[75]=Z):Z=e[75];let ee;if(e[76]!==r||e[77]!==h||e[78]!==d){let T;e[80]!==r||e[81]!==d?(T=(E,ye)=>t.jsx("span",{className:"alive-stack-bar","data-active":ye===r||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:me(E)},E.id),e[80]=r,e[81]=d,e[82]=T):T=e[82],ee=h.map(T),e[76]=r,e[77]=h,e[78]=d,e[79]=ee}else ee=e[79];let te;e[83]!==ee?(te=t.jsx("div",{className:"alive-lane-stacks",children:ee}),e[83]=ee,e[84]=te):te=e[84];let se;e[85]!==d||e[86]!==o?(se=U(o,d),e[85]=d,e[86]=o,e[87]=se):se=e[87];let le;e[88]!==se?(le=t.jsx("span",{className:"alive-playhead",style:{left:se}}),e[88]=se,e[89]=le):le=e[89];let ae;e[90]!==j||e[91]!==K||e[92]!==q||e[93]!==J||e[94]!==Z||e[95]!==te||e[96]!==le?(ae=t.jsxs("div",{className:"alive-lane-tracks",style:K,onClick:j,role:"presentation",children:[q,J,Z,te,le]}),e[90]=j,e[91]=K,e[92]=q,e[93]=J,e[94]=Z,e[95]=te,e[96]=le,e[97]=ae):ae=e[97];let ie;e[98]!==g||e[99]!==ae?(ie=t.jsxs("div",{className:"alive-lanes",children:[ne,t.jsx("div",{className:"alive-lane-scroll",ref:g,children:ae})]}),e[98]=g,e[99]=ae,e[100]=ie):ie=e[100];let oe;e[101]===Symbol.for("react.memo_cache_sentinel")?(oe=t.jsxs("div",{className:"alive-legend","aria-hidden":"true",children:[t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-chip"}),"Transcript word"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-drift"}),"Word off its vocal onset"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-onset"}),"Detected vocal onset"]})]}),e[101]=oe):oe=e[101];let ce;return e[102]!==S||e[103]!==ie?(ce=t.jsxs("section",{className:"alive-panel alive-timeline","aria-label":"Caption timeline",children:[S,ie,oe]}),e[102]=S,e[103]=ie,e[104]=ce):ce=e[104],ce}function st(a){return a.drifted}const ge=30;function lt(a){const e=F.c(3),s=A.useRef(null);let n,o;return e[0]!==a?(n=()=>{const c=s.current;return c?.showModal(),c?.querySelector(".alive-close")?.focus(),()=>{c?.close(),We(a)}},o=[a],e[0]=a,e[1]=n,e[2]=o):(n=e[1],o=e[2]),A.useEffect(n,o),s}function at(a){const e=F.c(6),[s,n]=A.useState(0),[o,c]=A.useState(!1);let l,i;e[0]!==a?(l=()=>{const r=a.current;if(!r)return;const f=g=>n(g.detail.frame),m=()=>c(!0),d=()=>c(!1);return r.addEventListener("frameupdate",f),r.addEventListener("play",m),r.addEventListener("pause",d),()=>{r.removeEventListener("frameupdate",f),r.removeEventListener("play",m),r.removeEventListener("pause",d)}},i=[a],e[0]=a,e[1]=l,e[2]=i):(l=e[1],i=e[2]),A.useEffect(l,i);let h;return e[3]!==s||e[4]!==o?(h={frame:s,playing:o},e[3]=s,e[4]=o,e[5]=h):h=e[5],h}function ft(a){const e=F.c(14),{asset:s,state:n,returnFocus:o,onClose:c}=a,l=lt(o),i=`Alive captions for ${s.label}`;let h;e[0]!==c?(h=m=>{m.preventDefault(),c()},e[0]=c,e[1]=h):h=e[1];let r;e[2]!==s.label||e[3]!==c||e[4]!==a||e[5]!==n.data||e[6]!==n.message||e[7]!==n.status?(r=n.status==="ready"?t.jsx(it,{...a,data:n.data}):t.jsxs("div",{className:"alive-studio-message",children:[t.jsx(je,{label:s.label,detail:null,onClose:c}),t.jsx("p",{role:n.status==="error"?"alert":"status",children:n.status==="error"?n.message:"Analysing vocals, phrases and faces…"})]}),e[2]=s.label,e[3]=c,e[4]=a,e[5]=n.data,e[6]=n.message,e[7]=n.status,e[8]=r):r=e[8];let f;return e[9]!==l||e[10]!==i||e[11]!==h||e[12]!==r?(f=t.jsx("dialog",{className:"alive-studio","aria-label":i,onCancel:h,ref:l,children:r}),e[9]=l,e[10]=i,e[11]=h,e[12]=r,e[13]=f):f=e[13],f}function je(a){const e=F.c(12),{label:s,detail:n,onClose:o,children:c}=a;let l;e[0]===Symbol.for("react.memo_cache_sentinel")?(l=t.jsx("h2",{children:"Alive captions"}),e[0]=l):l=e[0];const i=n?` · ${n}`:"";let h;e[1]!==s||e[2]!==i?(h=t.jsxs("span",{className:"alive-muted",children:[s,i]}),e[1]=s,e[2]=i,e[3]=h):h=e[3];let r;e[4]===Symbol.for("react.memo_cache_sentinel")?(r=t.jsx("span",{className:"alive-spacer"}),e[4]=r):r=e[4];let f;e[5]===Symbol.for("react.memo_cache_sentinel")?(f=t.jsx(Ie,{size:16}),e[5]=f):f=e[5];let m;e[6]!==o?(m=t.jsx("button",{type:"button",className:"alive-close","aria-label":"Close alive captions",onClick:o,children:f}),e[6]=o,e[7]=m):m=e[7];let d;return e[8]!==c||e[9]!==h||e[10]!==m?(d=t.jsxs("header",{className:"alive-header",children:[l,h,r,c,m]}),e[8]=c,e[9]=h,e[10]=m,e[11]=d):d=e[11],d}function it({asset:a,data:e,onClose:s,onSave:n,onRender:o,onReanalyze:c}){const{analysis:l}=e,i=Math.round(a.fps??ge)||ge,h=Math.max(1,Math.round(l.durationSeconds*i)),[r,f]=A.useState(e.settings),[m,d]=A.useState(()=>Re(a.width,a.height)),[g,u]=A.useState(!0),[j,v]=A.useState(null),[C,y]=A.useState(null),w=A.useRef(null),{frame:$,playing:b}=at(w),N=$/i,P=A.useMemo(()=>Ae(l,m),[l,m]),p=A.useMemo(()=>Me(l.phrases,r,P),[l.phrases,r,P]),k=A.useMemo(()=>_e(l,r),[l,r]),M=A.useMemo(()=>Ee(k),[k]),D=A.useMemo(()=>({mediaUrl:a.mediaUrl,sourceWidth:l.sourceWidth,sourceHeight:l.sourceHeight,cues:p,phrases:l.phrases,settings:r,showRegions:g}),[a.mediaUrl,l,p,r,g]),O=Oe(p,N),_=x=>w.current?.seekTo(Math.max(0,Math.min(h-1,Math.round(x*i)))),H=x=>f(L=>({...L,...x})),W=async(x,L,I)=>{v(x),y(null);try{await L(),y(I)}catch(z){y(z instanceof Error?z.message:String(z))}finally{v(null)}},R=fe.find(x=>x.id===m)??fe[0];return t.jsxs("div",{className:"alive-studio-body",children:[t.jsxs(je,{label:a.label,detail:`${l.sourceWidth}×${l.sourceHeight} · ${i} fps`,onClose:s,children:[t.jsx("div",{className:"alive-segmented",role:"group","aria-label":"Preview orientation",children:fe.map(x=>t.jsx("button",{type:"button","aria-pressed":x.id===m,onClick:()=>d(x.id),children:x.label},x.id))}),t.jsx("button",{type:"button",className:"alive-secondary",disabled:j!==null,onClick:()=>{W("Saving",()=>n(r),"Saved. Renders of this video now use alive captions.")},children:"Save"}),t.jsxs("button",{type:"button",className:"alive-primary",disabled:j!==null,onClick:()=>{W("Rendering",()=>o(r,m),`Saved and queued a ${R.label} render.`)},children:["Render ",R.label]})]}),t.jsxs("div",{className:"alive-main",children:[t.jsx(Xe,{rows:k,phraseLabels:p.map(me),activePhrase:O,time:N,snapped:r.snapToOnsets,onSeek:_}),t.jsxs("div",{className:"alive-stage",children:[t.jsx("div",{className:"alive-player",style:{aspectRatio:`${R.width} / ${R.height}`},children:t.jsx(Ne,{ref:w,component:Ke,inputProps:D,durationInFrames:h,fps:i,compositionWidth:R.width,compositionHeight:R.height,style:{width:"100%",height:"100%"},clickToPlay:!0,spaceKeyToPlayOrPause:!0})}),t.jsx("p",{className:"alive-status",role:"status",children:j?`${j}…`:C??(O>=0?`${me(p[O])} · ${p[O].lines.length} lines`:"Between phrases")})]}),t.jsx(Ye,{settings:r,showRegions:g,regionsAnalyzed:l.regionsAnalyzed,working:j!==null,onChange:H,onShowRegions:u,onReanalyze:()=>{W("Re-running analysis",c,"Analysis refreshed.")}})]}),t.jsx(tt,{duration:l.durationSeconds,fps:i,time:N,playing:b,envelope:l.envelope,rows:k,cues:p,activeCue:O,snapped:r.snapToOnsets,drift:M,onSeek:_,onStep:x=>_(N+x/i),onTogglePlay:()=>w.current?.toggle(),onToggleSnap:()=>H({snapToOnsets:!r.snapToOnsets})})]})}export{ft as AliveCaptionsStudio};