@cut-workbench/core 0.3.1 → 0.4.1

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 (67) hide show
  1. package/dist/chunks/{canvas-size-IzoEg2cq.cjs → canvas-size-DIABzEW2.cjs} +209 -302
  2. package/dist/chunks/canvas-size-DIABzEW2.cjs.map +1 -0
  3. package/dist/chunks/{canvas-size-iWL8zZPl.js → canvas-size-Dlnng74w.js} +168 -171
  4. package/dist/chunks/canvas-size-Dlnng74w.js.map +1 -0
  5. package/dist/chunks/id-CJsdlGei.js +35 -0
  6. package/dist/chunks/id-CJsdlGei.js.map +1 -0
  7. package/dist/chunks/id-DaCxD4-5.cjs +70 -0
  8. package/dist/chunks/id-DaCxD4-5.cjs.map +1 -0
  9. package/dist/chunks/rolldown-runtime-B2SfzNBj.cjs +17 -0
  10. package/dist/chunks/rolldown-runtime-D8jQpDG7.js +12 -0
  11. package/dist/chunks/{snap-CeYuTN6d.cjs → snap-Cfk15JVg.cjs} +3 -23
  12. package/dist/chunks/{snap-CeYuTN6d.cjs.map → snap-Cfk15JVg.cjs.map} +1 -1
  13. package/dist/chunks/{snap-Dc022smD.js → snap-DpkVPVJN.js} +3 -17
  14. package/dist/chunks/{snap-Dc022smD.js.map → snap-DpkVPVJN.js.map} +1 -1
  15. package/dist/chunks/srt-D539yJ-n.js +51 -0
  16. package/dist/chunks/srt-D539yJ-n.js.map +1 -0
  17. package/dist/chunks/srt-DaL36mXN.cjs +73 -0
  18. package/dist/chunks/srt-DaL36mXN.cjs.map +1 -0
  19. package/dist/chunks/thumbnails-DEjnao5r.cjs +81 -0
  20. package/dist/chunks/thumbnails-DEjnao5r.cjs.map +1 -0
  21. package/dist/chunks/thumbnails-qH0dX_Zs.js +64 -0
  22. package/dist/chunks/thumbnails-qH0dX_Zs.js.map +1 -0
  23. package/dist/chunks/time-CYEd91qN.cjs +196 -0
  24. package/dist/chunks/time-CYEd91qN.cjs.map +1 -0
  25. package/dist/chunks/time-ChF1GwCy.js +113 -0
  26. package/dist/chunks/time-ChF1GwCy.js.map +1 -0
  27. package/dist/chunks/{waveform-Bhvv2t7-.cjs → waveform-BYwDdKpC.cjs} +150 -31
  28. package/dist/chunks/waveform-BYwDdKpC.cjs.map +1 -0
  29. package/dist/chunks/{waveform-CWU8Fa-n.js → waveform-uyGNE01H.js} +111 -22
  30. package/dist/chunks/waveform-uyGNE01H.js.map +1 -0
  31. package/dist/editor/create-editor.d.ts +8 -106
  32. package/dist/editor/editor-store.d.ts +4 -0
  33. package/dist/editor/handle-types.d.ts +256 -0
  34. package/dist/engine/index.cjs +1185 -455
  35. package/dist/engine/index.cjs.map +1 -1
  36. package/dist/engine/index.d.ts +3 -0
  37. package/dist/engine/index.js +1169 -446
  38. package/dist/engine/index.js.map +1 -1
  39. package/dist/engine/webav/export-runner.d.ts +61 -0
  40. package/dist/engine/webav/exporter.d.ts +3 -1
  41. package/dist/engine/webav/import-files.d.ts +58 -0
  42. package/dist/engine/webav/import-pipeline.d.ts +23 -1
  43. package/dist/engine/webav/types.d.ts +15 -0
  44. package/dist/errors.d.ts +12 -0
  45. package/dist/export/types.d.ts +49 -0
  46. package/dist/index.cjs +83 -68
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.ts +6 -0
  49. package/dist/index.js +47 -43
  50. package/dist/index.js.map +1 -1
  51. package/dist/lib/error.d.ts +6 -0
  52. package/dist/media/thumbnails.d.ts +8 -0
  53. package/dist/ports/host-bridge.d.ts +7 -0
  54. package/dist/project/file-storage.d.ts +23 -0
  55. package/dist/project/schema.d.ts +16 -4
  56. package/dist/timeline/index.cjs +24 -19
  57. package/dist/timeline/index.d.ts +1 -0
  58. package/dist/timeline/index.js +4 -3
  59. package/dist/timeline/normalize.d.ts +28 -0
  60. package/dist/timeline/ops.d.ts +0 -4
  61. package/dist/timeline/snap.d.ts +0 -2
  62. package/dist/types.d.ts +14 -2
  63. package/package.json +3 -2
  64. package/dist/chunks/canvas-size-IzoEg2cq.cjs.map +0 -1
  65. package/dist/chunks/canvas-size-iWL8zZPl.js.map +0 -1
  66. package/dist/chunks/waveform-Bhvv2t7-.cjs.map +0 -1
  67. package/dist/chunks/waveform-CWU8Fa-n.js.map +0 -1
@@ -0,0 +1,196 @@
1
+ // src/timeline/time.ts
2
+ var US_PER_SECOND = 1e6;
3
+ var US_PER_MS = 1e3;
4
+ /** 秒 → 微秒 */
5
+ function secToUs(sec) {
6
+ return Math.round(sec * US_PER_SECOND);
7
+ }
8
+ /** 微秒 → 秒 */
9
+ function usToSec(us) {
10
+ return us / US_PER_SECOND;
11
+ }
12
+ /** 毫秒 → 微秒 */
13
+ function msToUs(ms) {
14
+ return Math.round(ms * US_PER_MS);
15
+ }
16
+ /** 微秒 → 毫秒 */
17
+ function usToMs(us) {
18
+ return Math.round(us / US_PER_MS);
19
+ }
20
+ /** 数字 → 微秒(用于从 DOM/WebAV 回调拿到的裸数字) */
21
+ function asUs(n) {
22
+ return Math.round(n);
23
+ }
24
+ /** 数字 → 像素 */
25
+ function asPx(n) {
26
+ return n;
27
+ }
28
+ /**
29
+ * 微秒 → 像素。
30
+ * @param us 时间(微秒)
31
+ * @param pxPerSecond 每秒对应多少像素
32
+ */
33
+ function usToPx(us, pxPerSecond) {
34
+ return us / US_PER_SECOND * pxPerSecond;
35
+ }
36
+ /**
37
+ * 像素 → 微秒。
38
+ * @param px 像素
39
+ * @param pxPerSecond 每秒对应多少像素
40
+ */
41
+ function pxToUs(px, pxPerSecond) {
42
+ return Math.round(px / pxPerSecond * US_PER_SECOND);
43
+ }
44
+ /** 微秒 → `HH:MM:SS.mmm` */
45
+ function formatTimecode(us, showMs = true) {
46
+ const totalMs = Math.floor(Math.max(0, us) / 1e3);
47
+ const ms = totalMs % 1e3;
48
+ const totalSec = Math.floor(totalMs / 1e3);
49
+ const sec = totalSec % 60;
50
+ const min = Math.floor(totalSec / 60) % 60;
51
+ const hour = Math.floor(totalSec / 3600);
52
+ const pad = (n, len = 2) => String(n).padStart(len, "0");
53
+ const base = `${pad(hour)}:${pad(min)}:${pad(sec)}`;
54
+ return showMs ? `${base}.${pad(ms, 3)}` : base;
55
+ }
56
+ /** 微秒 → `MM:SS` 或 `HH:MM:SS`,列表展示用 */
57
+ function formatDuration(us) {
58
+ if (!Number.isFinite(us)) return "∞";
59
+ const totalSec = Math.max(0, Math.round(us / US_PER_SECOND));
60
+ const sec = totalSec % 60;
61
+ const min = Math.floor(totalSec / 60) % 60;
62
+ const hour = Math.floor(totalSec / 3600);
63
+ const pad = (n) => String(n).padStart(2, "0");
64
+ return hour > 0 ? `${hour}:${pad(min)}:${pad(sec)}` : `${pad(min)}:${pad(sec)}`;
65
+ }
66
+ var TICK_STEPS_US = [
67
+ 1e5,
68
+ 2e5,
69
+ 5e5,
70
+ 1e6,
71
+ 2e6,
72
+ 5e6,
73
+ 1e7,
74
+ 15e6,
75
+ 3e7,
76
+ 6e7,
77
+ 12e7,
78
+ 3e8,
79
+ 6e8
80
+ ];
81
+ /**
82
+ * 根据缩放级别生成刻度尺。
83
+ *
84
+ * @param pxPerSecond 每秒像素
85
+ * @param viewportWidthPx 可视宽度(像素)
86
+ * @param scrollLeftPx 横向滚动偏移(像素)
87
+ * @returns 主刻度(带文字)与次刻度
88
+ */
89
+ function buildTicks(pxPerSecond, viewportWidthPx, scrollLeftPx = 0) {
90
+ const startUs = pxToUs(scrollLeftPx, pxPerSecond);
91
+ const endUs = pxToUs(scrollLeftPx + viewportWidthPx, pxPerSecond);
92
+ const minLabelSpacingPx = 72;
93
+ const step = TICK_STEPS_US.find((s) => usToPx(s, pxPerSecond) >= minLabelSpacingPx) ?? TICK_STEPS_US[TICK_STEPS_US.length - 1];
94
+ const minorStep = step / 5;
95
+ const first = Math.floor(startUs / step) * step;
96
+ const ticks = [];
97
+ for (let us = first; us <= endUs + step; us += minorStep) {
98
+ if (us < 0) continue;
99
+ ticks.push({
100
+ us,
101
+ px: usToPx(us, pxPerSecond),
102
+ major: us % step === 0
103
+ });
104
+ }
105
+ return ticks;
106
+ }
107
+ /** 保证值落在 [min, max] */
108
+ function clamp(value, min, max) {
109
+ return Math.min(max, Math.max(min, value));
110
+ }
111
+ Object.defineProperty(exports, "US_PER_MS", {
112
+ enumerable: true,
113
+ get: function() {
114
+ return US_PER_MS;
115
+ }
116
+ });
117
+ Object.defineProperty(exports, "US_PER_SECOND", {
118
+ enumerable: true,
119
+ get: function() {
120
+ return US_PER_SECOND;
121
+ }
122
+ });
123
+ Object.defineProperty(exports, "asPx", {
124
+ enumerable: true,
125
+ get: function() {
126
+ return asPx;
127
+ }
128
+ });
129
+ Object.defineProperty(exports, "asUs", {
130
+ enumerable: true,
131
+ get: function() {
132
+ return asUs;
133
+ }
134
+ });
135
+ Object.defineProperty(exports, "buildTicks", {
136
+ enumerable: true,
137
+ get: function() {
138
+ return buildTicks;
139
+ }
140
+ });
141
+ Object.defineProperty(exports, "clamp", {
142
+ enumerable: true,
143
+ get: function() {
144
+ return clamp;
145
+ }
146
+ });
147
+ Object.defineProperty(exports, "formatDuration", {
148
+ enumerable: true,
149
+ get: function() {
150
+ return formatDuration;
151
+ }
152
+ });
153
+ Object.defineProperty(exports, "formatTimecode", {
154
+ enumerable: true,
155
+ get: function() {
156
+ return formatTimecode;
157
+ }
158
+ });
159
+ Object.defineProperty(exports, "msToUs", {
160
+ enumerable: true,
161
+ get: function() {
162
+ return msToUs;
163
+ }
164
+ });
165
+ Object.defineProperty(exports, "pxToUs", {
166
+ enumerable: true,
167
+ get: function() {
168
+ return pxToUs;
169
+ }
170
+ });
171
+ Object.defineProperty(exports, "secToUs", {
172
+ enumerable: true,
173
+ get: function() {
174
+ return secToUs;
175
+ }
176
+ });
177
+ Object.defineProperty(exports, "usToMs", {
178
+ enumerable: true,
179
+ get: function() {
180
+ return usToMs;
181
+ }
182
+ });
183
+ Object.defineProperty(exports, "usToPx", {
184
+ enumerable: true,
185
+ get: function() {
186
+ return usToPx;
187
+ }
188
+ });
189
+ Object.defineProperty(exports, "usToSec", {
190
+ enumerable: true,
191
+ get: function() {
192
+ return usToSec;
193
+ }
194
+ });
195
+
196
+ //# sourceMappingURL=time-CYEd91qN.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-CYEd91qN.cjs","names":[],"sources":["../../src/timeline/time.ts"],"sourcesContent":["/**\n * 时间与像素的单位换算。\n *\n * 内部统一使用微秒(µs)。为避免中途混用毫秒/秒,这里定义 branded type:\n * - `Us` 微秒\n * - `Ms` 毫秒\n * - `Px` 像素\n *\n * 只在函数边界处做 cast,业务代码不允许出现裸 number 参与时间计算。\n */\n\ndeclare const usBrand: unique symbol\ndeclare const msBrand: unique symbol\ndeclare const pxBrand: unique symbol\n\nexport type Us = number & { readonly [usBrand]: true }\nexport type Ms = number & { readonly [msBrand]: true }\nexport type Px = number & { readonly [pxBrand]: true }\n\nexport const US_PER_SECOND = 1_000_000\nexport const US_PER_MS = 1_000\n\n/** 秒 → 微秒 */\nexport function secToUs(sec: number): Us {\n return Math.round(sec * US_PER_SECOND) as Us\n}\n\n/** 微秒 → 秒 */\nexport function usToSec(us: number): number {\n return us / US_PER_SECOND\n}\n\n/** 毫秒 → 微秒 */\nexport function msToUs(ms: number): Us {\n return Math.round(ms * US_PER_MS) as Us\n}\n\n/** 微秒 → 毫秒 */\nexport function usToMs(us: number): Ms {\n return Math.round(us / US_PER_MS) as Ms\n}\n\n/** 数字 → 微秒(用于从 DOM/WebAV 回调拿到的裸数字) */\nexport function asUs(n: number): Us {\n return Math.round(n) as Us\n}\n\n/** 数字 → 像素 */\nexport function asPx(n: number): Px {\n return n as Px\n}\n\n/**\n * 微秒 → 像素。\n * @param us 时间(微秒)\n * @param pxPerSecond 每秒对应多少像素\n */\nexport function usToPx(us: number, pxPerSecond: number): Px {\n return ((us / US_PER_SECOND) * pxPerSecond) as Px\n}\n\n/**\n * 像素 → 微秒。\n * @param px 像素\n * @param pxPerSecond 每秒对应多少像素\n */\nexport function pxToUs(px: number, pxPerSecond: number): Us {\n return Math.round((px / pxPerSecond) * US_PER_SECOND) as Us\n}\n\n/** 微秒 → `HH:MM:SS.mmm` */\nexport function formatTimecode(us: number, showMs = true): string {\n const safe = Math.max(0, us)\n const totalMs = Math.floor(safe / 1000)\n const ms = totalMs % 1000\n const totalSec = Math.floor(totalMs / 1000)\n const sec = totalSec % 60\n const min = Math.floor(totalSec / 60) % 60\n const hour = Math.floor(totalSec / 3600)\n const pad = (n: number, len = 2) => String(n).padStart(len, '0')\n const base = `${pad(hour)}:${pad(min)}:${pad(sec)}`\n return showMs ? `${base}.${pad(ms, 3)}` : base\n}\n\n/** 微秒 → `MM:SS` 或 `HH:MM:SS`,列表展示用 */\nexport function formatDuration(us: number): string {\n if (!Number.isFinite(us)) return '∞'\n const totalSec = Math.max(0, Math.round(us / US_PER_SECOND))\n const sec = totalSec % 60\n const min = Math.floor(totalSec / 60) % 60\n const hour = Math.floor(totalSec / 3600)\n const pad = (n: number) => String(n).padStart(2, '0')\n return hour > 0 ? `${hour}:${pad(min)}:${pad(sec)}` : `${pad(min)}:${pad(sec)}`\n}\n\nexport interface RulerTick {\n us: Us\n px: Px\n major: boolean\n}\n\nconst TICK_STEPS_US = [\n 100_000, 200_000, 500_000, 1_000_000, 2_000_000, 5_000_000, 10_000_000, 15_000_000,\n 30_000_000, 60_000_000, 120_000_000, 300_000_000, 600_000_000,\n]\n\n/**\n * 根据缩放级别生成刻度尺。\n *\n * @param pxPerSecond 每秒像素\n * @param viewportWidthPx 可视宽度(像素)\n * @param scrollLeftPx 横向滚动偏移(像素)\n * @returns 主刻度(带文字)与次刻度\n */\nexport function buildTicks(\n pxPerSecond: number,\n viewportWidthPx: number,\n scrollLeftPx = 0,\n): RulerTick[] {\n const startUs = pxToUs(scrollLeftPx, pxPerSecond)\n const endUs = pxToUs(scrollLeftPx + viewportWidthPx, pxPerSecond)\n const minLabelSpacingPx = 72\n const step =\n TICK_STEPS_US.find((s) => usToPx(s, pxPerSecond) >= minLabelSpacingPx) ??\n TICK_STEPS_US[TICK_STEPS_US.length - 1]\n const minorStep = step / 5\n const first = Math.floor(startUs / step) * step\n const ticks: RulerTick[] = []\n for (let us = first; us <= endUs + step; us += minorStep) {\n if (us < 0) continue\n ticks.push({\n us: us as Us,\n px: usToPx(us, pxPerSecond),\n major: us % step === 0,\n })\n }\n return ticks\n}\n\n/** 保证值落在 [min, max] */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n"],"mappings":";AAmBA,IAAa,gBAAgB;AAC7B,IAAa,YAAY;;AAGzB,SAAgB,QAAQ,KAAiB;CACvC,OAAO,KAAK,MAAM,MAAM,aAAa;AACvC;;AAGA,SAAgB,QAAQ,IAAoB;CAC1C,OAAO,KAAK;AACd;;AAGA,SAAgB,OAAO,IAAgB;CACrC,OAAO,KAAK,MAAM,KAAK,SAAS;AAClC;;AAGA,SAAgB,OAAO,IAAgB;CACrC,OAAO,KAAK,MAAM,KAAK,SAAS;AAClC;;AAGA,SAAgB,KAAK,GAAe;CAClC,OAAO,KAAK,MAAM,CAAC;AACrB;;AAGA,SAAgB,KAAK,GAAe;CAClC,OAAO;AACT;;;;;;AAOA,SAAgB,OAAO,IAAY,aAAyB;CAC1D,OAAS,KAAK,gBAAiB;AACjC;;;;;;AAOA,SAAgB,OAAO,IAAY,aAAyB;CAC1D,OAAO,KAAK,MAAO,KAAK,cAAe,aAAa;AACtD;;AAGA,SAAgB,eAAe,IAAY,SAAS,MAAc;CAEhE,MAAM,UAAU,KAAK,MADR,KAAK,IAAI,GAAG,EACE,IAAO,GAAI;CACtC,MAAM,KAAK,UAAU;CACrB,MAAM,WAAW,KAAK,MAAM,UAAU,GAAI;CAC1C,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI;CACxC,MAAM,OAAO,KAAK,MAAM,WAAW,IAAI;CACvC,MAAM,OAAO,GAAW,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG;CAC/D,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG;CAChD,OAAO,SAAS,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM;AAC5C;;AAGA,SAAgB,eAAe,IAAoB;CACjD,IAAI,CAAC,OAAO,SAAS,EAAE,GAAG,OAAO;CACjC,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,aAAa,CAAC;CAC3D,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI;CACxC,MAAM,OAAO,KAAK,MAAM,WAAW,IAAI;CACvC,MAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;CACpD,OAAO,OAAO,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG;AAC9E;AAQA,IAAM,gBAAgB;CACpB;CAAS;CAAS;CAAS;CAAW;CAAW;CAAW;CAAY;CACxE;CAAY;CAAY;CAAa;CAAa;AACpD;;;;;;;;;AAUA,SAAgB,WACd,aACA,iBACA,eAAe,GACF;CACb,MAAM,UAAU,OAAO,cAAc,WAAW;CAChD,MAAM,QAAQ,OAAO,eAAe,iBAAiB,WAAW;CAChE,MAAM,oBAAoB;CAC1B,MAAM,OACJ,cAAc,MAAM,MAAM,OAAO,GAAG,WAAW,KAAK,iBAAiB,KACrE,cAAc,cAAc,SAAS;CACvC,MAAM,YAAY,OAAO;CACzB,MAAM,QAAQ,KAAK,MAAM,UAAU,IAAI,IAAI;CAC3C,MAAM,QAAqB,CAAC;CAC5B,KAAK,IAAI,KAAK,OAAO,MAAM,QAAQ,MAAM,MAAM,WAAW;EACxD,IAAI,KAAK,GAAG;EACZ,MAAM,KAAK;GACL;GACJ,IAAI,OAAO,IAAI,WAAW;GAC1B,OAAO,KAAK,SAAS;EACvB,CAAC;CACH;CACA,OAAO;AACT;;AAGA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C"}
@@ -0,0 +1,113 @@
1
+ // src/timeline/time.ts
2
+ var US_PER_SECOND = 1e6;
3
+ var US_PER_MS = 1e3;
4
+ /** 秒 → 微秒 */
5
+ function secToUs(sec) {
6
+ return Math.round(sec * US_PER_SECOND);
7
+ }
8
+ /** 微秒 → 秒 */
9
+ function usToSec(us) {
10
+ return us / US_PER_SECOND;
11
+ }
12
+ /** 毫秒 → 微秒 */
13
+ function msToUs(ms) {
14
+ return Math.round(ms * US_PER_MS);
15
+ }
16
+ /** 微秒 → 毫秒 */
17
+ function usToMs(us) {
18
+ return Math.round(us / US_PER_MS);
19
+ }
20
+ /** 数字 → 微秒(用于从 DOM/WebAV 回调拿到的裸数字) */
21
+ function asUs(n) {
22
+ return Math.round(n);
23
+ }
24
+ /** 数字 → 像素 */
25
+ function asPx(n) {
26
+ return n;
27
+ }
28
+ /**
29
+ * 微秒 → 像素。
30
+ * @param us 时间(微秒)
31
+ * @param pxPerSecond 每秒对应多少像素
32
+ */
33
+ function usToPx(us, pxPerSecond) {
34
+ return us / US_PER_SECOND * pxPerSecond;
35
+ }
36
+ /**
37
+ * 像素 → 微秒。
38
+ * @param px 像素
39
+ * @param pxPerSecond 每秒对应多少像素
40
+ */
41
+ function pxToUs(px, pxPerSecond) {
42
+ return Math.round(px / pxPerSecond * US_PER_SECOND);
43
+ }
44
+ /** 微秒 → `HH:MM:SS.mmm` */
45
+ function formatTimecode(us, showMs = true) {
46
+ const totalMs = Math.floor(Math.max(0, us) / 1e3);
47
+ const ms = totalMs % 1e3;
48
+ const totalSec = Math.floor(totalMs / 1e3);
49
+ const sec = totalSec % 60;
50
+ const min = Math.floor(totalSec / 60) % 60;
51
+ const hour = Math.floor(totalSec / 3600);
52
+ const pad = (n, len = 2) => String(n).padStart(len, "0");
53
+ const base = `${pad(hour)}:${pad(min)}:${pad(sec)}`;
54
+ return showMs ? `${base}.${pad(ms, 3)}` : base;
55
+ }
56
+ /** 微秒 → `MM:SS` 或 `HH:MM:SS`,列表展示用 */
57
+ function formatDuration(us) {
58
+ if (!Number.isFinite(us)) return "∞";
59
+ const totalSec = Math.max(0, Math.round(us / US_PER_SECOND));
60
+ const sec = totalSec % 60;
61
+ const min = Math.floor(totalSec / 60) % 60;
62
+ const hour = Math.floor(totalSec / 3600);
63
+ const pad = (n) => String(n).padStart(2, "0");
64
+ return hour > 0 ? `${hour}:${pad(min)}:${pad(sec)}` : `${pad(min)}:${pad(sec)}`;
65
+ }
66
+ var TICK_STEPS_US = [
67
+ 1e5,
68
+ 2e5,
69
+ 5e5,
70
+ 1e6,
71
+ 2e6,
72
+ 5e6,
73
+ 1e7,
74
+ 15e6,
75
+ 3e7,
76
+ 6e7,
77
+ 12e7,
78
+ 3e8,
79
+ 6e8
80
+ ];
81
+ /**
82
+ * 根据缩放级别生成刻度尺。
83
+ *
84
+ * @param pxPerSecond 每秒像素
85
+ * @param viewportWidthPx 可视宽度(像素)
86
+ * @param scrollLeftPx 横向滚动偏移(像素)
87
+ * @returns 主刻度(带文字)与次刻度
88
+ */
89
+ function buildTicks(pxPerSecond, viewportWidthPx, scrollLeftPx = 0) {
90
+ const startUs = pxToUs(scrollLeftPx, pxPerSecond);
91
+ const endUs = pxToUs(scrollLeftPx + viewportWidthPx, pxPerSecond);
92
+ const minLabelSpacingPx = 72;
93
+ const step = TICK_STEPS_US.find((s) => usToPx(s, pxPerSecond) >= minLabelSpacingPx) ?? TICK_STEPS_US[TICK_STEPS_US.length - 1];
94
+ const minorStep = step / 5;
95
+ const first = Math.floor(startUs / step) * step;
96
+ const ticks = [];
97
+ for (let us = first; us <= endUs + step; us += minorStep) {
98
+ if (us < 0) continue;
99
+ ticks.push({
100
+ us,
101
+ px: usToPx(us, pxPerSecond),
102
+ major: us % step === 0
103
+ });
104
+ }
105
+ return ticks;
106
+ }
107
+ /** 保证值落在 [min, max] */
108
+ function clamp(value, min, max) {
109
+ return Math.min(max, Math.max(min, value));
110
+ }
111
+ export { buildTicks as a, formatTimecode as c, secToUs as d, usToMs as f, asUs as i, msToUs as l, usToSec as m, US_PER_SECOND as n, clamp as o, usToPx as p, asPx as r, formatDuration as s, US_PER_MS as t, pxToUs as u };
112
+
113
+ //# sourceMappingURL=time-ChF1GwCy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-ChF1GwCy.js","names":[],"sources":["../../src/timeline/time.ts"],"sourcesContent":["/**\n * 时间与像素的单位换算。\n *\n * 内部统一使用微秒(µs)。为避免中途混用毫秒/秒,这里定义 branded type:\n * - `Us` 微秒\n * - `Ms` 毫秒\n * - `Px` 像素\n *\n * 只在函数边界处做 cast,业务代码不允许出现裸 number 参与时间计算。\n */\n\ndeclare const usBrand: unique symbol\ndeclare const msBrand: unique symbol\ndeclare const pxBrand: unique symbol\n\nexport type Us = number & { readonly [usBrand]: true }\nexport type Ms = number & { readonly [msBrand]: true }\nexport type Px = number & { readonly [pxBrand]: true }\n\nexport const US_PER_SECOND = 1_000_000\nexport const US_PER_MS = 1_000\n\n/** 秒 → 微秒 */\nexport function secToUs(sec: number): Us {\n return Math.round(sec * US_PER_SECOND) as Us\n}\n\n/** 微秒 → 秒 */\nexport function usToSec(us: number): number {\n return us / US_PER_SECOND\n}\n\n/** 毫秒 → 微秒 */\nexport function msToUs(ms: number): Us {\n return Math.round(ms * US_PER_MS) as Us\n}\n\n/** 微秒 → 毫秒 */\nexport function usToMs(us: number): Ms {\n return Math.round(us / US_PER_MS) as Ms\n}\n\n/** 数字 → 微秒(用于从 DOM/WebAV 回调拿到的裸数字) */\nexport function asUs(n: number): Us {\n return Math.round(n) as Us\n}\n\n/** 数字 → 像素 */\nexport function asPx(n: number): Px {\n return n as Px\n}\n\n/**\n * 微秒 → 像素。\n * @param us 时间(微秒)\n * @param pxPerSecond 每秒对应多少像素\n */\nexport function usToPx(us: number, pxPerSecond: number): Px {\n return ((us / US_PER_SECOND) * pxPerSecond) as Px\n}\n\n/**\n * 像素 → 微秒。\n * @param px 像素\n * @param pxPerSecond 每秒对应多少像素\n */\nexport function pxToUs(px: number, pxPerSecond: number): Us {\n return Math.round((px / pxPerSecond) * US_PER_SECOND) as Us\n}\n\n/** 微秒 → `HH:MM:SS.mmm` */\nexport function formatTimecode(us: number, showMs = true): string {\n const safe = Math.max(0, us)\n const totalMs = Math.floor(safe / 1000)\n const ms = totalMs % 1000\n const totalSec = Math.floor(totalMs / 1000)\n const sec = totalSec % 60\n const min = Math.floor(totalSec / 60) % 60\n const hour = Math.floor(totalSec / 3600)\n const pad = (n: number, len = 2) => String(n).padStart(len, '0')\n const base = `${pad(hour)}:${pad(min)}:${pad(sec)}`\n return showMs ? `${base}.${pad(ms, 3)}` : base\n}\n\n/** 微秒 → `MM:SS` 或 `HH:MM:SS`,列表展示用 */\nexport function formatDuration(us: number): string {\n if (!Number.isFinite(us)) return '∞'\n const totalSec = Math.max(0, Math.round(us / US_PER_SECOND))\n const sec = totalSec % 60\n const min = Math.floor(totalSec / 60) % 60\n const hour = Math.floor(totalSec / 3600)\n const pad = (n: number) => String(n).padStart(2, '0')\n return hour > 0 ? `${hour}:${pad(min)}:${pad(sec)}` : `${pad(min)}:${pad(sec)}`\n}\n\nexport interface RulerTick {\n us: Us\n px: Px\n major: boolean\n}\n\nconst TICK_STEPS_US = [\n 100_000, 200_000, 500_000, 1_000_000, 2_000_000, 5_000_000, 10_000_000, 15_000_000,\n 30_000_000, 60_000_000, 120_000_000, 300_000_000, 600_000_000,\n]\n\n/**\n * 根据缩放级别生成刻度尺。\n *\n * @param pxPerSecond 每秒像素\n * @param viewportWidthPx 可视宽度(像素)\n * @param scrollLeftPx 横向滚动偏移(像素)\n * @returns 主刻度(带文字)与次刻度\n */\nexport function buildTicks(\n pxPerSecond: number,\n viewportWidthPx: number,\n scrollLeftPx = 0,\n): RulerTick[] {\n const startUs = pxToUs(scrollLeftPx, pxPerSecond)\n const endUs = pxToUs(scrollLeftPx + viewportWidthPx, pxPerSecond)\n const minLabelSpacingPx = 72\n const step =\n TICK_STEPS_US.find((s) => usToPx(s, pxPerSecond) >= minLabelSpacingPx) ??\n TICK_STEPS_US[TICK_STEPS_US.length - 1]\n const minorStep = step / 5\n const first = Math.floor(startUs / step) * step\n const ticks: RulerTick[] = []\n for (let us = first; us <= endUs + step; us += minorStep) {\n if (us < 0) continue\n ticks.push({\n us: us as Us,\n px: usToPx(us, pxPerSecond),\n major: us % step === 0,\n })\n }\n return ticks\n}\n\n/** 保证值落在 [min, max] */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n"],"mappings":";AAmBA,IAAa,gBAAgB;AAC7B,IAAa,YAAY;;AAGzB,SAAgB,QAAQ,KAAiB;CACvC,OAAO,KAAK,MAAM,MAAM,aAAa;AACvC;;AAGA,SAAgB,QAAQ,IAAoB;CAC1C,OAAO,KAAK;AACd;;AAGA,SAAgB,OAAO,IAAgB;CACrC,OAAO,KAAK,MAAM,KAAK,SAAS;AAClC;;AAGA,SAAgB,OAAO,IAAgB;CACrC,OAAO,KAAK,MAAM,KAAK,SAAS;AAClC;;AAGA,SAAgB,KAAK,GAAe;CAClC,OAAO,KAAK,MAAM,CAAC;AACrB;;AAGA,SAAgB,KAAK,GAAe;CAClC,OAAO;AACT;;;;;;AAOA,SAAgB,OAAO,IAAY,aAAyB;CAC1D,OAAS,KAAK,gBAAiB;AACjC;;;;;;AAOA,SAAgB,OAAO,IAAY,aAAyB;CAC1D,OAAO,KAAK,MAAO,KAAK,cAAe,aAAa;AACtD;;AAGA,SAAgB,eAAe,IAAY,SAAS,MAAc;CAEhE,MAAM,UAAU,KAAK,MADR,KAAK,IAAI,GAAG,EACE,IAAO,GAAI;CACtC,MAAM,KAAK,UAAU;CACrB,MAAM,WAAW,KAAK,MAAM,UAAU,GAAI;CAC1C,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI;CACxC,MAAM,OAAO,KAAK,MAAM,WAAW,IAAI;CACvC,MAAM,OAAO,GAAW,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG;CAC/D,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG;CAChD,OAAO,SAAS,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM;AAC5C;;AAGA,SAAgB,eAAe,IAAoB;CACjD,IAAI,CAAC,OAAO,SAAS,EAAE,GAAG,OAAO;CACjC,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,aAAa,CAAC;CAC3D,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI;CACxC,MAAM,OAAO,KAAK,MAAM,WAAW,IAAI;CACvC,MAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;CACpD,OAAO,OAAO,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG;AAC9E;AAQA,IAAM,gBAAgB;CACpB;CAAS;CAAS;CAAS;CAAW;CAAW;CAAW;CAAY;CACxE;CAAY;CAAY;CAAa;CAAa;AACpD;;;;;;;;;AAUA,SAAgB,WACd,aACA,iBACA,eAAe,GACF;CACb,MAAM,UAAU,OAAO,cAAc,WAAW;CAChD,MAAM,QAAQ,OAAO,eAAe,iBAAiB,WAAW;CAChE,MAAM,oBAAoB;CAC1B,MAAM,OACJ,cAAc,MAAM,MAAM,OAAO,GAAG,WAAW,KAAK,iBAAiB,KACrE,cAAc,cAAc,SAAS;CACvC,MAAM,YAAY,OAAO;CACzB,MAAM,QAAQ,KAAK,MAAM,UAAU,IAAI,IAAI;CAC3C,MAAM,QAAqB,CAAC;CAC5B,KAAK,IAAI,KAAK,OAAO,MAAM,QAAQ,MAAM,MAAM,WAAW;EACxD,IAAI,KAAK,GAAG;EACZ,MAAM,KAAK;GACL;GACJ,IAAI,OAAO,IAAI,WAAW;GAC1B,OAAO,KAAK,SAAS;EACvB,CAAC;CACH;CACA,OAAO;AACT;;AAGA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C"}
@@ -1,19 +1,37 @@
1
- const require_canvas_size = require("./canvas-size-IzoEg2cq.cjs");
1
+ const require_id = require("./id-DaCxD4-5.cjs");
2
+ const require_time = require("./time-CYEd91qN.cjs");
3
+ const require_canvas_size = require("./canvas-size-DIABzEW2.cjs");
2
4
  let zustand_vanilla = require("zustand/vanilla");
3
5
  let immer = require("immer");
4
6
  // src/project/schema.ts
7
+ /**
8
+ * 生成可落盘的工程快照。
9
+ *
10
+ * ⚠️ 必须是**深拷贝**:返回值会交给宿主(写入本地 JSON / 走 IPC)。
11
+ * 若直接返回 store 里的对象引用,宿主对这些字段的任何改动都会反向污染编辑器状态,
12
+ * 异步写盘期间发生编辑也会让「存下去的内容」与「保存时刻的状态」不一致。
13
+ */
5
14
  function serializeProject(project, assets) {
6
15
  return {
7
16
  schemaVersion: 1,
8
17
  savedAt: Date.now(),
9
- project,
10
- assets: assets.map(stripRuntimeFields)
18
+ project: structuredClone(project),
19
+ assets: assets.map((asset) => stripRuntimeFields(asset))
11
20
  };
12
21
  }
13
- /** 去掉不可持久化 / 无意义的运行时字段 */
22
+ /**
23
+ * 去掉不可持久化 / 无意义的运行时字段。
24
+ *
25
+ * - `thumbnailUrls`:会话内的 `blob:` URL,刷新后必然失效 —— 存下来只会让
26
+ * 恢复后的卡片显示破图,不如不存(恢复时重抽);
27
+ * - `waveform`:纯派生数据,400 个浮点数 ≈ 4KB。一个 20 条素材的工程光波形
28
+ * 就多占 80KB,而找回源文件后重算一次即可。
29
+ *
30
+ * 其余字段(含宿主写入的 `sourcePath`)原样保留。
31
+ */
14
32
  function stripRuntimeFields(asset) {
15
- const { thumbnailUrls: _thumbnailUrls, ...rest } = asset;
16
- return { ...rest };
33
+ const { thumbnailUrls: _thumbnailUrls, waveform: _waveform, ...rest } = asset;
34
+ return structuredClone(rest);
17
35
  }
18
36
  var ProjectSchemaError = class extends Error {
19
37
  constructor(message) {
@@ -26,16 +44,18 @@ function deserializeProject(raw) {
26
44
  const data = raw;
27
45
  if (typeof data.schemaVersion !== "number") throw new ProjectSchemaError("工程缺少 schemaVersion,无法判断版本");
28
46
  if (data.schemaVersion > 1) throw new ProjectSchemaError(`工程版本 ${data.schemaVersion} 高于当前应用支持的 1,请升级应用`);
29
- const project = migrate(data.schemaVersion, data.project);
30
- if (project == null) throw new ProjectSchemaError("工程主体缺失");
31
- const assets = Array.isArray(data.assets) ? data.assets : [];
47
+ const migrated = migrate(data.schemaVersion, data.project);
48
+ if (migrated == null) throw new ProjectSchemaError("工程主体缺失");
49
+ const project = require_canvas_size.normalizeProject(migrated);
50
+ if (project == null) throw new ProjectSchemaError("工程结构无法识别");
51
+ const assets = (Array.isArray(data.assets) ? data.assets : []).map((asset) => require_canvas_size.normalizeAsset(asset)).filter((asset) => asset != null);
32
52
  const assetIds = new Set(assets.map((a) => a.id));
33
- const fileBacked = new Set(assets.filter((a) => a.kind === "video" || a.kind === "audio" || a.kind === "image").map((a) => a.id));
34
53
  const referenced = new Set(project.clips.map((c) => c.assetId));
54
+ const fileBacked = assets.filter((a) => (a.kind === "video" || a.kind === "audio" || a.kind === "image") && referenced.has(a.id));
35
55
  return {
36
56
  project,
37
57
  assets,
38
- missingAssetIds: Array.from(/* @__PURE__ */ new Set([...project.clips.map((c) => c.assetId).filter((id) => !assetIds.has(id)), ...Array.from(fileBacked).filter((id) => referenced.has(id))]))
58
+ missingAssetIds: Array.from(/* @__PURE__ */ new Set([...project.clips.map((c) => c.assetId).filter((id) => !assetIds.has(id)), ...fileBacked.map((a) => a.id)]))
39
59
  };
40
60
  }
41
61
  function migrate(version, project) {
@@ -188,6 +208,69 @@ function createWebBridge(options = {}) {
188
208
  }
189
209
  };
190
210
  }
211
+ // src/export/types.ts
212
+ /** 导出默认值:1080p / 30fps / 8Mbps / 含音轨 */
213
+ var DEFAULT_EXPORT_SETTINGS = {
214
+ preset: "1080p",
215
+ width: 1920,
216
+ height: 1080,
217
+ fps: 30,
218
+ bitrate: 8e6,
219
+ includeAudio: true
220
+ };
221
+ function even(n) {
222
+ return Math.max(2, Math.round(n / 2) * 2);
223
+ }
224
+ /**
225
+ * 把宿主传入的局部设置补全为完整设置。
226
+ *
227
+ * 只给了 `preset` 时按预设推导尺寸(`source` 取工程尺寸并向下对齐到偶数),
228
+ * 显式给了 `width` / `height` 则以显式值为准。
229
+ */
230
+ function resolveExportSettings(project, partial) {
231
+ const preset = partial?.preset ?? DEFAULT_EXPORT_SETTINGS.preset;
232
+ const presetSize = preset === "720p" ? {
233
+ width: 1280,
234
+ height: 720
235
+ } : preset === "1080p" ? {
236
+ width: 1920,
237
+ height: 1080
238
+ } : {
239
+ width: even(project.width),
240
+ height: even(project.height)
241
+ };
242
+ return {
243
+ preset,
244
+ width: partial?.width ?? presetSize.width,
245
+ height: partial?.height ?? presetSize.height,
246
+ fps: partial?.fps ?? DEFAULT_EXPORT_SETTINGS.fps,
247
+ bitrate: partial?.bitrate ?? DEFAULT_EXPORT_SETTINGS.bitrate,
248
+ includeAudio: partial?.includeAudio ?? DEFAULT_EXPORT_SETTINGS.includeAudio
249
+ };
250
+ }
251
+ /** 默认文件名(与编辑器无关,宿主可覆盖) */
252
+ function createExportFilename(date = /* @__PURE__ */ new Date()) {
253
+ const pad = (n) => String(n).padStart(2, "0");
254
+ return `cut-test-${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}.mp4`;
255
+ }
256
+ // src/errors.ts
257
+ /**
258
+ * 对外错误类型。
259
+ *
260
+ * 放在根入口(不依赖 WebAV / React),宿主可以 `instanceof` 判断后决定
261
+ * 是否弹错误框 —— 用户主动取消导出不是错误,不该被当成失败提示。
262
+ */
263
+ /** 导出被 `cancel()` 取消。 */
264
+ var ExportCancelledError = class extends Error {
265
+ constructor(message = "导出已取消") {
266
+ super(message);
267
+ this.name = "ExportCancelledError";
268
+ }
269
+ };
270
+ /** 判断任意异常是否是「用户取消导出」。 */
271
+ function isExportCancelled(error) {
272
+ return error instanceof ExportCancelledError;
273
+ }
191
274
  // src/capability.ts
192
275
  /**
193
276
  * 运行环境能力探测。
@@ -493,23 +576,17 @@ var immer$1 = immerImpl;
493
576
  function createEditorStore(options) {
494
577
  const history = options.history;
495
578
  return (0, zustand_vanilla.createStore)()(immer$1((set, get) => {
496
- /**
497
- * 在结构性变更前压栈(必须在 set 之前调用,拿到的是「变更前」的完整快照)。
498
- *
499
- * @param label 变更描述
500
- * @param mergeKey 合并键:连续同质操作(如拖动同一个滑块)在时间窗口内合并为一步撤销。
501
- * `record()` 内部只保留第一次的快照,因此一次拖动 = 一步 Ctrl+Z。
502
- */
579
+ /** 在结构性变更前压栈(必须在 set 之前调用,拿到的是「变更前」的完整快照) */
503
580
  function recordHistory(label, mergeKey) {
504
581
  const { project, assets } = get();
505
582
  history.getState().record({
506
583
  project: structuredClone(project),
507
584
  assets: structuredClone(assets),
508
585
  label
509
- }, {
586
+ }, mergeKey != null ? {
510
587
  label,
511
588
  mergeKey
512
- });
589
+ } : { label });
513
590
  }
514
591
  return {
515
592
  project: options.project ?? require_canvas_size.createEmptyProject(),
@@ -548,6 +625,18 @@ function createEditorStore(options) {
548
625
  draft.dirty = true;
549
626
  });
550
627
  },
628
+ setProjectId: (id) => {
629
+ if (id === get().project.id) return;
630
+ recordHistory("修改工程 ID");
631
+ set((draft) => {
632
+ draft.project.id = id;
633
+ draft.project.updatedAt = Date.now();
634
+ draft.dirty = true;
635
+ });
636
+ },
637
+ setMissingAssetIds: (ids) => set((draft) => {
638
+ draft.missingAssetIds = [...ids];
639
+ }),
551
640
  /**
552
641
  * 修改画布尺寸(比例)。
553
642
  *
@@ -666,7 +755,7 @@ function createEditorStore(options) {
666
755
  const clip = draft.project.clips.find((c) => c.id === clipId);
667
756
  if (!clip) return;
668
757
  clip.trackId = trackId;
669
- clip.startUs = require_canvas_size.asUs(Math.max(0, startUs));
758
+ clip.startUs = require_time.asUs(Math.max(0, startUs));
670
759
  draft.project.updatedAt = Date.now();
671
760
  draft.dirty = true;
672
761
  });
@@ -692,16 +781,16 @@ function createEditorStore(options) {
692
781
  const sourceOffset = Math.round(leftDuration * clip.playbackRate);
693
782
  const right = {
694
783
  ...structuredClone(clip),
695
- id: require_canvas_size.createId("clip"),
696
- startUs: require_canvas_size.asUs(atUs),
697
- durationUs: require_canvas_size.asUs(rightDuration),
698
- inPointUs: require_canvas_size.asUs(clip.inPointUs + sourceOffset),
699
- fadeInUs: require_canvas_size.asUs(Math.min(clip.fadeInUs, rightDuration))
784
+ id: require_id.createId("clip"),
785
+ startUs: require_time.asUs(atUs),
786
+ durationUs: require_time.asUs(rightDuration),
787
+ inPointUs: require_time.asUs(clip.inPointUs + sourceOffset),
788
+ fadeInUs: require_time.asUs(Math.min(clip.fadeInUs, rightDuration))
700
789
  };
701
790
  return {
702
791
  leftId: clip.id,
703
- leftDuration: require_canvas_size.asUs(leftDuration),
704
- leftFadeOut: require_canvas_size.asUs(Math.min(clip.fadeOutUs, leftDuration)),
792
+ leftDuration: require_time.asUs(leftDuration),
793
+ leftFadeOut: require_time.asUs(Math.min(clip.fadeOutUs, leftDuration)),
705
794
  right
706
795
  };
707
796
  });
@@ -727,7 +816,7 @@ function createEditorStore(options) {
727
816
  const ids = state.selectedClipIds;
728
817
  const created = [];
729
818
  if (ids.length === 0) return created;
730
- const pairs = require_canvas_size.duplicateClipsData(structuredClone(state.project.clips), ids, offsetUs, () => require_canvas_size.createId("clip"));
819
+ const pairs = require_canvas_size.duplicateClipsData(structuredClone(state.project.clips), ids, offsetUs, () => require_id.createId("clip"));
731
820
  recordHistory("复制片段");
732
821
  set((draft) => {
733
822
  for (const { sourceId, clip } of pairs) {
@@ -788,7 +877,7 @@ function createEditorStore(options) {
788
877
  draft.selectedAssetId = id;
789
878
  }),
790
879
  setPlayhead: (us) => set((draft) => {
791
- draft.playheadUs = require_canvas_size.asUs(Math.max(0, us));
880
+ draft.playheadUs = require_time.asUs(Math.max(0, us));
792
881
  }),
793
882
  setPlaying: (playing) => set((draft) => {
794
883
  draft.playing = playing;
@@ -894,12 +983,24 @@ function normalizeWaveform(peaks, length) {
894
983
  }
895
984
  return out;
896
985
  }
986
+ Object.defineProperty(exports, "DEFAULT_EXPORT_SETTINGS", {
987
+ enumerable: true,
988
+ get: function() {
989
+ return DEFAULT_EXPORT_SETTINGS;
990
+ }
991
+ });
897
992
  Object.defineProperty(exports, "ENGINE_DEPENDENCIES_INSTALL_COMMAND", {
898
993
  enumerable: true,
899
994
  get: function() {
900
995
  return ENGINE_DEPENDENCIES_INSTALL_COMMAND;
901
996
  }
902
997
  });
998
+ Object.defineProperty(exports, "ExportCancelledError", {
999
+ enumerable: true,
1000
+ get: function() {
1001
+ return ExportCancelledError;
1002
+ }
1003
+ });
903
1004
  Object.defineProperty(exports, "ProjectSchemaError", {
904
1005
  enumerable: true,
905
1006
  get: function() {
@@ -930,6 +1031,12 @@ Object.defineProperty(exports, "createEventBus", {
930
1031
  return createEventBus;
931
1032
  }
932
1033
  });
1034
+ Object.defineProperty(exports, "createExportFilename", {
1035
+ enumerable: true,
1036
+ get: function() {
1037
+ return createExportFilename;
1038
+ }
1039
+ });
933
1040
  Object.defineProperty(exports, "createHistoryStore", {
934
1041
  enumerable: true,
935
1042
  get: function() {
@@ -990,12 +1097,24 @@ Object.defineProperty(exports, "isEnvironmentUsable", {
990
1097
  return isEnvironmentUsable;
991
1098
  }
992
1099
  });
1100
+ Object.defineProperty(exports, "isExportCancelled", {
1101
+ enumerable: true,
1102
+ get: function() {
1103
+ return isExportCancelled;
1104
+ }
1105
+ });
993
1106
  Object.defineProperty(exports, "normalizeWaveform", {
994
1107
  enumerable: true,
995
1108
  get: function() {
996
1109
  return normalizeWaveform;
997
1110
  }
998
1111
  });
1112
+ Object.defineProperty(exports, "resolveExportSettings", {
1113
+ enumerable: true,
1114
+ get: function() {
1115
+ return resolveExportSettings;
1116
+ }
1117
+ });
999
1118
  Object.defineProperty(exports, "selectAssetById", {
1000
1119
  enumerable: true,
1001
1120
  get: function() {
@@ -1063,4 +1182,4 @@ Object.defineProperty(exports, "summarizeCapabilities", {
1063
1182
  }
1064
1183
  });
1065
1184
 
1066
- //# sourceMappingURL=waveform-Bhvv2t7-.cjs.map
1185
+ //# sourceMappingURL=waveform-BYwDdKpC.cjs.map