stillmade-sdk 0.1.49 → 0.1.51

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 (64) hide show
  1. package/AGENTS.md +6 -2
  2. package/AGENT_CONTROL.md +15 -0
  3. package/FRAME_VIEWS.md +30 -0
  4. package/INTERFACE_DESIGN.md +84 -7
  5. package/MODULES.md +2 -2
  6. package/PASTE_TO_LLM.md +26 -19
  7. package/SDK.md +180 -45
  8. package/UI_AESTHETIC.md +15 -0
  9. package/blocks/generate/package.js +1 -1
  10. package/blocks/generate/versions/1.1.0/package.js +471 -0
  11. package/blocks/generate/versions/1.2.0/package.js +555 -0
  12. package/blocks/native/sm.board-editor/versions/3.0.0/package.js +50 -17
  13. package/blocks/native/sm.board-editor/versions/3.1.0/package.js +1037 -0
  14. package/blocks/native/sm.editor/versions/3.0.0/package.js +128 -83
  15. package/blocks/native/sm.editor/versions/3.1.0/package.js +1299 -0
  16. package/blocks/native/sm.panel-strip/versions/3.0.0/package.js +45 -12
  17. package/blocks/native/sm.panel-strip/versions/3.1.0/package.js +479 -0
  18. package/blocks/native/sm.voiceover/versions/3.0.0/package.js +9 -3
  19. package/docs/build/block-builder-contract.md +6 -2
  20. package/docs/build/frame-views.md +30 -0
  21. package/docs/build/interface-design.md +84 -7
  22. package/docs/build/modules.md +2 -2
  23. package/docs/reference/authoring-guide.md +4 -4
  24. package/docs/reference/errors.md +1 -1
  25. package/docs/reference/execution.md +18 -4
  26. package/docs/reference/first-party-blocks.md +4 -4
  27. package/docs/reference/parity.md +1 -1
  28. package/docs/reference/ports.md +1 -1
  29. package/docs/reference/view-bridge.md +3 -0
  30. package/docs/tools/llm.md +26 -19
  31. package/package.json +1 -1
  32. package/packages/block-cli/dev-host/assets/host.js +161 -33
  33. package/packages/block-cli/dev-host/assets/index.css +1 -1
  34. package/packages/block-platform/block-readiness.js +16 -3
  35. package/packages/block-platform/canvas.js +4 -1
  36. package/packages/block-platform/catalog.js +32 -5
  37. package/packages/block-platform/flow-inspection.js +30 -2
  38. package/packages/block-platform/listings.js +16 -2
  39. package/packages/block-platform/steps.js +4 -1
  40. package/packages/block-sdk/admission.js +2 -2
  41. package/packages/block-sdk/agent-inputs.js +4 -2
  42. package/packages/block-sdk/appearance.js +19 -4
  43. package/packages/block-sdk/builder-contract.js +7 -4
  44. package/packages/block-sdk/first-party-identities.js +9 -1
  45. package/packages/block-sdk/first-party-packages.js +11 -1
  46. package/packages/block-sdk/generation-catalog.js +55 -5
  47. package/packages/block-sdk/generation-models.js +60 -0
  48. package/packages/block-sdk/index.d.ts +18 -4
  49. package/packages/block-sdk/index.js +2 -1
  50. package/packages/block-sdk/input-source-policy.js +2 -1
  51. package/packages/block-sdk/module-hosted.js +13 -5
  52. package/packages/block-sdk/module-worker.js +1 -1
  53. package/packages/block-sdk/port-types.js +6 -2
  54. package/packages/block-sdk/semantic-contracts.d.ts +1 -1
  55. package/packages/block-sdk/semantic-relationships.js +3 -0
  56. package/packages/block-sdk/semantic-schema.js +4 -1
  57. package/packages/block-sdk/shared-controls.js +4 -1
  58. package/packages/block-sdk/staged-releases.js +2 -1
  59. package/packages/block-sdk/testing.js +3 -0
  60. package/packages/block-sdk/view-bridge.js +3 -0
  61. package/packages/block-sdk/view-design.js +56 -12
  62. package/packages/block-sdk/view-renderer.js +19 -6
  63. package/packages/block-sdk/view.js +3 -2
  64. package/packages/design-system/block-kit.css +12 -3
@@ -27,9 +27,15 @@ export default {
27
27
  "media": {
28
28
  "type": "asset[]",
29
29
  "required": false,
30
- "semantic": "source_media",
30
+ "semantic": "editable_media",
31
31
  "description": "Clips and pictures from earlier Steps, shown in the Editor's media to put on the timeline."
32
32
  },
33
+ "canvas": {
34
+ "type": "pipeline",
35
+ "required": false,
36
+ "semantic": "canvas_document",
37
+ "description": "A Canvas from an earlier Step: its pictures and clips go in the Editor's media and on a new timeline."
38
+ },
33
39
  "narrationAudio": {
34
40
  "type": "audio",
35
41
  "required": false,
@@ -64,63 +70,93 @@ export default {
64
70
  "type": "text",
65
71
  "required": false,
66
72
  "semantic": "editor_action",
67
- "description": "What a run makes: a picture, a clip, word timings, a saved file or the result."
73
+ "description": "What a run makes: a picture, a clip, word timings, a saved file or the result.",
74
+ "sources": [
75
+ "view"
76
+ ]
68
77
  },
69
78
  "request": {
70
79
  "type": "json",
71
80
  "schema": "json",
72
81
  "required": false,
73
82
  "semantic": "editor_request",
74
- "description": "The details of what to make."
83
+ "description": "The details of what to make.",
84
+ "sources": [
85
+ "view"
86
+ ]
75
87
  },
76
88
  "references": {
77
89
  "type": "image[]",
78
90
  "required": false,
79
91
  "semantic": "reference_image",
80
- "description": "Saved pictures a new picture keeps."
92
+ "description": "Saved pictures a new picture keeps.",
93
+ "sources": [
94
+ "view"
95
+ ]
81
96
  },
82
97
  "firstFrame": {
83
98
  "type": "image",
84
99
  "required": false,
85
100
  "semantic": "first_frame",
86
- "description": "The picture a clip starts on."
101
+ "description": "The picture a clip starts on.",
102
+ "sources": [
103
+ "view"
104
+ ]
87
105
  },
88
106
  "lastFrame": {
89
107
  "type": "image",
90
108
  "required": false,
91
109
  "semantic": "last_frame",
92
- "description": "The picture a clip ends on."
110
+ "description": "The picture a clip ends on.",
111
+ "sources": [
112
+ "view"
113
+ ]
93
114
  },
94
115
  "audio": {
95
116
  "type": "asset",
96
117
  "required": false,
97
118
  "semantic": "source_audio",
98
- "description": "Saved sound to find the words of."
119
+ "description": "Saved sound to find the words of.",
120
+ "sources": [
121
+ "view"
122
+ ]
99
123
  },
100
124
  "files": {
101
125
  "type": "asset[]",
102
126
  "required": false,
103
127
  "semantic": "export_media",
104
- "description": "The saved clips, pictures and sound an export's timeline uses."
128
+ "description": "The saved clips, pictures and sound an export's timeline uses.",
129
+ "sources": [
130
+ "view"
131
+ ]
105
132
  },
106
133
  "dataUrl": {
107
134
  "type": "text",
108
135
  "required": false,
109
136
  "semantic": "file_data",
110
- "description": "A file the screen saves: a picture, a clip or a sound."
137
+ "description": "A file the screen saves: a picture, a clip or a sound.",
138
+ "sources": [
139
+ "view"
140
+ ]
111
141
  },
112
142
  "key": {
113
143
  "type": "text",
114
144
  "required": false,
115
145
  "semantic": "storage_key",
116
- "description": "A file name or a saved setting of this Block."
146
+ "description": "A file name or a saved setting of this Block.",
147
+ "sources": [
148
+ "view"
149
+ ]
117
150
  },
118
151
  "value": {
119
152
  "type": "json",
120
153
  "schema": "json",
121
154
  "required": false,
122
155
  "semantic": "storage_value",
123
- "description": "The value of that setting."
156
+ "description": "The value of that setting.",
157
+ "sources": [
158
+ "view"
159
+ ]
124
160
  }
125
161
  },
126
162
  "outputs": {
@@ -133,10 +169,16 @@ export default {
133
169
  "description": "The complete Editor document for the next Step."
134
170
  },
135
171
  "export": {
136
- "type": "asset",
172
+ "type": "video",
137
173
  "required": false,
138
- "semantic": "exported_video",
139
- "description": "The exported video (or sound), to download or pass on."
174
+ "semantic": "finished_video",
175
+ "description": "The exported video, to download or pass on."
176
+ },
177
+ "exportAudio": {
178
+ "type": "audio",
179
+ "required": false,
180
+ "semantic": "finished_audio",
181
+ "description": "The exported sound alone (MP3), to download or pass on."
140
182
  },
141
183
  "made": {
142
184
  "type": "asset[]",
@@ -149,7 +191,10 @@ export default {
149
191
  "schema": "json",
150
192
  "required": false,
151
193
  "semantic": "editor_answer",
152
- "description": "What the screen asked for: a picture, word timings, a saved file."
194
+ "description": "What the screen asked for: a picture, word timings, a saved file.",
195
+ "sources": [
196
+ "view"
197
+ ]
153
198
  }
154
199
  },
155
200
  "permissions": {
@@ -187,8 +232,8 @@ export default {
187
232
  "entry": "main.js",
188
233
  "files": {
189
234
  "main.js": {
190
- "sha256": "a8bd224898c99235a736b0cf6bcda78718301645ff03fb3c1990ab7ea4cec959",
191
- "bytes": 5966,
235
+ "sha256": "ccd7dc5208e8bc54e295f370b75adb1ce1f4e648711f343e2ead54803309a605",
236
+ "bytes": 6005,
192
237
  "mediaType": "text/javascript"
193
238
  }
194
239
  }
@@ -196,198 +241,198 @@ export default {
196
241
  "view": {
197
242
  "html": "<div id=\"root\" data-stillmade-layout=\"own\"></div>\n",
198
243
  "css": "/* ============================================================\n StillMade AI — Foundations applied to the AI Video Workflow app.\n Two surfaces only: cream (#F7F0DB) and ink (#0A0A0A).\n Everything else is a tonal shift of one of those two.\n Dark is the default; [data-mode=\"light\"] flips the surface.\n ============================================================ */\n/* When the licensed Balgin Skinny Italic files are available, drop\n them into client/public/fonts and uncomment this block — the\n display face points at \"Balgin\" first and switches automatically. */\n/*\n@font-face {\n font-family: \"Balgin\";\n src: url(\"/fonts/Balgin-SkinnyItalic.woff2\") format(\"woff2\");\n font-weight: 100;\n font-style: italic;\n font-display: swap;\n}\n*/\n\n*, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* ============================================================\n Animated Studio — fixed slate theme (ignores light/dark).\n :root[...] specificity beats [data-mode], so it wins in both modes.\n ============================================================ */\n:root[data-anim-theme=\"1\"]:not([data-mode=\"white\"]) {\n color-scheme: dark;\n --bg: #0A0D13;\n --bg-elev-1: #0F141C;\n --bg-elev-2: #1A2230;\n --bg-inset: #0F141C;\n --fg: #D8DEE8;\n --fg-muted: #8B98AC;\n --fg-subtle: #64748B;\n --fg-on-accent: #0A0D13;\n --border-tok: #232D3D;\n --border-strong: #303D50;\n --divider: #1A2230;\n --hover-wash: rgba(139, 152, 172, 0.08);\n --press-wash: rgba(139, 152, 172, 0.16);\n --selection-bg: #303D50;\n --selection-fg: #D8DEE8;\n\n --bg-primary: #0A0D13;\n --bg-secondary: #0F141C;\n --bg-tertiary: #1A2230;\n --bg-elevated: #1A2230;\n --bg-hover: #232D3D;\n --border: #232D3D;\n --border-light: #303D50;\n --accent: #8B98AC;\n --accent-hover: #B6C0CE;\n --accent-dim: rgba(139, 152, 172, 0.12);\n --accent-glow: rgba(139, 152, 172, 0.25);\n --accent-contrast: #0A0D13;\n --editor-standout-bg: #D8DEE8;\n --editor-standout-fg: #0A0D13;\n --text-primary: #D8DEE8;\n --text-secondary: #8B98AC;\n --text-muted: #64748B;\n --success: #8B98AC;\n --warning: #B6C0CE;\n --danger: #B6C0CE;\n}\n\nhtml, body {\n height: 100%;\n width: 100%;\n overflow: hidden;\n background: var(--bg);\n color: var(--fg);\n font-family: var(--font-body);\n font-size: 14px;\n line-height: 1.6;\n letter-spacing: var(--tr-body);\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n}\n\n#root {\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* App shell fills the dynamically-visible viewport. 100dvh (not 100vh) so the\n mobile browser's collapsing toolbar doesn't push the inner scroll container —\n and its last row of content — below the visible area where it can't be\n reached. vh fallback first for browsers without dvh. */\n.sm-app-shell { height: 100vh; height: 100dvh; }\n\n/* Full-screen mobile nav menu enters with a composited fade+slide (rule 6). */\n@keyframes sm-navmenu-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }\n.mobile-nav-menu { animation: sm-navmenu-in 200ms cubic-bezier(0.22, 1, 0.36, 1); }\n\n::selection { background: var(--selection-bg); color: var(--selection-fg); }\n\n/* Display lockups — always italic, always thin. This is the brand. */\n.display, h1, h2 {\n font-family: var(--font-display);\n font-style: italic;\n font-weight: 200;\n line-height: var(--lh-tight);\n letter-spacing: var(--tr-display);\n margin: 0;\n}\n.display { line-height: var(--lh-display); }\nh3, h4 {\n font-family: var(--font-body);\n font-weight: 500;\n line-height: var(--lh-tight);\n letter-spacing: -0.01em;\n margin: 0;\n}\n\n.eyebrow {font-size: 11px;\n color: var(--fg-muted);\n font-weight: 500;}\n\ncode, pre, .mono {\n font-family: var(--font-mono);\n font-size: 0.92em;\n}\n/* Listing IDs are interface text, not code. */\n.listing-identity code { font-family: inherit; font-size: inherit; }\n\nbutton {\n font-family: var(--font-body);\n cursor: pointer;\n border: none;\n outline: none;\n letter-spacing: var(--tr-body);\n}\n\ntextarea, input, select {\n font-family: var(--font-body);\n outline: none;\n}\n\n/* ─── Native <select> → app theme, applied GLOBALLY to every select (now + future),\n so individual call sites never need touching. This themes the CLOSED control via the\n theme tokens while keeping the browser's NATIVE open/close + selection behavior fully\n intact (so picking an option always works). The OPEN popup is drawn by the OS —\n macOS/Safari can't be CSS-themed — and `option` colors below theme it only where the\n browser honors them (Chrome/Firefox on Win/Linux). A truly themed popup everywhere\n needs a custom dropdown component, not native <select>. ─── */\nselect {\n background-color: var(--bg-elev-1);\n color: var(--text-primary);\n border: 1px solid var(--border);\n border-radius: var(--r-2);\n}\nselect option,\nselect optgroup {\n background-color: var(--bg-elevated);\n color: var(--text-primary);\n}\nselect option:checked { font-weight: 600; }\n\n/* ─── ThemedSelect — a custom dropdown whose OPEN popup is themed too (the one thing a\n native <select> can't do on macOS). The trigger mirrors the native `select` look above,\n so a converted call site is visually identical when closed; the popup + options are ours,\n including per-option disabled state and an \"ⓘ\" info tooltip (e.g. Coming Soon). ─── */\n.tsel-trigger {\n display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;\n background-color: var(--bg-elev-1); color: var(--text-primary);\n border: 1px solid var(--border); border-radius: var(--r-2);\n font-family: var(--font-body); font-size: inherit; padding: 6px 10px;\n cursor: pointer; text-align: left;\n}\n.tsel-trigger:hover { border-color: var(--border-strong); }\n.tsel-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }\n.tsel-trigger:disabled { opacity: 0.5; cursor: default; }\n.tsel-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tsel-caret { flex: none; font-size: 10px; opacity: 0.7; }\n.tsel-pop {\n /* Above EVERY overlay that can contain a select, not just app dialogs (100000):\n the mobile BottomSheet is 100050, TemplateStudio 100090 and the PreviewGrid\n lightbox 100095. At the old 100010 the popup painted UNDERNEATH the sheet\n that opened it, so every dropdown inside a mobile sheet (motion easing,\n font, position, word-reveal swap/emphasis/trail layout) and the Whoosh\n transition's Direction slot in TemplateStudio silently did nothing. */\n z-index: 100100;\n max-height: 260px; overflow-y: auto;\n background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-2);\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.28); padding: 4px;\n}\n.tsel-opt {\n display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-radius: 6px;\n color: var(--text-primary); cursor: pointer; font-size: 13px; white-space: nowrap;\n}\n.tsel-opt[data-active=\"true\"] { background: var(--bg-elev-1); }\n.tsel-opt[aria-selected=\"true\"] { font-weight: 600; }\n.tsel-opt[aria-disabled=\"true\"] { color: var(--text-muted); cursor: default; }\n.tsel-opt[aria-disabled=\"true\"][data-active=\"true\"] { background: transparent; }\n.tsel-check { flex: none; width: 12px; font-size: 11px; opacity: 0.8; }\n.tsel-opt-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }\n.tsel-note {\n position: relative;\n flex: none; width: 16px; height: 16px; font-size: 11px; cursor: help;\n color: var(--text-muted); border: 1px solid var(--border); border-radius: 999px;\n display: inline-flex; align-items: center; justify-content: center;\n}\n.tsel-note:hover { color: var(--text-primary); border-color: var(--border-strong); }\n/* Info tooltip (e.g. \"Coming Soon\"). Portaled to <body> and positioned to the RIGHT of the ⓘ\n so the popup's overflow can never clip it. */\n.tsel-tip {\n z-index: 100110; /* one step above .tsel-pop — it annotates an option inside it */\n background: var(--text-primary); color: var(--bg-elevated);\n padding: 4px 8px; border-radius: 5px; font-size: 11px; font-weight: 600;\n max-width: min(260px, calc(100vw - 16px)); box-sizing: border-box;\n white-space: normal; pointer-events: none;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);\n}\n@media (max-width: 767.98px), (max-height: 480px) and (pointer: coarse) {\n .tsel-opt { min-height: 44px; box-sizing: border-box; font-size: 14px; }\n .tsel-note { width: 44px; height: 44px; flex: 0 0 44px; font-size: 14px; }\n}\n\n.video-editor input,\n.video-editor select,\n.video-editor textarea {\n width: 100%;\n min-width: 0;\n background: var(--bg-inset);\n color: var(--fg);\n border: var(--bw-1) solid var(--border-strong);\n border-radius: var(--r-2);\n padding: 7px 8px;\n font-family: var(--font-body);\n font-size: 12px;\n accent-color: var(--signal);\n}\n\n.video-editor,\n.mobile-editor-root {\n user-select: none;\n -webkit-user-select: none;\n /* Kill the iOS long-press callout (Copy / Search) and the selection\n magnifier so a touch drag/trim/long-press on the timeline, labels, or\n buttons can't accidentally select UI text. Inputs re-enable both below. */\n -webkit-touch-callout: none;\n}\n\n.video-editor input,\n.video-editor select,\n.video-editor textarea,\n.video-editor [contenteditable=\"true\"],\n.mobile-editor-root input,\n.mobile-editor-root select,\n.mobile-editor-root textarea,\n.mobile-editor-root [contenteditable=\"true\"] {\n user-select: text;\n -webkit-user-select: text;\n -webkit-touch-callout: default;\n}\n\n.video-editor input[type=\"range\"] {\n padding: 0;\n border: 0;\n background: transparent;\n}\n\n.video-editor input[type=\"checkbox\"] {\n width: auto;\n min-width: auto;\n}\n\n.video-editor select:focus,\n.video-editor input:focus,\n.video-editor textarea:focus {\n border-color: var(--signal);\n box-shadow: 0 0 0 1px var(--signal-dim);\n}\n\n/* Focus — always visible, always the signal color */\n:focus-visible {\n outline: 2px solid var(--signal);\n outline-offset: 2px;\n}\n\n::-webkit-scrollbar {\n width: 6px;\n height: 6px;\n}\n::-webkit-scrollbar-track { background: transparent; }\n::-webkit-scrollbar-thumb {\n background: var(--border-strong);\n border-radius: var(--r-pill);\n}\n::-webkit-scrollbar-thumb:hover { background: var(--fg-subtle); }\n\n/* Hide the scrollbar chrome while keeping the element scrollable (wheel /\n trackpad). Used on the editor's left panel + tab rail for a clean column. */\n.sm-hide-scrollbar { scrollbar-width: none; -ms-overflow-style: none; }\n.sm-hide-scrollbar::-webkit-scrollbar { width: 0; height: 0; display: none; }\n\n/* ============================================================\n Buttons — primary is fg/bg inversion, not a color.\n Sharp by default; pill is a deliberate touch affordance.\n ============================================================ */\n.btn {\n display: inline-flex;\n align-items: center;\n gap: var(--s-2);\n padding: var(--s-2) var(--s-4);\n border-radius: var(--r-pill);\n font-size: 13px;\n font-weight: 500;\n letter-spacing: var(--tr-body);\n transition: transform var(--dur-fast) var(--ease-out),\n background-color var(--dur-fast) var(--ease-out),\n border-color var(--dur-fast) var(--ease-out),\n color var(--dur-fast) var(--ease-out),\n opacity var(--dur-fast) var(--ease-out);\n}\n.btn:active { transform: scale(0.98); }\n\n.btn-primary {\n background: var(--fg);\n color: var(--bg);\n}\n.btn-primary:hover { background: var(--fg); opacity: 0.86; }\n.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }\n\n.btn-secondary {\n background: transparent;\n color: var(--fg);\n border: var(--bw-1) solid var(--border-strong);\n}\n.btn-secondary:hover { background: var(--hover-wash); border-color: var(--fg); }\n\n.btn-ghost {\n background: transparent;\n color: var(--fg-muted);\n padding: 6px 10px;\n}\n.btn-ghost:hover { background: var(--hover-wash); color: var(--fg); }\n\n.btn-icon {\n background: transparent;\n color: var(--fg-muted);\n padding: 5px;\n border-radius: var(--r-2);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: background-color var(--dur-fast) var(--ease-out),\n color var(--dur-fast) var(--ease-out),\n transform var(--dur-fast) var(--ease-out);\n}\n.btn-icon:hover { background: var(--hover-wash); color: var(--fg); }\n.btn-icon:active { transform: scale(0.98); }\n.btn-icon:disabled { opacity: 0.4; cursor: not-allowed; }\n\n.typing-indicator {\n display: flex;\n gap: 4px;\n align-items: center;\n padding: 4px 0;\n}\n.typing-indicator span {\n width: 6px;\n height: 6px;\n border-radius: var(--r-pill);\n background: var(--fg-subtle);\n animation: bounce 1.2s infinite;\n}\n.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }\n.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }\n\n@keyframes bounce {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }\n 30% { transform: translateY(-5px); opacity: 1; }\n}\n\n@keyframes fadeIn {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 0.4; transform: scale(0.9); }\n 50% { opacity: 1; transform: scale(1.1); }\n}\n\n/* Toast slide-in for ToastHost (services/toast.js) */\n@keyframes toastIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* Q3 — keyboard focus rings (focus-visible only, so mouse users don't see them) */\nbutton:focus-visible,\n[role=\"button\"]:focus-visible,\na:focus-visible,\ninput:focus-visible,\nselect:focus-visible,\ntextarea:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n border-radius: 4px;\n}\n\n/* Typing fields never show a focus outline or ring (docs/UI_AESTHETIC.md):\n the caret marks focus. Buttons, links, switches and checkboxes keep theirs.\n !important so component focus-visible rules cannot bring the ring back. */\ninput:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"range\"]):not([type=\"color\"]):not([type=\"file\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]):is(:focus, :focus-visible),\ntextarea:is(:focus, :focus-visible),\nselect:is(:focus, :focus-visible),\n[contenteditable]:not([contenteditable=\"false\"]):is(:focus, :focus-visible) {\n outline: none !important;\n}\n\n/* Skeleton shimmer for P2 loaders */\n@keyframes skeletonShimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n}\n.skeleton {\n background: linear-gradient(90deg,\n rgba(255,255,255,0.03) 0%,\n rgba(255,255,255,0.10) 50%,\n rgba(255,255,255,0.03) 100%);\n background-size: 200% 100%;\n animation: skeletonShimmer 1.4s ease-in-out infinite;\n border-radius: 6px;\n}\n\n/* Node-state visuals (E1) — applied to NodeShell wrapper.\n States: empty (dashed ghost) / generating (shimmer ring) / failed (red stripe) / complete */\n/* opacity:0.78 removed — CSS opacity cascades to children and faded the\n image too. Dashed border alone is the \"pending\" signal now. */\n.node-state-empty { border-style: dashed !important; }\n/* The pulsing glow animates OPACITY on a pseudo-element (compositor-only)\n instead of keyframing box-shadow, which repainted the node's full shadow\n region on the main thread every frame for the whole generation — with\n batch generation pulsing many nodes at once. Same look: constant 2px\n accent ring + a breathing 18px glow. */\n.node-state-generating { box-shadow: 0 0 0 2px var(--accent); position: relative; }\n.node-state-generating::after {\n content: '';\n position: absolute;\n inset: -2px;\n border-radius: inherit;\n box-shadow: 0 0 18px rgba(247, 200, 50, 0.55);\n animation: nodePulse 1.6s ease-in-out infinite;\n pointer-events: none;\n will-change: opacity;\n}\n@keyframes nodePulse {\n 0%, 100% { opacity: 0.36; }\n 50% { opacity: 1; }\n}\n.node-state-warning { position: relative; border-color: var(--attention-warning) !important; }\n.node-state-warning::after {\n content: ''; position: absolute; inset: -2px; border-radius: inherit; pointer-events: none;\n box-shadow: 0 0 0 1px var(--attention-warning), 0 0 14px color-mix(in srgb, var(--attention-warning) 40%, transparent);\n}\n.node-state-failed { border-top: 4px solid #d04848 !important; }\n.node-state-failed::before {\n content: '⚠ '; color: #d04848; font-weight: 800;\n position: absolute; top: 6px; left: 8px; font-size: 12px; z-index: 2;\n pointer-events: none;\n}\n\n/* React Flow overrides */\n.react-flow__node { cursor: default; }\n/* Promote layers only WHILE a gesture is live (xyflow toggles these classes\n automatically at drag start/end) — the dragged card and the panning\n viewport move on the compositor instead of repainting their 8-layer\n shadows every frame. No idle memory cost: the hint drops with the class. */\n.react-flow__node.dragging { will-change: transform; }\n.react-flow__pane.dragging .react-flow__viewport { will-change: transform; }\n\n/* ── 3D node extrusion (StillMade design bundle) ────────────────────\n Stacked box-shadow that follows the corner radius, plus an ambient\n cast. Compositor-only: no per-frame JS, no extra DOM. Capped at 6\n solid layers so paint cost stays bounded on large scenes (147 nodes).\n Excludes layout-only node types (scene groups, shot labels, sticky\n notes) which aren't cards. */\n.react-flow__node:not(.react-flow__node-sceneGroupNode):not(.react-flow__node-shotLabelNode):not(.react-flow__node-stickyNoteNode):not(.react-flow__node-transitionNode) {\n border-radius: 10px;\n box-shadow:\n 1px 1px 0 var(--node-side, #d8cfb3),\n 2px 2px 0 var(--node-side, #d8cfb3),\n 3px 3px 0 var(--node-side, #d8cfb3),\n 4px 4px 0 var(--node-side, #d8cfb3),\n 5px 5px 0 var(--node-side, #d8cfb3),\n 6px 6px 0 var(--node-side, #d8cfb3),\n 7px 7px 0 var(--node-edge, rgba(10,10,10,0.18)),\n 14px 16px 18px -4px rgba(10,10,10,0.18);\n /* No transition / hover-lift / drag-lift — animating transform on\n react-flow's already-transformed wrapper compounds onto its pan\n matrix and makes pans/drags feel laggy. Static shadow only. */\n}\n[data-mode=\"dark\"] .react-flow__node:not(.react-flow__node-sceneGroupNode):not(.react-flow__node-shotLabelNode):not(.react-flow__node-stickyNoteNode):not(.react-flow__node-transitionNode) {\n --node-side: #1f1d18;\n --node-edge: rgba(247, 240, 219, 0.18);\n}\n/* Zoom controls laid out as a 2×2 square (positioned above the Feedback pill\n in JS). Overrides React Flow v12's default flex-column. */\n.react-flow__controls {\n display: grid !important;\n grid-template-columns: repeat(2, 1fr) !important;\n}\n.react-flow__controls button {\n background: var(--bg-elev-2) !important;\n border-color: var(--border-tok) !important;\n color: var(--fg-muted) !important;\n fill: var(--fg-muted) !important;\n}\n.react-flow__controls button:hover {\n background: var(--ink-300) !important;\n}\n.react-flow__edge-path {\n stroke: var(--border-strong);\n}\n\n/* While actively panning a large graph, skip painting the edge layer (the main\n big-graph pan cost). Edges stay mounted — only paint is suppressed — so they\n reappear instantly with no remount when motion stops. See WorkflowCanvas\n markPanning / EDGE_PAN_HIDE_MIN. */\n.react-flow.rf-edges-panning .react-flow__edges {\n display: none;\n}\n\n.react-flow__node.node-controls-locked input,\n.react-flow__node.node-controls-locked textarea,\n.react-flow__node.node-controls-locked select,\n.react-flow__node.node-controls-locked button,\n.react-flow__node.node-controls-locked [role=\"button\"] {\n pointer-events: none !important;\n}\n\n.react-flow__node.node-controls-locked {\n cursor: grab;\n}\n\n.react-flow__node.node-controls-locked:active {\n cursor: grabbing;\n}\n\n.react-flow__node.scene-add-available-node {\n filter: drop-shadow(0 0 10px rgba(247,240,219,0.22));\n}\n\n.react-flow__node.scene-add-available-node > div {\n outline: 1px solid var(--border-strong);\n outline-offset: 4px;\n border-radius: var(--r-3);\n}\n\n.react-flow__node.scene-add-available-node::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n border: 1px dashed var(--border-strong);\n border-radius: var(--r-3);\n pointer-events: none;\n}\n.react-flow__node.node-replace-available {\n filter: drop-shadow(0 0 10px rgba(247,240,219,0.22));\n}\n\n.react-flow__node.node-replace-available > div {\n outline: 1px solid var(--border-strong);\n outline-offset: 4px;\n border-radius: var(--r-3);\n}\n\n.react-flow__node.node-replace-available::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n border: 1px dashed var(--border-strong);\n border-radius: var(--r-3);\n pointer-events: none;\n}\n\nselect option {\n background: var(--bg-elev-2);\n color: var(--fg);\n}\n\n.spinner {\n width: 16px;\n height: 16px;\n border: 2px solid var(--border-tok);\n border-top-color: var(--fg);\n border-radius: var(--r-pill);\n animation: spin 0.7s linear infinite;\n}\n\n.media-upload-preview:hover .media-upload-overlay {\n opacity: 1 !important;\n}\n\n/* Reduced motion — respect it everywhere */\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n animation-duration: 1ms !important;\n transition-duration: 1ms !important;\n }\n}\n\n/* All Assets grid: overlay shows on hover via CSS so the parent\n doesn't need a hoveredId state that re-renders the whole list. */\n.assets-card .assets-card-overlay { opacity: 0; transition: opacity 0.15s; }\n.assets-card:hover .assets-card-overlay { opacity: 1; }\n\n/* YouTube hub — Video performance rows: soft accent glow on hover so the rows\n feel clickable. Inset (not outer) shadow because the table clips overflow. */\n.yt-video-row { transition: background 0.12s ease, box-shadow 0.12s ease, color 0.12s ease; }\n.yt-video-row:hover {\n background: var(--hover-wash) !important;\n box-shadow: inset 2px 0 0 var(--accent), inset 0 0 14px var(--accent-glow);\n color: var(--text-primary);\n}\n\n/* Chat bubble text selection — the global ::selection token (which uses\n ink-600 in light mode) collides with the user bubble's dark accent\n background, making highlights invisible. Force the signal/amber color\n here so highlights pop on both user (dark bubble) and assistant\n (cream bubble) regardless of theme. */\n.chat-bubble *::selection { background: var(--signal); color: #0A0A0A; }\n.chat-bubble *::-moz-selection { background: var(--signal); color: #0A0A0A; }\n\n/* Chat bubble copy button — visible on hover/focus, and stays visible\n while the cursor is over the button itself (otherwise moving from\n bubble onto button would hide it before you could click). */\n.chat-bubble:hover .chat-bubble-copy,\n.chat-bubble:focus-within .chat-bubble-copy,\n.chat-bubble-copy:hover,\n.chat-bubble-copy:focus { opacity: 1 !important; }\n/* Subtle hover/active feedback so the user knows it's clickable. */\n.chat-bubble-copy:hover { background: var(--bg-elevated-2, var(--bg-elevated)); color: var(--text-primary) !important; }\n.chat-bubble-copy:active { transform: scale(0.94); }\n\n/* ── StillMade logo lockup — hover animation ──────────────────────────────\n Hovering the top-left lockup turns the isometric cube left-to-right around its\n vertical axis (a 3D rotateY) with a soft currentColor glow; it turns back on\n leave. Reduced-motion users get just a gentle scale + glow, no rotation. */\n.sm-brand .sm-brandmark {\n transform-origin: 50% 50%;\n transition: transform 760ms cubic-bezier(0.2, 0.8, 0.2, 1), filter 280ms ease;\n}\n.sm-brand:hover .sm-brandmark {\n transform: perspective(340px) rotateY(360deg) scale(1.06);\n filter: drop-shadow(0 0 7px color-mix(in srgb, currentColor 45%, transparent));\n will-change: transform, filter;\n}\n/* Wordmark resting position + a subtle lift on hover (a small nudge — gentler\n than the design's). Resting transform lives here (not inline) so :hover can\n override it. */\n.sm-brand .sm-word {\n transform: translate(-4px, 0px);\n transition: transform 300ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n.sm-brand:hover .sm-word { transform: translate(-4px, -1px); will-change: transform; }\n@media (prefers-reduced-motion: reduce) {\n .sm-brand .sm-brandmark { transition: transform 240ms ease, filter 240ms ease; }\n .sm-brand:hover .sm-brandmark { transform: scale(1.06); }\n .sm-brand:hover .sm-word { transform: translate(-4px, 0px); }\n}\n\n/* ── Mobile UI ergonomics ───────────────────────────────────────────────────\n Scoped to body.sm-mobile-ui, which App.jsx adds ONLY when the user chose the\n mobile site on a small screen, including a rotated touch phone. Ordinary\n desktop windows and the continue-anyway mode are unaffected.\n\n The app is inline-styled, so these few universal touch fixes are applied here\n once instead of edited into every input across every screen:\n - 16px text fields stop iOS from zooming the page on focus (needs !important\n to beat the inline font sizes).\n - comfortable minimum tap target on buttons/selects. */\nbody.sm-mobile-ui input,\nbody.sm-mobile-ui textarea,\nbody.sm-mobile-ui select {\n font-size: 16px !important;\n}\nbody.sm-mobile-ui button,\nbody.sm-mobile-ui select,\nbody.sm-mobile-ui [role=\"button\"] {\n min-height: 44px;\n}\n/* WebKit can ignore min-height on its native one-line select. Keep the\n physical control touch-sized and let enlarged text make it taller. */\nbody.sm-mobile-ui select:not([multiple]):not([size]) {\n height: max(44px, 2.75em);\n}\n/* Icon-only / chip-sized controls opt out of the min height so dense toolbars\n (timeline, inspector) don't balloon. */\nbody.sm-mobile-ui button.btn-icon,\nbody.sm-mobile-ui button[data-compact],\nbody.sm-mobile-ui .no-min-tap {\n min-height: 0;\n}\n/* YouTube hub analytics rows are dense multi-column grids; keep their columns\n readable and let the table scroll horizontally instead of squishing on a\n phone (the table container is overflow-x:auto). */\nbody.sm-mobile-ui .yt-video-row {\n min-width: 560px;\n}\n\n/* Frame view: the Editor fills the space StillMade gives its Step (at least 560 pixels tall). */\n#root { height: max(560px, var(--stillmade-space-height, 100vh)); }\n/* Text wraps as on StillMade's own pages (frame views break long words anywhere by default). */\nhtml { overflow-wrap: normal; }\n\n/* Stylesheets the screen's components import. */\n.bs-private-dialog{box-sizing:border-box;margin:auto;width:min(720px,calc(100vw - 32px));max-height:calc(100dvh - 32px);padding:0;border:1px solid var(--border);border-radius:var(--r-3);background:var(--bg-primary);color:var(--text-primary);font:16px/1.6 var(--font-body);overflow:auto;overflow-wrap:anywhere}\n.bs-private-dialog::backdrop{background:var(--scrim,rgba(0,0,0,.4))}\n.bs-private-dialog>header,.bs-private-dialog>footer{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 24px;background:var(--bg-primary)}\n.bs-private-dialog>header{border-bottom:1px solid var(--border);position:sticky;top:0;z-index:1}.bs-private-dialog>header>div{min-width:0}.bs-private-dialog>header p{margin:4px 0 0;font-size:14px;color:var(--text-secondary)}\n.bs-private-dialog h2{margin:0;font:italic 200 30px/1.2 var(--font-display);letter-spacing:var(--tr-display)}\n.bs-private-body{padding:20px 24px}.bs-private-body>p:first-child{margin-top:0}.bs-private-dialog fieldset{min-width:0;border:1px solid var(--border);border-radius:var(--r-3);padding:16px}.bs-private-dialog legend{padding:0 6px;font-size:14px}\n.bs-private-check{display:flex;align-items:flex-start;gap:12px;margin:14px 0}.bs-private-check input{width:18px;height:18px;flex-shrink:0;margin:4px 0 0;accent-color:var(--fg)}.bs-private-note{font-size:14px;color:var(--text-secondary)}\n.bs-private-dialog>footer{position:sticky;bottom:0;border-top:1px solid var(--border);justify-content:flex-end;z-index:1}.bs-private-dialog button,.bs-team-library button{font:inherit;max-width:100%;padding:8px 16px;border:1px solid var(--border-strong);border-radius:var(--r-pill);background:transparent;color:inherit;cursor:pointer}.bs-private-dialog button:disabled{opacity:.5;cursor:default}.bs-private-dialog .bs-private-primary{background:var(--fg);color:var(--bg-primary);border-color:var(--fg)}.bs-private-dialog :is(button,input):focus-visible{outline:2px solid var(--signal);outline-offset:3px}\n.bs-private-review{width:min(1100px,calc(100vw - 32px))}.bs-private-review .bs-import-review{margin:0}.bs-private-review .bs-import-review input[type=checkbox]{width:auto}.bs-private-review .bs-actions{position:sticky;bottom:0;background:var(--bg-secondary);border-top:1px solid var(--border);padding:12px 0}.bs-private-review .bs-actions button{font-size:16px}\n.bs-team-library{border-top:1px solid var(--border);margin-top:28px;padding-top:20px}.bs-team-library>header{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}.bs-team-library h2{margin:0}.bs-team-library .bs-card{border:1px solid var(--border);background:var(--bg-secondary)}.bs-team-library h3{margin:0;font-weight:500}.bs-team-library .bs-card button{display:block;margin-top:16px}\n@media(max-width:600px){.bs-private-dialog{width:calc(100vw - 16px);max-height:calc(100dvh - 16px)}.bs-private-dialog>header,.bs-private-dialog>footer,.bs-private-body{padding:16px}.bs-private-dialog>header{align-items:flex-start}.bs-private-dialog h2{font-size:26px}.bs-private-dialog>header>button{flex-shrink:0}.bs-team-library>header{flex-direction:column}.bs-private-review .bs-import-review{padding:16px}.bs-private-review .bs-private-body{padding:8px}.bs-private-dialog :is(input,select,textarea){font-size:16px}}\n\n.bs-private-check span>small{display:block}\n\n.publish-build-review{width:min(760px,calc(100vw - 32px))}\n.publish-build-review .bs-private-body{display:grid;gap:20px}\n.publish-build-review h3{margin:0 0 8px;font-size:18px;font-weight:600}\n.publish-build-review p{margin:8px 0;color:var(--text-secondary)}\n.publish-build-review details{border-top:1px solid var(--border);padding-top:16px}\n.publish-build-review summary{cursor:pointer;font-weight:600}\n.publish-build-review form>footer{display:flex;gap:12px;justify-content:flex-end;position:sticky;bottom:0;padding:18px 24px;border-top:1px solid var(--border);background:var(--bg-primary)}\n.publish-build-review .bs-private-check{cursor:pointer}\n@media(max-width:540px){.publish-build-review form>footer{flex-direction:column;padding:16px}.publish-build-review form>footer button{width:100%}}\n\n.project-type-start-review .bs-private-body>label{display:grid;gap:8px}.project-type-start-review :is(input,select,textarea){box-sizing:border-box;width:100%;padding:10px 12px;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border);border-radius:var(--r-3);font:inherit}.project-type-start-review textarea{resize:vertical}\n\n.block-audio-library{min-width:0;margin-top:20px;padding-top:16px;border-top:1px solid var(--border-tok);color:var(--fg);font:16px/1.5 var(--font-body);overflow-wrap:anywhere}\n.block-audio-library h3{font:200 italic 24px/1.2 var(--font-display);margin:0 0 14px}\n.bal-recording{display:grid;gap:8px;min-width:0;padding:12px 0}.bal-recording+.bal-recording{border-top:1px solid var(--border-tok)}.bal-recording p{margin:0;color:var(--fg-muted);font-size:13px}\n.bal-recording audio{display:block;min-width:0;width:100%;max-width:100%;height:44px}.bal-recording button{width:100%;min-width:0;font:inherit;padding:9px 14px;border:1px solid var(--border-tok);border-radius:var(--r-pill);background:var(--bg-elevated);color:var(--fg);cursor:pointer}.bal-recording button:disabled{opacity:.45;cursor:default}.bal-recording button:focus-visible{outline:2px solid var(--signal);outline-offset:3px}\n\n.timeline-edit-preview{margin:12px 0;padding:16px;border:1px solid var(--border-tok);border-radius:var(--r-card,12px);background:var(--bg-elevated);color:var(--fg);font:16px/1.5 var(--font-body);min-width:0;overflow-wrap:anywhere}\n.timeline-edit-preview figcaption{font:200 italic 24px/1.2 var(--font-display)}\n.timeline-edit-preview>p{color:var(--fg-muted);margin:10px 0;font-size:14px}\n.tep-change{padding:12px 0;border-top:1px solid var(--border-tok)}.tep-change>strong{display:block;margin-bottom:8px}\n.tep-row{display:grid;grid-template-columns:52px minmax(0,1fr);gap:6px 10px;align-items:center;margin:8px 0}.tep-row>small{grid-column:2;color:var(--fg-muted);font-size:12px}.tep-row>span{font-size:13px}\n.tep-lane{height:24px;position:relative;background:var(--bg);border-radius:4px;overflow:hidden;border:1px solid var(--border-tok)}.tep-clip{position:absolute;top:2px;bottom:2px;background:var(--signal);border:1px solid var(--fg-muted);border-radius:3px;min-width:2px}.tep-lane>small{position:absolute;inset:0;text-align:center;color:var(--fg-muted);font-size:12px}\n\n/* StillMade media player, photo button and full-screen viewer: option A \"Cream blocks\" (owner, November 2, 2026). Solid cream\n rounded squares with ink icons, a thick cream timeline, the time in the thin italic display face. The chrome sits on the\n picture, so it is the same in Light, Dark and White; the letterbox is ink. Rounded squares only, never circles\n (UI_AESTHETIC \"Icon preference\"). Everything that moves per frame moves by transform; nothing uses backdrop-filter.\n Built by media-player.js (attachMediaPlayer, openMediaViewer, attachPhotoExpand). */\n:where(.sm-player,.sm-viewer,.sm-expand-btn){--sm-cream:var(--cream-100,#F7F0DB);--sm-ink:var(--ink-600,#0A0A0A);--sm-gold:var(--signal,#E8B23A);--sm-out:var(--dur-fast,160ms);--sm-in:var(--dur-base,240ms);--sm-ease:var(--ease-out,cubic-bezier(.22,1,.36,1));--sm-spring:var(--ease-spring,cubic-bezier(.34,1.56,.64,1));--sm-display:var(--font-display,\"Balgin\",\"Hanken Grotesk\",ui-sans-serif,sans-serif)}\n\n/* ---------- The player box: shrinks to the video like a bare <video>; data-fill fills a box the caller sizes ---------- */\n.sm-player{position:relative;display:inline-block;vertical-align:top;max-width:100%;box-sizing:border-box;overflow:hidden;background:var(--sm-ink);color:var(--sm-cream);line-height:1;font-family:var(--font-body,\"Hanken Grotesk\",ui-sans-serif,system-ui,sans-serif);user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation;outline:none}\n.sm-player:focus-visible{outline:2px solid var(--sm-gold);outline-offset:2px}\n.sm-player>video{display:block;width:auto;max-width:100%;height:auto;max-height:inherit;margin:0 auto;object-fit:contain;background:transparent}\n.sm-player[data-fill]>video,.sm-player:fullscreen>video,.sm-player[data-stage]>video{width:100%;height:100%;max-width:none;max-height:none}\n.sm-player[data-fill]{display:block}\n.sm-player[data-idle]{cursor:none}\n:where(.sm-stage)>.sm-player{max-width:100%;max-height:100%;border-radius:var(--r-2,4px)}\n\n/* The controls layer covers the picture; only the bar takes the pointer, so a click on the picture reaches the box. */\n.sm-player-ui{position:absolute;inset:0;z-index:1;pointer-events:none}\n.sm-player-shade{position:absolute;left:0;right:0;bottom:0;height:120px;max-height:100%;background:linear-gradient(to top,rgba(10,10,10,.55),rgba(10,10,10,0))}\n.sm-player-bar{position:absolute;left:12px;right:12px;bottom:12px;display:flex;align-items:center;gap:10px;pointer-events:auto}\n.sm-player-shade,.sm-player-bar{transition:opacity var(--sm-in) var(--sm-ease)}\n/* November 2, 2026 (owner): hover only. data-away (no pointer over it, no keyboard focus in it, no recent tap) and data-idle\n (the mouse resting on a playing video) hide them; hidden controls take no pointer, so a tap reaches the picture. */\n.sm-player[data-away] .sm-player-shade,.sm-player[data-away] .sm-player-bar,.sm-player[data-idle] .sm-player-shade,.sm-player[data-idle] .sm-player-bar{opacity:0;pointer-events:none;transition-duration:var(--sm-out)}\n\n/* ---------- Cream squares (player, viewer) ---------- */\n:where(.sm-player,.sm-viewer) .sm-media-btn{appearance:none;-webkit-appearance:none;box-sizing:border-box;flex:none;display:grid;place-items:center;width:44px;height:44px;min-width:0;min-height:0;margin:0;padding:0;border:0;border-radius:var(--r-3,8px);background:var(--sm-cream);color:var(--sm-ink);box-shadow:none;font:inherit;line-height:1;text-decoration:none;cursor:pointer;transition:transform var(--sm-out) var(--sm-spring)}\n:where(.sm-player,.sm-viewer) .sm-media-btn svg{display:block;width:20px;height:20px}\n:is(.sm-player,.sm-viewer) .sm-media-btn.sm-media-btn.sm-media-btn-text{width:auto;padding:0 14px;font-size:14px;font-weight:600}\n/* November 2, 2026: the hover rules restate the cream, so a page's own button:hover (the listing pages, a Block's CSS) never\n washes the squares out. */\n@media (hover:hover){:where(.sm-player,.sm-viewer) .sm-media-btn:hover{transform:translateY(-1px);background:var(--sm-cream);color:var(--sm-ink)}}\n:where(.sm-player,.sm-viewer) .sm-media-btn:active{transform:scale(.94)}\n:is(.sm-player,.sm-viewer) .sm-media-btn.sm-media-btn:focus-visible{outline:2px solid var(--sm-gold);outline-offset:2px;border-radius:var(--r-3,8px)}\n/* November 2, 2026: a container's own button rule outranked the squares and drew them as outlined pills on a Step\n (.bs-step-workspace button:not(.btn-primary) is 0,2,1 and 0,3,1 on hover; .block-playground and .bs-shell buttons). The\n look is restated at 0,3,0, and the cream at 0,4,0 on any hover (a tap leaves :hover on touch); size, place and display\n stay in the rules above, so the narrow-player and viewer rules keep working. */\n:is(.sm-player,.sm-viewer) .sm-media-btn.sm-media-btn{min-width:0;min-height:0;padding:0;border:0;border-radius:var(--r-3,8px);background:var(--sm-cream);color:var(--sm-ink);box-shadow:none;font:inherit;line-height:1;text-decoration:none;cursor:pointer}\n:is(.sm-player,.sm-viewer) .sm-media-btn.sm-media-btn:hover{background:var(--sm-cream);color:var(--sm-ink)}\n.sm-player .sm-player-bar [data-control=\"fullscreen\"]{margin-left:auto}\n\n/* ---------- Volume (owner, November 2, 2026): a vertical cream line above the sound button, shown while the button or the line\n is hovered or focused, or while it is dragged; the same track, fill and square knob as the timeline. Mouse only. ---------- */\n.sm-player-sound{position:relative;display:flex;flex:none}\n.sm-player-volume{position:absolute;left:50%;bottom:100%;padding-bottom:10px;opacity:0;pointer-events:none;transform:translate(-50%,6px);transition:opacity var(--sm-out) var(--sm-ease),transform var(--sm-out) var(--sm-ease)}\n.sm-player-sound:hover .sm-player-volume,.sm-player-sound:focus-within .sm-player-volume,.sm-player-volume[data-drag]{opacity:1;pointer-events:auto;transform:translate(-50%,0);transition-duration:var(--sm-in)}\n.sm-player-volume-rail{position:relative;box-sizing:border-box;width:44px;height:128px;padding:14px 0;border-radius:var(--r-3,8px);background:rgba(10,10,10,.64);cursor:pointer;touch-action:none;outline:none}\n.sm-player-volume-rail:focus-visible{outline:2px solid var(--sm-gold);outline-offset:2px}\n.sm-player-volume-track{position:relative;width:6px;height:100%;margin:0 auto;border-radius:3px;background:rgba(247,240,219,.28);overflow:visible}\n.sm-player-volume-level{position:absolute;inset:0;border-radius:3px;background:var(--sm-cream);transform-origin:center bottom;transform:scaleY(1)}\n.sm-player-volume-head{position:absolute;inset:0;pointer-events:none;transform:translateY(-100%)}\n.sm-player-volume-knob{position:absolute;left:50%;bottom:0;width:16px;height:16px;margin:0 0 -8px -8px;border-radius:4px;background:var(--sm-cream);box-shadow:0 0 0 3px rgba(10,10,10,.35)}\n.sm-player-volume[data-drag] .sm-player-volume-head{will-change:transform}\n/* The player box clips, and the line opens 194 px above its bottom: under 200 px tall it is shorter, under 150 px it stays\n closed and the button only mutes (data-volume-room, measured by the player's ResizeObserver). */\n.sm-player[data-volume-room=\"short\"] .sm-player-volume-rail{height:84px;padding:12px 0}\n.sm-player[data-volume-room=\"none\"] .sm-player-volume{display:none}\n@media (hover:none){.sm-player-volume{display:none}}\n\n/* ---------- Timeline: 24 px to point at, a 6 px track that grows, a cream square knob, the time under the pointer ---------- */\n.sm-player-rail{position:relative;flex:1 1 auto;min-width:48px;height:24px;cursor:pointer;touch-action:none;outline:none}\n.sm-player-rail:focus-visible{outline:2px solid var(--sm-gold);outline-offset:2px;border-radius:var(--r-2,4px)}\n.sm-player-track{position:absolute;left:0;right:0;top:50%;height:6px;margin-top:-3px;border-radius:3px;background:rgba(247,240,219,.28);overflow:hidden;transition:transform var(--sm-out) var(--sm-ease)}\n.sm-player-buffered,.sm-player-played{position:absolute;inset:0;transform-origin:left center;transform:scaleX(0)}\n.sm-player-buffered{background:rgba(247,240,219,.18)}\n.sm-player-played{background:var(--sm-cream)}\n.sm-player-head{position:absolute;inset:0;pointer-events:none;transform:translateX(0)}\n.sm-player[data-playing] .sm-player-head,.sm-player[data-playing] .sm-player-played,.sm-player-rail[data-drag] .sm-player-head{will-change:transform}\n.sm-player-knob{position:absolute;top:50%;left:0;width:16px;height:16px;margin:-8px 0 0 -8px;border-radius:4px;background:var(--sm-cream);box-shadow:0 0 0 3px rgba(10,10,10,.35);transform:scale(0);transition:transform var(--sm-out) var(--sm-spring)}\n.sm-player-rail:hover .sm-player-knob,.sm-player-rail[data-drag] .sm-player-knob,.sm-player-rail:focus-visible .sm-player-knob{transform:scale(1)}\n.sm-player-rail:hover .sm-player-track,.sm-player-rail[data-drag] .sm-player-track{transform:scaleY(1.34)}\n.sm-player-tip{position:absolute;bottom:calc(100% + 4px);left:0;padding:3px 7px;border-radius:var(--r-2,4px);background:var(--sm-ink);border:1px solid rgba(247,240,219,.14);color:var(--sm-cream);font-size:12px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity var(--sm-out) var(--sm-ease)}\n.sm-player-rail:hover .sm-player-tip,.sm-player-rail[data-drag] .sm-player-tip{opacity:1}\n\n/* ---------- Time: \"0:12 / 0:34\", the total at 55% ---------- */\n.sm-player-time{flex:none;font-family:var(--sm-display);font-style:italic;font-weight:200;font-size:22px;line-height:1;letter-spacing:-.01em;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--sm-cream);text-shadow:0 1px 8px rgba(10,10,10,.6)}\n:where(.sm-player,.sm-viewer) .sm-media-of{opacity:.55}\n\n/* ---------- Narrow players step down by measured width so the bar never overflows (November 2, 2026: a 320 px vertical\n result clipped full screen): under 400 px no total and a smaller clock, under 300 px no clock, under 240 px no sound,\n under 180 px only play and full screen. The timeline keeps at least 48 px. ---------- */\n.sm-player[data-size] .sm-player-bar{gap:8px}\n.sm-player[data-size] .sm-player-total{display:none}\n.sm-player[data-size] .sm-player-time{font-size:18px}\n.sm-player:is([data-size=\"compact\"],[data-size=\"tiny\"],[data-size=\"micro\"]) .sm-player-time{display:none}\n.sm-player:is([data-size=\"tiny\"],[data-size=\"micro\"]) [data-control=\"volume\"]{display:none}\n.sm-player[data-size=\"micro\"] .sm-player-bar>:not([data-control=\"play\"]):not([data-control=\"fullscreen\"]){display:none}\n\n/* ---------- Touch: 44 px targets ---------- */\n@media (hover:none){.sm-player-rail{height:44px}}\n\n/* ---------- Full screen, and theater mode where the page may not go full screen (top layer, safe areas) ---------- */\n.sm-player:fullscreen{width:100%;height:100%;max-width:none;max-height:none;border-radius:0}\n.sm-player[data-stage=\"theater\"]{position:fixed;inset:0;z-index:2147483000;display:block;width:auto;height:auto;max-width:none;max-height:none;margin:0;border:0;border-radius:0;padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);overflow:hidden;color:var(--sm-cream);background:var(--sm-ink)}\n.sm-player[data-stage=\"theater\"]::backdrop{background:var(--sm-ink)}\n.sm-player:fullscreen .sm-player-bar,.sm-player[data-stage] .sm-player-bar{left:max(12px,env(safe-area-inset-left,0px));right:max(12px,env(safe-area-inset-right,0px));bottom:max(12px,env(safe-area-inset-bottom,0px))}\n\n/* ---------- Photo button: the video's full-screen square in the same corner, bottom right. 44 px on photos at least 240 px\n wide, 32 px under that (data-size=\"small\"). Shown only while the photo is hovered or the button has keyboard focus, and for\n 3 s after a tap on touch (data-show); hidden, it takes no pointer, so the first tap lands on the photo. ---------- */\n.sm-expand-host{position:relative}\n.sm-expand-btn{position:absolute;right:12px;bottom:12px;z-index:2;box-sizing:border-box;display:grid;place-items:center;width:44px;height:44px;min-width:0;min-height:0;margin:0;padding:0;border:0;border-radius:var(--r-3,8px);background:var(--sm-cream);color:var(--sm-ink);box-shadow:none;line-height:1;cursor:pointer;opacity:0;pointer-events:none;transition:opacity var(--sm-out) var(--sm-ease),transform var(--sm-out) var(--sm-spring)}\n.sm-expand-btn svg{display:block;width:20px;height:20px}\n.sm-expand-btn[data-size=\"small\"]{right:6px;bottom:6px;width:32px;height:32px;border-radius:6px}\n.sm-expand-btn[data-size=\"small\"] svg{width:16px;height:16px}\n.sm-expand-btn[data-size=\"small\"]::before{content:\"\";position:absolute;inset:-6px}\n@media (hover:hover){:hover>.sm-expand-btn{opacity:1;pointer-events:auto}.sm-expand-btn:hover{transform:translateY(-1px);background:var(--sm-cream);color:var(--sm-ink)}}\n.sm-expand-btn:focus-visible,.sm-expand-btn[data-show]{opacity:1;pointer-events:auto}\n.sm-expand-btn:active{transform:scale(.94)}\n.sm-expand-btn.sm-expand-btn.sm-expand-btn:focus-visible{outline:2px solid var(--sm-gold);outline-offset:2px}\n/* The same guard as the squares above (November 2, 2026): the look at 0,3,0 and 0,4,0, never position, size or display. */\n.sm-expand-btn.sm-expand-btn.sm-expand-btn{min-width:0;min-height:0;padding:0;border:0;border-radius:var(--r-3,8px);background:var(--sm-cream);color:var(--sm-ink);box-shadow:none;font:inherit;line-height:1;cursor:pointer}\n.sm-expand-btn.sm-expand-btn.sm-expand-btn[data-size=\"small\"]{border-radius:6px}\n.sm-expand-btn.sm-expand-btn.sm-expand-btn:hover{background:var(--sm-cream);color:var(--sm-ink)}\n\n/* ---------- Viewer: a modal dialog on ink, the photo contained, cream squares to close and move ---------- */\n.sm-viewer{position:fixed;inset:0;box-sizing:border-box;width:100%;height:100%;max-width:none;max-height:none;margin:0;padding:0;border:0;overflow:hidden;background:var(--sm-ink);color:var(--sm-cream);font-family:var(--font-body,\"Hanken Grotesk\",ui-sans-serif,system-ui,sans-serif)}\n.sm-viewer[open]{display:grid;grid-template-rows:minmax(0,1fr) auto;animation:sm-viewer-in var(--sm-in) var(--sm-ease) both}\n.sm-viewer::backdrop{background:var(--ink-600,#0A0A0A)}\n@keyframes sm-viewer-in{from{opacity:0}}\n.sm-viewer [hidden],.sm-viewer .sm-media-btn[hidden]{display:none}\n.sm-viewer-stage{position:relative;display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);place-items:center;min-width:0;min-height:0;overflow:hidden;padding:max(12px,env(safe-area-inset-top,0px)) max(12px,env(safe-area-inset-right,0px)) 12px max(12px,env(safe-area-inset-left,0px))}\n/* The stage is one 1fr cell, so the photo is held to the screen in both directions (November 2, 2026: it ran off the bottom). */\n.sm-viewer-media{display:block;width:100%;height:100%;min-width:0;min-height:0;object-fit:contain}\n.sm-viewer-stage>.sm-player{width:100%;height:100%;max-width:100%;max-height:100%}\n/* What cannot open here (a file kept on another device) is a quiet tile with no words (November 2, 2026: \"notices, not\n prose\"); the app's single toast says why. */\n.sm-viewer-off,.sm-player-off{display:inline-grid;place-items:center;box-sizing:border-box;border:1px solid var(--border-tok,#58534D);border-radius:var(--r-2,4px);background:var(--bg-inset,#171716);color:var(--fg-muted,#BBB2A7)}\n.sm-viewer-off{width:min(60vw,320px);aspect-ratio:4/3}\n.sm-player-off{width:min(100%,320px);max-width:100%;aspect-ratio:16/9;vertical-align:top}\n.sm-viewer-off svg,.sm-player-off svg{display:block;width:24px;height:24px}\n.sm-viewer-top{position:absolute;top:max(12px,env(safe-area-inset-top,0px));right:max(12px,env(safe-area-inset-right,0px));z-index:2;display:flex;gap:10px}\n.sm-viewer .sm-viewer-nav{position:absolute;top:50%;margin-top:-22px;z-index:2}\n.sm-viewer .sm-viewer-previous{left:max(12px,env(safe-area-inset-left,0px))}\n.sm-viewer .sm-viewer-next{right:max(12px,env(safe-area-inset-right,0px))}\n.sm-viewer-foot{display:flex;align-items:baseline;justify-content:center;gap:12px;min-width:0;padding:12px max(12px,env(safe-area-inset-right,0px)) max(14px,env(safe-area-inset-bottom,0px)) max(12px,env(safe-area-inset-left,0px))}\n.sm-viewer-count{flex:none;font-family:var(--sm-display);font-style:italic;font-weight:200;font-size:24px;line-height:1;letter-spacing:-.01em;font-variant-numeric:tabular-nums;white-space:nowrap}\n.sm-viewer-name{min-width:0;font-size:13px;color:var(--fg-muted,#BBB2A7);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n\n@media (prefers-reduced-motion:reduce){\n .sm-player *,.sm-viewer,.sm-viewer *,.sm-expand-btn{transition:none!important;animation:none!important}\n}\n\n/* Preview shape tiles in the transport bar: a quiet row of outlines sized to the bar. */\n.ve-shape-choices{display:flex;flex-shrink:0;gap:2px}\n/* November 2, 2026: only unpicked tiles go transparent; the pick keeps the kit's ink fill, since\n a transparent pick drew its shape in the page colour (the kit's colour:var(--bg)) and vanished. */\n.ve-shape-choices>label{min-height:28px;padding:4px 6px}\n.ve-shape-choices>label:not(:has(input:checked)){border-color:transparent;background:transparent}\n.ve-shape-choices .sm-shape{--sm-shape-size:16px;border-width:1.5px}\n",
199
- "javascript": "(function(){\"use strict\";var graph={\"view-BfB00tVc.js\":[\"react-Cd33N7Zq.js\",\"subscribeAnim-BqBgmjD4.js\",\"view-D6ZHgOjJ.js\"],\"MediaViewer-CkF9dtek.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"media-player-B5xtn5y5.js\"],\"MobileEditor-4328GdaI.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"editorTimelines-BHnIf5H0.js\",\"subscribeAnim-BqBgmjD4.js\",\"assetStore-4qfBrYoN.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"bind-CkWXB-UM.js\",\"boxOpacity-9sGMQ6qd.js\"],\"PanelBlocksPanel-C9reO-vH.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"contracts-C4-BRCqz.js\",\"subscribeAnim-BqBgmjD4.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"boxOpacity-9sGMQ6qd.js\"],\"VideoEditor-BZqIpoNf.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"editorTimelines-BHnIf5H0.js\",\"subscribeAnim-BqBgmjD4.js\",\"assetStore-4qfBrYoN.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"bind-CkWXB-UM.js\",\"speedSample-BXiYiZ4E.js\",\"boxOpacity-9sGMQ6qd.js\",\"media-player-B5xtn5y5.js\"],\"_frame-empty_wasm_vtracer_wasm_vtracer_bg_wasm_url-C085yj93.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"assetStore-4qfBrYoN.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"contracts-C4-BRCqz.js\"],\"bind-CkWXB-UM.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"sharedVault-mMOG3PsG.js\"],\"boxOpacity-9sGMQ6qd.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"editorTimelines-BHnIf5H0.js\",\"contracts-C4-BRCqz.js\",\"subscribeAnim-BqBgmjD4.js\",\"assetStore-4qfBrYoN.js\",\"type-workspace-U7I6uKdn.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"bind-CkWXB-UM.js\",\"sharedVault-mMOG3PsG.js\",\"vectorizeClient-CSsuV7Ew.js\"],\"boxOpacity-CxJqpgqJ.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"subscribeAnim-BqBgmjD4.js\"],\"browser-CGfns6yT.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"contracts-C4-BRCqz.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"editorAdds-CY8-DaYg.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"subscribeAnim-BqBgmjD4.js\"],\"editorTimelines-BHnIf5H0.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"contracts-C4-BRCqz.js\",\"subscribeAnim-BqBgmjD4.js\",\"type-workspace-U7I6uKdn.js\"],\"exportRender-BX-s25gI.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"boxOpacity-CxJqpgqJ.js\",\"bind-CkWXB-UM.js\",\"videoSource-_Ta7C4qY.js\"],\"exportRender-CIHSH4Lo.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"exportRender-BX-s25gI.js\"],\"favorites-BjGs2PS6.js\":[\"VideoEditor-BZqIpoNf.js\"],\"frameExtract-CpwOQS0p.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"imagetracer_v1.2.6-BBGerUPj.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"lamejs-Dix5aA0E.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"liveOverlaysCanvas-DfCRS-HH.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"media-player-B5xtn5y5.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"nativeRender-CFoK_eQg.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"boxOpacity-CxJqpgqJ.js\",\"videoSource-_Ta7C4qY.js\"],\"overlaysCanvas-CZA0FOpU.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"subscribeAnim-BqBgmjD4.js\",\"boxOpacity-CxJqpgqJ.js\"],\"panelExportProcess-CtsabYhm.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"type-workspace-U7I6uKdn.js\",\"boxOpacity-9sGMQ6qd.js\"],\"react-Cd33N7Zq.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"rolldown-runtime-BDP3x1s3.js\":[],\"sharedVault-mMOG3PsG.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"speedSample-BXiYiZ4E.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"subscribeAnim-BqBgmjD4.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"contracts-C4-BRCqz.js\"],\"type-workspace-U7I6uKdn.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"contracts-C4-BRCqz.js\",\"assetStore-4qfBrYoN.js\"],\"v2AssetGen-DLqHswHt.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"view-D6ZHgOjJ.js\",\"sharedVault-mMOG3PsG.js\",\"vectorizeClient-CSsuV7Ew.js\",\"vectorizeClient-BGAa1YU-.js\",\"boxOpacity-9sGMQ6qd.js\"],\"vectorizeClient-BGAa1YU-.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"vectorizeClient-CSsuV7Ew.js\"],\"vectorizeClient-CSsuV7Ew.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"videoSource-_Ta7C4qY.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-D6ZHgOjJ.js\",\"boxOpacity-CxJqpgqJ.js\",\"overlaysCanvas-CZA0FOpU.js\",\"bind-CkWXB-UM.js\",\"speedSample-BXiYiZ4E.js\",\"sharedVault-mMOG3PsG.js\"],\"view-D6ZHgOjJ.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-CY8-DaYg.js\",\"editorTimelines-BHnIf5H0.js\",\"contracts-C4-BRCqz.js\",\"subscribeAnim-BqBgmjD4.js\",\"assetStore-4qfBrYoN.js\",\"type-workspace-U7I6uKdn.js\"],\"wasm_vtracer_bg-BPZSQuDe.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"wavesurfer.esm-B4xOEftU.js\":[\"rolldown-runtime-BDP3x1s3.js\"]},dir=\"code/\",factories=Object.create(null),cache=Object.create(null),loading=Object.create(null);\nfunction name(id){return String(id).replace(/^\\.\\//,\"\")}\nfunction require(id){var key=name(id);if(cache[key])return cache[key].exports;var factory=factories[key];if(!factory)throw new Error(key+\" is not loaded\");var module={exports:{}};cache[key]=module;factory.call(undefined,module.exports,require,module,load);return module.exports}\nfunction needed(key,into){if(into.indexOf(key)<0){into.push(key);(graph[key]||[]).forEach(function(next){needed(next,into)})}return into}\nfunction get(key){if(factories[key])return Promise.resolve();return loading[key]||(loading[key]=StillMade.loadCode(dir+key).then(function(){if(!factories[key])throw new Error(dir+key+\" did not define its module\")},function(error){delete loading[key];throw error}))}\nfunction load(id){return Promise.all(needed(name(id),[]).map(get))}\nObject.defineProperty(globalThis,\"__stillmadeCode_bfe7de0f1190\",{value:Object.freeze({define:function(key,factory){if(!factories[key])factories[key]=factory}})});\nload(\"view-BfB00tVc.js\").then(function(){require(\"view-BfB00tVc.js\")}).catch(function(error){var note=document.createElement(\"p\");note.setAttribute(\"role\",\"alert\");note.style.cssText=\"margin:16px;color:var(--fg)\";note.textContent=\"This screen could not load: \"+(error&&error.message||error);(document.getElementById(\"root\")||document.body).appendChild(note);throw error})})();\n",
244
+ "javascript": "(function(){\"use strict\";var graph={\"view-Buc7ZedJ.js\":[\"react-Cd33N7Zq.js\",\"subscribeAnim-ByIUWu3t.js\",\"view-W38q_YTK.js\"],\"MediaViewer-CkF9dtek.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"media-player-B5xtn5y5.js\"],\"MobileEditor-P12YCSjz.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"editorTimelines-DBb3aAhU.js\",\"subscribeAnim-ByIUWu3t.js\",\"assetStore-BgsZckW8.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"bind-CAXOoUUg.js\",\"boxOpacity-Byax21hB.js\"],\"PanelBlocksPanel-BlaDyqG2.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"contracts-u4CPGmB0.js\",\"subscribeAnim-ByIUWu3t.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"boxOpacity-Byax21hB.js\"],\"VideoEditor-CR3JAl4f.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"editorTimelines-DBb3aAhU.js\",\"subscribeAnim-ByIUWu3t.js\",\"assetStore-BgsZckW8.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"bind-CAXOoUUg.js\",\"speedSample-BXiYiZ4E.js\",\"boxOpacity-Byax21hB.js\",\"media-player-B5xtn5y5.js\"],\"_frame-empty_wasm_vtracer_wasm_vtracer_bg_wasm_url-C085yj93.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"assetStore-BgsZckW8.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"contracts-u4CPGmB0.js\"],\"bind-CAXOoUUg.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"sharedVault-mMOG3PsG.js\"],\"boxOpacity-Byax21hB.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"editorTimelines-DBb3aAhU.js\",\"contracts-u4CPGmB0.js\",\"subscribeAnim-ByIUWu3t.js\",\"assetStore-BgsZckW8.js\",\"type-workspace-X5ESexG7.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"bind-CAXOoUUg.js\",\"sharedVault-mMOG3PsG.js\",\"vectorizeClient-CSsuV7Ew.js\"],\"boxOpacity-CB2dZ7DS.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"subscribeAnim-ByIUWu3t.js\"],\"browser-CGfns6yT.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"contracts-u4CPGmB0.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"editorAdds-C13FvFcr.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"subscribeAnim-ByIUWu3t.js\"],\"editorTimelines-DBb3aAhU.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"contracts-u4CPGmB0.js\",\"subscribeAnim-ByIUWu3t.js\",\"type-workspace-X5ESexG7.js\"],\"exportRender-Bsh5AgLZ.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"boxOpacity-CB2dZ7DS.js\",\"bind-CAXOoUUg.js\",\"videoSource-HzOCEBWk.js\"],\"exportRender-CHsHRApZ.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"exportRender-Bsh5AgLZ.js\"],\"favorites-MjtjQgnp.js\":[\"VideoEditor-CR3JAl4f.js\"],\"frameExtract-CpwOQS0p.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"imagetracer_v1.2.6-BBGerUPj.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"lamejs-Dix5aA0E.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"liveOverlaysCanvas-DfCRS-HH.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"media-player-B5xtn5y5.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"nativeRender-Buwn2f5w.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"boxOpacity-CB2dZ7DS.js\",\"videoSource-HzOCEBWk.js\"],\"overlaysCanvas-Bhxk3pwo.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"subscribeAnim-ByIUWu3t.js\",\"boxOpacity-CB2dZ7DS.js\"],\"panelExportProcess-Cb63eg8e.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"type-workspace-X5ESexG7.js\",\"boxOpacity-Byax21hB.js\"],\"react-Cd33N7Zq.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"rolldown-runtime-BDP3x1s3.js\":[],\"sharedVault-mMOG3PsG.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"speedSample-BXiYiZ4E.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"subscribeAnim-ByIUWu3t.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"contracts-u4CPGmB0.js\"],\"type-workspace-X5ESexG7.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"contracts-u4CPGmB0.js\",\"assetStore-BgsZckW8.js\"],\"v2AssetGen-D5a31k1h.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"view-W38q_YTK.js\",\"sharedVault-mMOG3PsG.js\",\"vectorizeClient-CSsuV7Ew.js\",\"vectorizeClient-BGAa1YU-.js\",\"boxOpacity-Byax21hB.js\"],\"vectorizeClient-BGAa1YU-.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"vectorizeClient-CSsuV7Ew.js\"],\"vectorizeClient-CSsuV7Ew.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"videoSource-HzOCEBWk.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"liveOverlaysCanvas-DfCRS-HH.js\",\"view-W38q_YTK.js\",\"boxOpacity-CB2dZ7DS.js\",\"overlaysCanvas-Bhxk3pwo.js\",\"bind-CAXOoUUg.js\",\"speedSample-BXiYiZ4E.js\",\"sharedVault-mMOG3PsG.js\"],\"view-W38q_YTK.js\":[\"rolldown-runtime-BDP3x1s3.js\",\"react-Cd33N7Zq.js\",\"editorAdds-C13FvFcr.js\",\"editorTimelines-DBb3aAhU.js\",\"contracts-u4CPGmB0.js\",\"subscribeAnim-ByIUWu3t.js\",\"assetStore-BgsZckW8.js\",\"type-workspace-X5ESexG7.js\"],\"wasm_vtracer_bg-BPZSQuDe.js\":[\"rolldown-runtime-BDP3x1s3.js\"],\"wavesurfer.esm-B4xOEftU.js\":[\"rolldown-runtime-BDP3x1s3.js\"]},dir=\"code/\",factories=Object.create(null),cache=Object.create(null),loading=Object.create(null);\nfunction name(id){return String(id).replace(/^\\.\\//,\"\")}\nfunction require(id){var key=name(id);if(cache[key])return cache[key].exports;var factory=factories[key];if(!factory)throw new Error(key+\" is not loaded\");var module={exports:{}};cache[key]=module;factory.call(undefined,module.exports,require,module,load);return module.exports}\nfunction needed(key,into){if(into.indexOf(key)<0){into.push(key);(graph[key]||[]).forEach(function(next){needed(next,into)})}return into}\nfunction get(key){if(factories[key])return Promise.resolve();return loading[key]||(loading[key]=StillMade.loadCode(dir+key).then(function(){if(!factories[key])throw new Error(dir+key+\" did not define its module\")},function(error){delete loading[key];throw error}))}\nfunction load(id){return Promise.all(needed(name(id),[]).map(get))}\nObject.defineProperty(globalThis,\"__stillmadeCode_36e1c140cee8\",{value:Object.freeze({define:function(key,factory){if(!factories[key])factories[key]=factory}})});\nload(\"view-Buc7ZedJ.js\").then(function(){require(\"view-Buc7ZedJ.js\")}).catch(function(error){var note=document.createElement(\"p\");note.setAttribute(\"role\",\"alert\");note.style.cssText=\"margin:16px;color:var(--fg)\";note.textContent=\"This screen could not load: \"+(error&&error.message||error);(document.getElementById(\"root\")||document.body).appendChild(note);throw error})})();\n",
200
245
  "runtime": "frame",
201
246
  "files": {
202
247
  "schemaVersion": 1,
203
248
  "files": {
204
249
  "code/MediaViewer-CkF9dtek.js": {
205
- "sha256": "eac30aa758e33337a22be61e860b6131c1260f1bba75a02712f3e9a94bd7f806",
250
+ "sha256": "ed16abcebdc878791e89f8ac3af247d404d3e89057d13974a01b28da18586a79",
206
251
  "bytes": 1053,
207
252
  "mediaType": "text/javascript"
208
253
  },
209
- "code/MobileEditor-4328GdaI.js": {
210
- "sha256": "6879f1f36e6ffd18b53e4d828ef6589aa5edfc4097f6ba5de00765650cadac42",
211
- "bytes": 168629,
254
+ "code/MobileEditor-P12YCSjz.js": {
255
+ "sha256": "790778f9bbe6cd9733ffef63e7d7bfc92b7fddb1b0733deacdaefe627db5bf10",
256
+ "bytes": 168693,
212
257
  "mediaType": "text/javascript"
213
258
  },
214
- "code/PanelBlocksPanel-C9reO-vH.js": {
215
- "sha256": "0efaea039fe4d7a9c2232864fdb29611f036f4257089353082fd0f803224bcf6",
259
+ "code/PanelBlocksPanel-BlaDyqG2.js": {
260
+ "sha256": "cda4804520ddb881dfe59c79b794a13b155e239f6460e41226d985daf9f09eb7",
216
261
  "bytes": 316146,
217
262
  "mediaType": "text/javascript"
218
263
  },
219
- "code/VideoEditor-BZqIpoNf.js": {
220
- "sha256": "e0ee96e1d64c8c7e43ae43702ce733d35c7c49bb59041d38f6fbeb97c50bd577",
221
- "bytes": 482065,
264
+ "code/VideoEditor-CR3JAl4f.js": {
265
+ "sha256": "53c22b3ec8be8a81ff5dcd9cf9a969c280e2875f7416d01ddbc86e50fa6b20cd",
266
+ "bytes": 482260,
222
267
  "mediaType": "text/javascript"
223
268
  },
224
269
  "code/_frame-empty_wasm_vtracer_wasm_vtracer_bg_wasm_url-C085yj93.js": {
225
- "sha256": "3e40e2c88eb2e7e3c02279b36e87b6a5ce8f5d5b530ffb26f4d01247bb533c50",
270
+ "sha256": "29fd829982f802ca660e7f5d1b797c243c3cd74cda95f64fec6471f7d0ec8d03",
226
271
  "bytes": 269,
227
272
  "mediaType": "text/javascript"
228
273
  },
229
- "code/assetStore-4qfBrYoN.js": {
230
- "sha256": "6b4d8a0f74b3a79fd847747ecd5e9affd69a7a89884c620dce0b74f8c04bfe52",
274
+ "code/assetStore-BgsZckW8.js": {
275
+ "sha256": "36c05daff552c567b62f01c8d31cd9d4af5608b9e6489c18f7123021e8d4c274",
231
276
  "bytes": 1511,
232
277
  "mediaType": "text/javascript"
233
278
  },
234
- "code/bind-CkWXB-UM.js": {
235
- "sha256": "ae8c618bb3dd1d3732a6757574b8a8197a6c5e592ff508c8e8498fd5286be5cb",
279
+ "code/bind-CAXOoUUg.js": {
280
+ "sha256": "1ca4a9a579235d6a042124eae3e790e5af30d8b5be88f62c32a97523ce859f26",
236
281
  "bytes": 349873,
237
282
  "mediaType": "text/javascript"
238
283
  },
239
- "code/boxOpacity-9sGMQ6qd.js": {
240
- "sha256": "d5e29d286668b102b28480985b55a62f7025fd2e0f2c7dea9405c8ca389b72e8",
284
+ "code/boxOpacity-Byax21hB.js": {
285
+ "sha256": "e5f7d12fed4f5ba6c466aa366efee2a74950e87d256112a180cd09a7d1813d98",
241
286
  "bytes": 350824,
242
287
  "mediaType": "text/javascript"
243
288
  },
244
- "code/boxOpacity-CxJqpgqJ.js": {
245
- "sha256": "c91ac644c4fc9d8febe12384631bfaeca3bd6a3b1efecc2b83d8e0ec39cff62b",
289
+ "code/boxOpacity-CB2dZ7DS.js": {
290
+ "sha256": "d82ab04820cf8ffa8a5450a941fa84e74c8ed880cda94f80b1f222b04e58bcde",
246
291
  "bytes": 14167,
247
292
  "mediaType": "text/javascript"
248
293
  },
249
294
  "code/browser-CGfns6yT.js": {
250
- "sha256": "d2f9a02fe41bee7e21eaeae2e4b447ada01cb798ab331e854ddd653a70b7973f",
295
+ "sha256": "1a4d1868882257be19382e1ff42bf6bb84db870c58450719dc9c18ca86ac854d",
251
296
  "bytes": 12691,
252
297
  "mediaType": "text/javascript"
253
298
  },
254
- "code/contracts-C4-BRCqz.js": {
255
- "sha256": "592eb96757265e95b566a5c8d9e4dd63cf338e9b4b9c211d141757a3b6fe1d25",
256
- "bytes": 63845,
299
+ "code/contracts-u4CPGmB0.js": {
300
+ "sha256": "fa68cd4fc539b58b8fc7f0c10566fbb597eb84062a642124894f637792097205",
301
+ "bytes": 63894,
257
302
  "mediaType": "text/javascript"
258
303
  },
259
- "code/editorAdds-CY8-DaYg.js": {
260
- "sha256": "fade9743324565452281dc83233b02217db439dfb6413e02c33c05ba11b8c1e8",
304
+ "code/editorAdds-C13FvFcr.js": {
305
+ "sha256": "224069ac25000437186456cfa839232ebc7b0e8868d4f753ceb70e251e7ab60e",
261
306
  "bytes": 194975,
262
307
  "mediaType": "text/javascript"
263
308
  },
264
- "code/editorTimelines-BHnIf5H0.js": {
265
- "sha256": "52c10f896a6780f7569615c092fe5d9c148df66cd205b9c4d1390a0af6a25397",
309
+ "code/editorTimelines-DBb3aAhU.js": {
310
+ "sha256": "3a276ed86dae49afe213827dd20fbf83199ee21e3d9e5fb093e3f47b2b5c6c98",
266
311
  "bytes": 69058,
267
312
  "mediaType": "text/javascript"
268
313
  },
269
- "code/exportRender-BX-s25gI.js": {
270
- "sha256": "52d04c4072fddbf83977705fb376cfa2cef9984003886b30a523bbac87826473",
314
+ "code/exportRender-Bsh5AgLZ.js": {
315
+ "sha256": "7ec5c4b2e9240bad1cf30650ff5d018deb5dbf80aa4abffcbb1506e7add0afdc",
271
316
  "bytes": 47153,
272
317
  "mediaType": "text/javascript"
273
318
  },
274
- "code/exportRender-CIHSH4Lo.js": {
275
- "sha256": "d20409213361c326f9f5e3b39bc4345f2ee7689dcf2a1a45f12b81d10e5d625c",
319
+ "code/exportRender-CHsHRApZ.js": {
320
+ "sha256": "dad4e8bb10fd91c996de4af53c484e6af7f4f5069cbc6c3f67d13f8fa9c5a1bd",
276
321
  "bytes": 348,
277
322
  "mediaType": "text/javascript"
278
323
  },
279
- "code/favorites-BjGs2PS6.js": {
280
- "sha256": "a353dac5bf2ce1a73ceb8835ba9c5ab72b5c5d9b6a403a9dc3941af42ec2a467",
324
+ "code/favorites-MjtjQgnp.js": {
325
+ "sha256": "e8280992fa2c0c925ad2f8c136cf442df2ea67c3b5f6f4cbedae2c17d6ddecea",
281
326
  "bytes": 182,
282
327
  "mediaType": "text/javascript"
283
328
  },
284
329
  "code/frameExtract-CpwOQS0p.js": {
285
- "sha256": "cfa13d283c3abc4bcfe9fef0862a0fbd90c1b0bb7e94c60b5410f4ed88fd1d20",
330
+ "sha256": "c783313a5960c641323016bed621a685a47478f128a24361d91cc133dd0bbc3a",
286
331
  "bytes": 1336,
287
332
  "mediaType": "text/javascript"
288
333
  },
289
334
  "code/imagetracer_v1.2.6-BBGerUPj.js": {
290
- "sha256": "d009214481dc2dd2cf4e15acfcc2b0f88991d70d68265780f22e6fd1b1e15ba3",
335
+ "sha256": "26444c080368d4345507288574ab04aea4b23923d6565d3e1df6453cc34c4172",
291
336
  "bytes": 19877,
292
337
  "mediaType": "text/javascript"
293
338
  },
294
339
  "code/lamejs-Dix5aA0E.js": {
295
- "sha256": "904e6e081c287058228e1f6f63853018dab0cfbe820b3fd1774e81107c06979d",
340
+ "sha256": "366394c17eca4689a595377e87a9209e6effbd8017b89073890c1394cfdf2795",
296
341
  "bytes": 163273,
297
342
  "mediaType": "text/javascript"
298
343
  },
299
344
  "code/liveOverlaysCanvas-DfCRS-HH.js": {
300
- "sha256": "32b8d87fb1723ef9608f713f96c125348f444fa29ce483d2e904ef913282e1cd",
345
+ "sha256": "b98ad8c6280538db9f9f19282b333e63064aba24e2678a8a991304f9ac0dcc1f",
301
346
  "bytes": 34146,
302
347
  "mediaType": "text/javascript"
303
348
  },
304
349
  "code/media-player-B5xtn5y5.js": {
305
- "sha256": "0b769c5f5ce2b164d396f8baeea71fee5160164e2dd01ed4774a48ea44d5f616",
350
+ "sha256": "3e0aa6329f01a826213ec1c40f53312eb7aabaebf64ec0b4e88e9ef038e1f6c0",
306
351
  "bytes": 19849,
307
352
  "mediaType": "text/javascript"
308
353
  },
309
- "code/nativeRender-CFoK_eQg.js": {
310
- "sha256": "cee4c4e812a36119214d8303a5ac0689157c4225c109ed5ba48bbdcfeb095a11",
354
+ "code/nativeRender-Buwn2f5w.js": {
355
+ "sha256": "9b5bca4305a412d21f786f8bca9c4db213df893d862b73bd8103154e3fa5e868",
311
356
  "bytes": 2601,
312
357
  "mediaType": "text/javascript"
313
358
  },
314
- "code/overlaysCanvas-CZA0FOpU.js": {
315
- "sha256": "dbced64f8d142c0cdcd632ac4483ac702cd0efaf9815cbd34ec06e7199f3d96c",
359
+ "code/overlaysCanvas-Bhxk3pwo.js": {
360
+ "sha256": "0335e53eb149122bf3cfdbe70917eb87468834b23eda796ebdc7e3d023887a26",
316
361
  "bytes": 11939,
317
362
  "mediaType": "text/javascript"
318
363
  },
319
- "code/panelExportProcess-CtsabYhm.js": {
320
- "sha256": "3ce40f40a4320178b260a7d9b2382003512d1ba1ce4b0cef5f8ee2f70b3b71e9",
364
+ "code/panelExportProcess-Cb63eg8e.js": {
365
+ "sha256": "d771ac56cc89bb6fc168542dfa0e807cf62698c2d0e7002480e9c5cfdf7401d3",
321
366
  "bytes": 4590,
322
367
  "mediaType": "text/javascript"
323
368
  },
324
369
  "code/react-Cd33N7Zq.js": {
325
- "sha256": "dc117c28ee56e749811ab506aaff7f557cf02fc5b3c442870d0f77290088841d",
370
+ "sha256": "6c3e1149164f63873ac74d1587ccfa2d9b2ec2bd3449eabb3359751a6878e7ca",
326
371
  "bytes": 6674,
327
372
  "mediaType": "text/javascript"
328
373
  },
329
374
  "code/rolldown-runtime-BDP3x1s3.js": {
330
- "sha256": "2b1ef09b125440faa4d23ca16dc11c30ab4f9e3c3cb853c09f231bb2bba6e0c4",
375
+ "sha256": "347f415842e9070f7ac9edbd494eac69b7b874426f9f5cbac4dd4abff885b73d",
331
376
  "bytes": 1189,
332
377
  "mediaType": "text/javascript"
333
378
  },
334
379
  "code/sharedVault-mMOG3PsG.js": {
335
- "sha256": "132fed136a9462896c81b15f33e2d17c735f1405b2ba2d0616ecf67978850d93",
380
+ "sha256": "a849ce4aac772fdfa91ed87d0501f51545ed2787f9a35f27b23b4ea5ebe7cd83",
336
381
  "bytes": 3026,
337
382
  "mediaType": "text/javascript"
338
383
  },
339
384
  "code/speedSample-BXiYiZ4E.js": {
340
- "sha256": "a2a79e6ee7fb228f41fe88c1c0d607dbb751441383dafad696c613dc4de4a722",
385
+ "sha256": "e209e0a342817e813a3c939b574eea8cc2f73bd803c255ee03bfa2eb687130a2",
341
386
  "bytes": 1474,
342
387
  "mediaType": "text/javascript"
343
388
  },
344
- "code/subscribeAnim-BqBgmjD4.js": {
345
- "sha256": "5c9bb6e7a680d3ea915cf0303615d5826c46075883e2fe1419020d7f3737a9f2",
389
+ "code/subscribeAnim-ByIUWu3t.js": {
390
+ "sha256": "c28c5f58a08135b21e14e819bb904d807891698289d915aa28cb45452d4fb4ff",
346
391
  "bytes": 3786,
347
392
  "mediaType": "text/javascript"
348
393
  },
349
- "code/type-workspace-U7I6uKdn.js": {
350
- "sha256": "c92be71bd8dedcf00bae589ede879e2e997cfdc2b4243ab27e5eb0ebd3d5a801",
394
+ "code/type-workspace-X5ESexG7.js": {
395
+ "sha256": "bd39948c580f863a6156b6bab918c61bc518a161af33e6c6d9843f547e1dc4a8",
351
396
  "bytes": 260765,
352
397
  "mediaType": "text/javascript"
353
398
  },
354
- "code/v2AssetGen-DLqHswHt.js": {
355
- "sha256": "01b59599e773423ca9a1e532de58588e4fcc1a9b08cfb9fb0b4d97cdd6c7ab89",
399
+ "code/v2AssetGen-D5a31k1h.js": {
400
+ "sha256": "f534893ea7ec925b057da5c90cea364df291335a5facc58cb12212459ac7d79d",
356
401
  "bytes": 3973,
357
402
  "mediaType": "text/javascript"
358
403
  },
359
404
  "code/vectorizeClient-BGAa1YU-.js": {
360
- "sha256": "6c5d15c18ed47437dba544170365396de0f8a45673090e80978b41d837fd941f",
405
+ "sha256": "db1d48ba7c8846816641ed19392e9af96fd2959f11a4003cdd937937916907af",
361
406
  "bytes": 442,
362
407
  "mediaType": "text/javascript"
363
408
  },
364
409
  "code/vectorizeClient-CSsuV7Ew.js": {
365
- "sha256": "37fb517aad0735abc6623695531c80ce8bb93493db5958e3ffb577fbb0413238",
410
+ "sha256": "55e6fe25b1764e0210bdce5a326b94ad01c1480fdfb3cc5a2614c3fb1eaa3629",
366
411
  "bytes": 5278,
367
412
  "mediaType": "text/javascript"
368
413
  },
369
- "code/videoSource-_Ta7C4qY.js": {
370
- "sha256": "7c065246e96ba90174f982dd054bcec8adc859ee3aa47f9897d8471e7d1b998f",
414
+ "code/videoSource-HzOCEBWk.js": {
415
+ "sha256": "ad272f517849419b9e4592852724bfa390cc0f4914419973b771a1d792359b94",
371
416
  "bytes": 193830,
372
417
  "mediaType": "text/javascript"
373
418
  },
374
- "code/view-BfB00tVc.js": {
375
- "sha256": "3b9fba1385b889bee750d47e6d15db4dbdc32de4a38ed27c910e1fefe88a09c7",
419
+ "code/view-Buc7ZedJ.js": {
420
+ "sha256": "bb32b8b0df247ea2cec0f39589d6f4a9abdcad01eee07edc2071c6e678e8b50d",
376
421
  "bytes": 206,
377
422
  "mediaType": "text/javascript"
378
423
  },
379
- "code/view-D6ZHgOjJ.js": {
380
- "sha256": "ed493c8af9d76d98f57a3cc2ff7bd4185800496fa06a20e68925a88ec5a1c4e0",
381
- "bytes": 273199,
424
+ "code/view-W38q_YTK.js": {
425
+ "sha256": "86fb101713ed05c5b298a61b7f565c39afdbc9a58f7f220d87811211fc479f66",
426
+ "bytes": 273459,
382
427
  "mediaType": "text/javascript"
383
428
  },
384
429
  "code/wasm_vtracer_bg-BPZSQuDe.js": {
385
- "sha256": "caaedb09a5fada258aa4cf45828fd87e222ab5317b82d52adbe56cee580d6149",
430
+ "sha256": "ff0a0e69a6dc2e4870bd6da840f2430923f02f2e3acad9512844b0a68032f93e",
386
431
  "bytes": 6530,
387
432
  "mediaType": "text/javascript"
388
433
  },
389
434
  "code/wavesurfer.esm-B4xOEftU.js": {
390
- "sha256": "5b20537b49d64ca4af8985c25d4013416eff880aa5fe3b967ff69cfd682389fb",
435
+ "sha256": "c8dc4c025559314823c3a4e117afd9e5bee1d681af9f912561d7c6d893537a71",
391
436
  "bytes": 39687,
392
437
  "mediaType": "text/javascript"
393
438
  }
@@ -746,6 +791,6 @@ export default {
746
791
  }
747
792
  ],
748
793
  "moduleSource": {
749
- "main.js": "//#region blocks/native/sm.editor/frame/main.js\nconst fail = (message) => {\n\tthrow Error(message);\n};\nconst plain = (value) => !!value && typeof value === \"object\" && !Array.isArray(value);\nconst isMedia = (value, kind) => plain(value) && typeof value.url === \"string\" && typeof value.assetId === \"string\" && (!kind || value.kind === kind);\nconst dataUrlBytes = (dataUrl) => {\n\tconst match = /^data:([a-z]+\\/[a-z0-9.+-]+)(?:;[^,;]*)*;base64,(.+)$/i.exec(String(dataUrl || \"\"));\n\tif (!match) fail(\"Choose a file to save.\");\n\tconst text = atob(match[2]), bytes = new Uint8Array(text.length);\n\tfor (let index = 0; index < text.length; index++) bytes[index] = text.charCodeAt(index);\n\treturn {\n\t\tmediaType: match[1].toLowerCase(),\n\t\tbuffer: bytes.buffer\n\t};\n};\nconst EXTENSIONS = {\n\t\"image/png\": \"png\",\n\t\"image/jpeg\": \"jpg\",\n\t\"image/webp\": \"webp\",\n\t\"image/gif\": \"gif\",\n\t\"video/mp4\": \"mp4\",\n\t\"video/webm\": \"webm\",\n\t\"video/quicktime\": \"mov\",\n\t\"audio/mpeg\": \"mp3\",\n\t\"audio/wav\": \"wav\",\n\t\"audio/x-wav\": \"wav\",\n\t\"audio/mp4\": \"m4a\",\n\t\"audio/ogg\": \"ogg\",\n\t\"audio/webm\": \"webm\"\n};\nasync function run(input, stillmade) {\n\tconst make = typeof input.make === \"string\" ? input.make : \"use\";\n\tconst request = plain(input.request) ? input.request : {};\n\tconst references = (Array.isArray(input.references) ? input.references : []).filter((value) => isMedia(value, \"image\"));\n\tconst editor = plain(input.editor) ? {\n\t\t...input.editor,\n\t\tschemaVersion: input.editor.schemaVersion ?? 1\n\t} : null;\n\tconst done = (result, made = []) => ({\n\t\t...editor ? { editor } : {},\n\t\t...made.length ? { made } : {},\n\t\tresult: result === void 0 ? null : result\n\t});\n\tswitch (make) {\n\t\tcase \"use\": return done(null);\n\t\tcase \"image\": {\n\t\t\tif (typeof request.readablePrompt !== \"string\" || !request.readablePrompt.trim()) fail(\"Write what the picture shows first.\");\n\t\t\tstillmade.progress(.2, \"Making the picture\");\n\t\t\tconst settings = Object.fromEntries(Object.entries({\n\t\t\t\tmodel: request.model,\n\t\t\t\taspectRatio: request.aspectRatio,\n\t\t\t\tquality: request.quality,\n\t\t\t\tresolution: request.resolution\n\t\t\t}).filter(([, value]) => typeof value === \"string\" && value));\n\t\t\tconst made = await stillmade.hosted.run(\"image.generate\", {\n\t\t\t\tprompt: request.readablePrompt,\n\t\t\t\t...references.length ? { references: references.slice(0, 8) } : {},\n\t\t\t\t...Object.keys(settings).length ? { settings } : {}\n\t\t\t});\n\t\t\treturn done(made, [made]);\n\t\t}\n\t\tcase \"video\": {\n\t\t\tstillmade.progress(.1, \"Making the clip\");\n\t\t\tconst settings = Object.fromEntries(Object.entries({\n\t\t\t\tmodel: request.model,\n\t\t\t\taspectRatio: request.aspectRatio,\n\t\t\t\tquality: request.quality,\n\t\t\t\tresolution: request.resolution,\n\t\t\t\tduration: request.duration,\n\t\t\t\tseed: request.seed,\n\t\t\t\tgenerateAudio: request.generateAudio\n\t\t\t}).filter(([, value]) => value !== void 0 && value !== null && value !== \"\"));\n\t\t\tconst made = await stillmade.hosted.run(\"video.generate\", {\n\t\t\t\tprompt: request.readablePrompt || \"\",\n\t\t\t\t...isMedia(input.firstFrame, \"image\") ? { firstFrame: input.firstFrame } : {},\n\t\t\t\t...isMedia(input.lastFrame, \"image\") ? { lastFrame: input.lastFrame } : {},\n\t\t\t\t...request.negativePrompt ? { negativePrompt: request.negativePrompt } : {},\n\t\t\t\t...Object.keys(settings).length ? { settings } : {}\n\t\t\t});\n\t\t\treturn done(made, [made]);\n\t\t}\n\t\tcase \"transcribe\": {\n\t\t\tif (!isMedia(input.audio)) fail(\"Choose the sound to transcribe.\");\n\t\t\tstillmade.progress(.2, \"Finding the words\");\n\t\t\tconst timing = await stillmade.hosted.run(\"audio.transcribe\", { audio: input.audio });\n\t\t\tconst words = (Array.isArray(timing?.words) ? timing.words : []).map((word) => ({\n\t\t\t\tword: word.text ?? word.word,\n\t\t\t\ttext: word.text ?? word.word,\n\t\t\t\tstart: word.start,\n\t\t\t\tend: word.end\n\t\t\t}));\n\t\t\treturn done({\n\t\t\t\ttext: String(timing?.text || words.map((word) => word.text).join(\" \")),\n\t\t\t\twords\n\t\t\t});\n\t\t}\n\t\tcase \"upload\": {\n\t\t\tconst { mediaType, buffer } = dataUrlBytes(input.dataUrl);\n\t\t\tconst extension = EXTENSIONS[mediaType] || fail(\"Save a picture, a clip or a sound file.\");\n\t\t\tconst name = String(input.key || `upload.${extension}`).replace(/[^\\w.-]+/g, \"-\").slice(0, 120) || `upload.${extension}`;\n\t\t\tconst saved = await stillmade.files.write(buffer, {\n\t\t\t\tmediaType,\n\t\t\t\tname: /\\.[a-z0-9]{2,5}$/i.test(name) ? name : `${name}.${extension}`\n\t\t\t});\n\t\t\treturn done(saved, [saved]);\n\t\t}\n\t\tcase \"export\": {\n\t\t\tconst kind = request.kind === \"audio\" ? \"audio\" : \"video\";\n\t\t\tstillmade.progress(.05, kind === \"audio\" ? \"Mixing the sound\" : \"Rendering the video\");\n\t\t\tconst { asset } = await stillmade.actions.run({\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tkind: \"stillmade.media-action\",\n\t\t\t\toperation: \"final.render\",\n\t\t\t\tresultPort: null,\n\t\t\t\trequest: {\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tkind,\n\t\t\t\t\ttimeline: request.timeline,\n\t\t\t\t\tsettings: request.settings,\n\t\t\t\t\tsource: plain(request.source) ? request.source : {\n\t\t\t\t\t\tid: \"sm.editor\",\n\t\t\t\t\t\tversion: \"3.0.0\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst kept = {\n\t\t\t\tkind: asset.kind,\n\t\t\t\tassetId: asset.assetId,\n\t\t\t\tversionId: asset.versionId,\n\t\t\t\turl: asset.url,\n\t\t\t\t...asset.mimeType ? { mimeType: asset.mimeType } : {},\n\t\t\t\t...Number(asset.duration) > 0 ? { duration: Number(asset.duration) } : {}\n\t\t\t};\n\t\t\treturn {\n\t\t\t\t...done(kept, [kept]),\n\t\t\t\texport: kept\n\t\t\t};\n\t\t}\n\t\tcase \"stock-status\": return done({ available: true });\n\t\tcase \"stock-grid\": {\n\t\t\tconst { results } = await stillmade.actions.run({\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tkind: \"stillmade.media-action\",\n\t\t\t\toperation: \"stock.search\",\n\t\t\t\tresultPort: null,\n\t\t\t\trequest: {\n\t\t\t\t\tquery: String(request.query || request.q || \"\").slice(0, 500) || \"scene\",\n\t\t\t\t\ttype: request.type === \"video\" ? \"video\" : \"photo\"\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn done(results || []);\n\t\t}\n\t\tcase \"storage-get\": return done(await stillmade.storage.get(String(input.key || \"\")));\n\t\tcase \"storage-set\":\n\t\t\tawait stillmade.storage.set(String(input.key || \"\"), input.value ?? null);\n\t\t\treturn done(true);\n\t}\n\tfail(`${make} is not something the Editor Block does yet.`);\n}\n\n//#endregion\nexport { run as default };"
794
+ "main.js": "//#region blocks/native/sm.editor/frame/main.js\nconst fail = (message) => {\n\tthrow Error(message);\n};\nconst plain = (value) => !!value && typeof value === \"object\" && !Array.isArray(value);\nconst isMedia = (value, kind) => plain(value) && typeof value.url === \"string\" && typeof value.assetId === \"string\" && (!kind || value.kind === kind);\nconst dataUrlBytes = (dataUrl) => {\n\tconst match = /^data:([a-z]+\\/[a-z0-9.+-]+)(?:;[^,;]*)*;base64,(.+)$/i.exec(String(dataUrl || \"\"));\n\tif (!match) fail(\"Choose a file to save.\");\n\tconst text = atob(match[2]), bytes = new Uint8Array(text.length);\n\tfor (let index = 0; index < text.length; index++) bytes[index] = text.charCodeAt(index);\n\treturn {\n\t\tmediaType: match[1].toLowerCase(),\n\t\tbuffer: bytes.buffer\n\t};\n};\nconst EXTENSIONS = {\n\t\"image/png\": \"png\",\n\t\"image/jpeg\": \"jpg\",\n\t\"image/webp\": \"webp\",\n\t\"image/gif\": \"gif\",\n\t\"video/mp4\": \"mp4\",\n\t\"video/webm\": \"webm\",\n\t\"video/quicktime\": \"mov\",\n\t\"audio/mpeg\": \"mp3\",\n\t\"audio/wav\": \"wav\",\n\t\"audio/x-wav\": \"wav\",\n\t\"audio/mp4\": \"m4a\",\n\t\"audio/ogg\": \"ogg\",\n\t\"audio/webm\": \"webm\"\n};\nasync function run(input, stillmade) {\n\tconst make = typeof input.make === \"string\" ? input.make : \"use\";\n\tconst request = plain(input.request) ? input.request : {};\n\tconst references = (Array.isArray(input.references) ? input.references : []).filter((value) => isMedia(value, \"image\"));\n\tconst editor = plain(input.editor) ? {\n\t\t...input.editor,\n\t\tschemaVersion: input.editor.schemaVersion ?? 1\n\t} : null;\n\tconst done = (result, made = []) => ({\n\t\t...editor ? { editor } : {},\n\t\t...made.length ? { made } : {},\n\t\tresult: result === void 0 ? null : result\n\t});\n\tswitch (make) {\n\t\tcase \"use\": return done(null);\n\t\tcase \"image\": {\n\t\t\tif (typeof request.readablePrompt !== \"string\" || !request.readablePrompt.trim()) fail(\"Write what the picture shows first.\");\n\t\t\tstillmade.progress(.2, \"Making the picture\");\n\t\t\tconst settings = Object.fromEntries(Object.entries({\n\t\t\t\tmodel: request.model,\n\t\t\t\taspectRatio: request.aspectRatio,\n\t\t\t\tquality: request.quality,\n\t\t\t\tresolution: request.resolution\n\t\t\t}).filter(([, value]) => typeof value === \"string\" && value));\n\t\t\tconst made = await stillmade.hosted.run(\"image.generate\", {\n\t\t\t\tprompt: request.readablePrompt,\n\t\t\t\t...references.length ? { references: references.slice(0, 8) } : {},\n\t\t\t\t...Object.keys(settings).length ? { settings } : {}\n\t\t\t});\n\t\t\treturn done(made, [made]);\n\t\t}\n\t\tcase \"video\": {\n\t\t\tstillmade.progress(.1, \"Making the clip\");\n\t\t\tconst settings = Object.fromEntries(Object.entries({\n\t\t\t\tmodel: request.model,\n\t\t\t\taspectRatio: request.aspectRatio,\n\t\t\t\tquality: request.quality,\n\t\t\t\tresolution: request.resolution,\n\t\t\t\tduration: request.duration,\n\t\t\t\tseed: request.seed,\n\t\t\t\tgenerateAudio: request.generateAudio\n\t\t\t}).filter(([, value]) => value !== void 0 && value !== null && value !== \"\"));\n\t\t\tconst made = await stillmade.hosted.run(\"video.generate\", {\n\t\t\t\tprompt: request.readablePrompt || \"\",\n\t\t\t\t...isMedia(input.firstFrame, \"image\") ? { firstFrame: input.firstFrame } : {},\n\t\t\t\t...isMedia(input.lastFrame, \"image\") ? { lastFrame: input.lastFrame } : {},\n\t\t\t\t...request.negativePrompt ? { negativePrompt: request.negativePrompt } : {},\n\t\t\t\t...Object.keys(settings).length ? { settings } : {}\n\t\t\t});\n\t\t\treturn done(made, [made]);\n\t\t}\n\t\tcase \"transcribe\": {\n\t\t\tif (!isMedia(input.audio)) fail(\"Choose the sound to transcribe.\");\n\t\t\tstillmade.progress(.2, \"Finding the words\");\n\t\t\tconst timing = await stillmade.hosted.run(\"audio.transcribe\", { audio: input.audio });\n\t\t\tconst words = (Array.isArray(timing?.words) ? timing.words : []).map((word) => ({\n\t\t\t\tword: word.text ?? word.word,\n\t\t\t\ttext: word.text ?? word.word,\n\t\t\t\tstart: word.start,\n\t\t\t\tend: word.end\n\t\t\t}));\n\t\t\treturn done({\n\t\t\t\ttext: String(timing?.text || words.map((word) => word.text).join(\" \")),\n\t\t\t\twords\n\t\t\t});\n\t\t}\n\t\tcase \"upload\": {\n\t\t\tconst { mediaType, buffer } = dataUrlBytes(input.dataUrl);\n\t\t\tconst extension = EXTENSIONS[mediaType] || fail(\"Save a picture, a clip or a sound file.\");\n\t\t\tconst name = String(input.key || `upload.${extension}`).replace(/[^\\w.-]+/g, \"-\").slice(0, 120) || `upload.${extension}`;\n\t\t\tconst saved = await stillmade.files.write(buffer, {\n\t\t\t\tmediaType,\n\t\t\t\tname: /\\.[a-z0-9]{2,5}$/i.test(name) ? name : `${name}.${extension}`\n\t\t\t});\n\t\t\treturn done(saved, [saved]);\n\t\t}\n\t\tcase \"export\": {\n\t\t\tconst kind = request.kind === \"audio\" ? \"audio\" : \"video\";\n\t\t\tstillmade.progress(.05, kind === \"audio\" ? \"Mixing the sound\" : \"Rendering the video\");\n\t\t\tconst { asset } = await stillmade.actions.run({\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tkind: \"stillmade.media-action\",\n\t\t\t\toperation: \"final.render\",\n\t\t\t\tresultPort: null,\n\t\t\t\trequest: {\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tkind,\n\t\t\t\t\ttimeline: request.timeline,\n\t\t\t\t\tsettings: request.settings,\n\t\t\t\t\tsource: plain(request.source) ? request.source : {\n\t\t\t\t\t\tid: \"sm.editor\",\n\t\t\t\t\t\tversion: \"3.0.0\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst kept = {\n\t\t\t\tkind: asset.kind,\n\t\t\t\tassetId: asset.assetId,\n\t\t\t\tversionId: asset.versionId,\n\t\t\t\turl: asset.url,\n\t\t\t\t...asset.mimeType ? { mimeType: asset.mimeType } : {},\n\t\t\t\t...Number(asset.duration) > 0 ? { duration: Number(asset.duration) } : {}\n\t\t\t};\n\t\t\treturn {\n\t\t\t\t...done(kept, [kept]),\n\t\t\t\t[kind === \"audio\" ? \"exportAudio\" : \"export\"]: kept\n\t\t\t};\n\t\t}\n\t\tcase \"stock-status\": return done({ available: true });\n\t\tcase \"stock-grid\": {\n\t\t\tconst { results } = await stillmade.actions.run({\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tkind: \"stillmade.media-action\",\n\t\t\t\toperation: \"stock.search\",\n\t\t\t\tresultPort: null,\n\t\t\t\trequest: {\n\t\t\t\t\tquery: String(request.query || request.q || \"\").slice(0, 500) || \"scene\",\n\t\t\t\t\ttype: request.type === \"video\" ? \"video\" : \"photo\"\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn done(results || []);\n\t\t}\n\t\tcase \"storage-get\": return done(await stillmade.storage.get(String(input.key || \"\")));\n\t\tcase \"storage-set\":\n\t\t\tawait stillmade.storage.set(String(input.key || \"\"), input.value ?? null);\n\t\t\treturn done(true);\n\t}\n\tfail(`${make} is not something the Editor Block does yet.`);\n}\n\n//#endregion\nexport { run as default };"
750
795
  }
751
796
  };