fablecut 0.0.0-stage → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1198 -0
- package/LICENSE +21 -0
- package/README.md +571 -2
- package/analyze.js +289 -0
- package/app.js +13339 -0
- package/audio-fx.js +241 -0
- package/cli.js +31 -0
- package/color.js +1043 -0
- package/denoise.js +120 -0
- package/ducking.js +127 -0
- package/edit-ops.js +962 -0
- package/encode-profiles.js +302 -0
- package/encoding-profiles.json +68 -0
- package/export-jobs.js +163 -0
- package/favicon.svg +14 -0
- package/fx-worklet.js +162 -0
- package/icons/favicon-32.png +0 -0
- package/import-url.js +293 -0
- package/index.html +420 -0
- package/library/README.md +15 -0
- package/library/elements/.gitkeep +0 -0
- package/library/elements/bokeh-drift.svg +19 -0
- package/library/elements/light-leak-cool.svg +16 -0
- package/library/elements/light-leak-warm.svg +22 -0
- package/library/elements/vhs-scanlines.svg +18 -0
- package/library/elements/vignette-frame.svg +14 -0
- package/library/fonts/.gitkeep +0 -0
- package/library/fonts/Abril Fatface.woff2 +0 -0
- package/library/fonts/Anton.woff2 +0 -0
- package/library/fonts/Archivo Black.woff2 +0 -0
- package/library/fonts/Bangers.woff2 +0 -0
- package/library/fonts/Barlow.woff2 +0 -0
- package/library/fonts/Bebas Neue.woff2 +0 -0
- package/library/fonts/Bungee.woff2 +0 -0
- package/library/fonts/Caveat.woff2 +0 -0
- package/library/fonts/DM Sans.woff2 +0 -0
- package/library/fonts/Inter.woff2 +0 -0
- package/library/fonts/LICENSES.md +31 -0
- package/library/fonts/Lato.woff2 +0 -0
- package/library/fonts/Montserrat.woff2 +0 -0
- package/library/fonts/Oswald.woff2 +0 -0
- package/library/fonts/Pacifico.woff2 +0 -0
- package/library/fonts/Playfair Display.woff2 +0 -0
- package/library/fonts/Poppins.woff2 +0 -0
- package/library/fonts/Righteous.woff2 +0 -0
- package/library/fonts/Roboto.woff2 +0 -0
- package/library/fonts/Rubik.woff2 +0 -0
- package/library/fonts/Teko.woff2 +0 -0
- package/library/sfx/README.md +18 -0
- package/library/svg/ai-star.svg +17 -0
- package/library/svg/arrow-bounce.svg +18 -0
- package/library/svg/arrow-scribble.svg +13 -0
- package/library/svg/burst-lines.svg +30 -0
- package/library/svg/checkmark-success.svg +19 -0
- package/library/svg/confetti-burst.svg +23 -0
- package/library/svg/countdown-ring.svg +92 -0
- package/library/svg/equalizer.svg +18 -0
- package/library/svg/glow-orbs.svg +29 -0
- package/library/svg/heart-pop.svg +28 -0
- package/library/svg/loading-dots.svg +16 -0
- package/library/svg/location-pin.svg +25 -0
- package/library/svg/lower-third.svg +17 -0
- package/library/svg/new-badge.svg +18 -0
- package/library/svg/progress-bar.svg +16 -0
- package/library/svg/radial-pulse.svg +19 -0
- package/library/svg/rating-stars.svg +25 -0
- package/library/svg/rec-indicator.svg +41 -0
- package/library/svg/sparkles.svg +17 -0
- package/library/svg/spawning-hearts.svg +39 -0
- package/library/svg/speech-bubble.svg +23 -0
- package/library/svg/subscribe-bell.svg +29 -0
- package/library/svg/subscribe-pill.svg +22 -0
- package/library/svg/swipe-up.svg +46 -0
- package/library/svg/underline-swoosh.svg +15 -0
- package/loudness.js +135 -0
- package/mcp-server.js +1421 -0
- package/meter-worklet.js +229 -0
- package/package.json +45 -4
- package/paths.js +106 -0
- package/ruler-worker.js +120 -0
- package/server.js +775 -0
- package/style.css +3563 -0
package/index.html
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>FableCut - Video Editor</title>
|
|
7
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
8
|
+
<link rel="icon" href="/icons/favicon-32.png" sizes="32x32" type="image/png">
|
|
9
|
+
<meta name="theme-color" content="#0e0e10">
|
|
10
|
+
<link rel="stylesheet" href="style.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div class="app" id="app">
|
|
14
|
+
|
|
15
|
+
<!-- ══════════ TOP BAR ══════════ -->
|
|
16
|
+
<header class="topbar">
|
|
17
|
+
<div class="logo"><span class="logo-mark">▶</span> Fable<b>Cut</b></div>
|
|
18
|
+
<div class="topbar-center" id="projectName">Untitled Project</div>
|
|
19
|
+
<div class="topbar-right">
|
|
20
|
+
<span class="btn-group ws-switch" id="wsSwitch" role="tablist" title="Workspace">
|
|
21
|
+
<button type="button" class="btn tiny on" data-ws="edit" title="Edit workspace: media bin, inspector, mixer">Edit</button>
|
|
22
|
+
<button type="button" class="btn tiny" data-ws="color" title="Color workspace: scopes, wheels and the grade of the selected clip">Color</button>
|
|
23
|
+
</span>
|
|
24
|
+
<span class="layout-tools">
|
|
25
|
+
<button type="button" class="btn tiny" id="btnLayoutReset" title="Restore default layout">⊡ Layout</button>
|
|
26
|
+
<span class="btn-group" id="trackSizeGroup" title="Timeline track height">
|
|
27
|
+
<button type="button" class="btn tiny" data-track-size="s" title="Compact tracks (no thumbnails)">S</button>
|
|
28
|
+
<button type="button" class="btn tiny" data-track-size="m" title="Medium tracks">M</button>
|
|
29
|
+
<button type="button" class="btn tiny" data-track-size="l" title="Large tracks">L</button>
|
|
30
|
+
</span>
|
|
31
|
+
</span>
|
|
32
|
+
<button class="btn ghost" id="btnSettings" title="Settings" aria-label="Settings">
|
|
33
|
+
<svg class="ico" viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
|
|
34
|
+
<path fill="currentColor" fill-rule="evenodd" d="M6.71 2.81L6.88.94L9.12.94L9.29 2.81L10.76 3.41L12.2 2.22L13.78 3.8L12.59 5.24L13.19 6.71L15.06 6.88L15.06 9.12L13.19 9.29L12.59 10.76L13.78 12.2L12.2 13.78L10.76 12.59L9.29 13.19L9.12 15.06L6.88 15.06L6.71 13.19L5.24 12.59L3.8 13.78L2.22 12.2L3.41 10.76L2.81 9.29L.94 9.12L.94 6.88L2.81 6.71L3.41 5.24L2.22 3.8L3.8 2.22L5.24 3.41Z M5.15 8a2.85 2.85 0 1 0 5.7 0a2.85 2.85 0 1 0-5.7 0"/>
|
|
35
|
+
</svg>
|
|
36
|
+
</button>
|
|
37
|
+
<button class="btn ghost" id="btnHelp" title="Keyboard shortcuts">?</button>
|
|
38
|
+
<button class="btn primary" id="btnExport">⬇ Export</button>
|
|
39
|
+
</div>
|
|
40
|
+
</header>
|
|
41
|
+
|
|
42
|
+
<!-- ══════════ UPPER PANELS ══════════ -->
|
|
43
|
+
<div class="upper">
|
|
44
|
+
|
|
45
|
+
<!-- Media bin -->
|
|
46
|
+
<aside class="panel bin">
|
|
47
|
+
<div class="panel-head">
|
|
48
|
+
<span class="panel-head-actions bin-actions">
|
|
49
|
+
<button type="button" class="btn tiny" id="btnTitle" title="Add a title card at the playhead">+ Title</button>
|
|
50
|
+
<button type="button" class="btn tiny" id="btnAdjust" title="Add an adjustment layer (grades everything below it)">+ Adjust</button>
|
|
51
|
+
<label class="btn tiny accent" id="btnImport" for="fileInput" title="Import media files">+ Import</label>
|
|
52
|
+
<button type="button" class="btn tiny" id="btnImportUrl" title="Download media from an HTTPS URL into the project">+ URL</button>
|
|
53
|
+
</span>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="bin-tabs" id="binTabs">
|
|
56
|
+
<button type="button" data-tab="project" class="on" title="Media used by this project — right-click for New folder">Project</button>
|
|
57
|
+
<button type="button" data-tab="elements" title="Overlay art from library/elements">Elements</button>
|
|
58
|
+
<button type="button" data-tab="sfx" title="Sound effects from library/sfx">Sound FX</button>
|
|
59
|
+
<button type="button" data-tab="svg" title="Vector animations from library/svg">SVG</button>
|
|
60
|
+
</div>
|
|
61
|
+
<input type="file" id="fileInput" class="sr-only" multiple accept="video/*,audio/*,image/*,.mp4,.mov,.webm,.mkv,.mp3,.wav,.m4a,.png,.jpg,.jpeg,.gif,.webp,.svg">
|
|
62
|
+
<div class="bin-list" id="binList">
|
|
63
|
+
<div class="bin-empty" id="binEmpty">
|
|
64
|
+
<div class="bin-empty-icon">🎬</div>
|
|
65
|
+
<p>Drop video, audio or images here<br>or click <b>+ Import</b> / <b>+ URL</b></p>
|
|
66
|
+
<p class="hint">Double-click to open in Source, or drag onto the timeline.</p>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="bin-list hidden" id="libList"></div>
|
|
70
|
+
</aside>
|
|
71
|
+
|
|
72
|
+
<!-- Single monitor (Source / Program — Avid-style toggle) -->
|
|
73
|
+
<!-- Scopes (Color workspace) -->
|
|
74
|
+
<aside class="panel scopes" id="scopesPanel" aria-label="Scopes">
|
|
75
|
+
<div class="scope-slot" data-slot="0"></div>
|
|
76
|
+
<div class="scope-slot" data-slot="1"></div>
|
|
77
|
+
</aside>
|
|
78
|
+
|
|
79
|
+
<section class="panel monitor" id="monitorPanel">
|
|
80
|
+
<div class="panel-head">
|
|
81
|
+
<span class="panel-head-title">
|
|
82
|
+
<span class="btn-group monitor-mode" id="monitorModeGroup" title="Source = loaded clip · Program = timeline">
|
|
83
|
+
<button type="button" class="btn tiny" data-monitor-mode="source" id="btnMonSource">Source</button>
|
|
84
|
+
<button type="button" class="btn tiny on" data-monitor-mode="program" id="btnMonProgram">Program</button>
|
|
85
|
+
</span>
|
|
86
|
+
<span class="monitor-clip-name dim" id="monitorClipName"></span>
|
|
87
|
+
<button class="btn tiny hidden" id="btnZoom100" title="Reset monitor view to fit stage"><svg class="ico" viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" d="M1.5 5V1.5H5M11 1.5h3.5V5M14.5 11v3.5H11M5 14.5H1.5V11"/><path fill="none" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" stroke-linejoin="round" d="M3.2 3.2l2.6 2.6M12.8 3.2l-2.6 2.6M12.8 12.8l-2.6-2.6M3.2 12.8l2.6-2.6"/></svg> Fit</button>
|
|
88
|
+
</span>
|
|
89
|
+
<span class="panel-head-actions">
|
|
90
|
+
<select id="aspectSel" class="head-select" title="Canvas aspect preset"></select>
|
|
91
|
+
<select id="fpsSel" class="head-select" title="Project frame rate"></select>
|
|
92
|
+
<select id="exportFrameSel" class="head-select" title="Delivery export frame — crop inside the canvas for reframing"></select>
|
|
93
|
+
<button class="btn tiny toggle" id="btnExportFrame" title="Toggle export frame overlay (drag handle to reframe)">⬒ Frame</button>
|
|
94
|
+
<button type="button" class="btn tiny toggle hidden" id="btnExportFrameDim" aria-pressed="true" title="Lights off — crop to the export frame"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><g class="ef-bulb-rays" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M8 .4v1.05M1.7 3.45l.85.65M14.3 3.45l-.85.65"/></g><path class="ef-bulb-glass" fill="none" stroke="currentColor" stroke-width="1.55" stroke-linejoin="round" d="M8 1.7A4.1 4.1 0 0 0 3.9 5.8c0 1.62.86 2.72 1.8 3.5.38.32.62.68.62 1.15v.35h4.36v-.35c0-.47.24-.83.62-1.15.94-.78 1.8-1.88 1.8-3.5A4.1 4.1 0 0 0 8 1.7z"/><path fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="square" d="M6.25 12.85h3.5M6.7 14.35h2.6"/></svg></button>
|
|
95
|
+
<button class="btn tiny toggle" id="btnGuides" title="Toggle safe-area guides">▦ Safe</button>
|
|
96
|
+
<span class="dim" id="monitorRes"></span>
|
|
97
|
+
</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="monitor-stage" id="monitorStage">
|
|
100
|
+
<div class="monitor-scroll" id="monitorScroll">
|
|
101
|
+
<div class="monitor-zoom-inner" id="monitorZoomInner">
|
|
102
|
+
<canvas id="preview" width="1280" height="720"></canvas>
|
|
103
|
+
<div id="safeOverlay" class="hidden">
|
|
104
|
+
<div class="sa-action"></div>
|
|
105
|
+
<div class="sa-title"></div>
|
|
106
|
+
<div class="sa-ui-bottom"></div>
|
|
107
|
+
<div class="sa-ui-right"></div>
|
|
108
|
+
</div>
|
|
109
|
+
<div id="exportFrameOverlay" class="hidden">
|
|
110
|
+
<div class="ef-shade"></div>
|
|
111
|
+
<button type="button" class="ef-handle"
|
|
112
|
+
aria-label="Export frame — drag or arrow keys to reposition (Shift for 10px steps)">Export frame</button>
|
|
113
|
+
<div class="ef-edge ef-edge-t" title="Drag to reposition export frame" aria-hidden="true"></div>
|
|
114
|
+
<div class="ef-edge ef-edge-b" title="Drag to reposition export frame" aria-hidden="true"></div>
|
|
115
|
+
<div class="ef-edge ef-edge-l" title="Drag to reposition export frame" aria-hidden="true"></div>
|
|
116
|
+
<div class="ef-edge ef-edge-r" title="Drag to reposition export frame" aria-hidden="true"></div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="kf-graphs" id="kfGraphs" hidden></div>
|
|
121
|
+
<div class="vu-meter" id="vuMeter" title="Click to switch RMS / LUFS / Peak"></div>
|
|
122
|
+
</div>
|
|
123
|
+
<div class="source-scrub hidden" id="sourceScrub" title="Scrub source · drag to seek">
|
|
124
|
+
<div class="source-scrub-track" id="sourceScrubTrack">
|
|
125
|
+
<div class="source-scrub-range" id="sourceScrubRange"></div>
|
|
126
|
+
<div class="source-scrub-mark in" id="sourceScrubIn" hidden></div>
|
|
127
|
+
<div class="source-scrub-mark out" id="sourceScrubOut" hidden></div>
|
|
128
|
+
<div class="source-scrub-head" id="sourceScrubHead"></div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="transport">
|
|
132
|
+
<span class="tc-playhead" title="Playhead / sequence duration">
|
|
133
|
+
<span class="timecode" id="tcCurrent" title="Playhead — click (or type a digit) to enter a time">00:00:00</span>
|
|
134
|
+
<span class="tc-slash">/</span>
|
|
135
|
+
<span class="timecode dim" id="tcTotal">00:00:00</span>
|
|
136
|
+
</span>
|
|
137
|
+
<div class="transport-btns">
|
|
138
|
+
<button class="btn icon" id="btnMarkIn" title="Mark In (I) — Source marks when Source is active; timeline work area in Program">I</button>
|
|
139
|
+
<button class="btn icon" id="btnHome" title="Go to start (Home)">⏮</button>
|
|
140
|
+
<button class="btn icon" id="btnBack" title="Back 1 frame (←)">◀︎</button>
|
|
141
|
+
<button class="btn icon big" id="btnPlay" title="Play / Pause (Space)">▶</button>
|
|
142
|
+
<button class="btn icon" id="btnFwd" title="Forward 1 frame (→)">▶︎</button>
|
|
143
|
+
<button class="btn icon" id="btnEnd" title="Go to end (End)">⏭</button>
|
|
144
|
+
<button class="btn icon" id="btnMarkOut" title="Mark Out (O) — Source marks when Source is active; timeline work area in Program">O</button>
|
|
145
|
+
<button class="btn icon toggle" id="btnSpeed" title="Preview speed — click to cycle 1×/1.5×/2×/4×. L forward · J reverse (tap again = faster) · K stop. Preview only, not export.">1×</button>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="transport-end">
|
|
148
|
+
<button type="button" class="btn icon hidden" id="btnInsert" title="Insert Source In→Out at the timeline playhead (,)" aria-label="Insert">
|
|
149
|
+
<svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
|
|
150
|
+
<path fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="square" d="M0.75 5H3.5V11H0.75M15.25 5H12.5V11h2.75"/>
|
|
151
|
+
<path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" d="M8 4.2v5.4M5.55 7.35L8 9.9L10.45 7.35"/>
|
|
152
|
+
</svg>
|
|
153
|
+
</button>
|
|
154
|
+
<button type="button" class="btn icon hidden" id="btnReplace" title="Replace (overwrite) Source In→Out at the timeline playhead (.)" aria-label="Replace">
|
|
155
|
+
<svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
|
|
156
|
+
<path fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="square" d="M0.75 5H3.5V11H0.75M15.25 5H12.5V11h2.75"/>
|
|
157
|
+
<rect x="5.35" y="5" width="5.3" height="6" rx="0.4" fill="currentColor"/>
|
|
158
|
+
</svg>
|
|
159
|
+
</button>
|
|
160
|
+
<div class="tc-io idle" id="tcIo" aria-hidden="true">
|
|
161
|
+
<span class="tc-io-item in" title="IN point">
|
|
162
|
+
<span class="tc-io-lab">IN</span>
|
|
163
|
+
<span class="timecode unset" id="tcIn">00:00:00</span>
|
|
164
|
+
</span>
|
|
165
|
+
<span class="tc-io-item dur" title="Marked duration">
|
|
166
|
+
<span class="tc-io-lab">DUR</span>
|
|
167
|
+
<span class="timecode unset" id="tcDur">00:00:00</span>
|
|
168
|
+
</span>
|
|
169
|
+
<span class="tc-io-item out" title="OUT point">
|
|
170
|
+
<span class="tc-io-lab">OUT</span>
|
|
171
|
+
<span class="timecode unset" id="tcOut">00:00:00</span>
|
|
172
|
+
</span>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</section>
|
|
177
|
+
|
|
178
|
+
<!-- Inspector -->
|
|
179
|
+
<aside class="panel inspector">
|
|
180
|
+
<div class="bin-tabs side-tabs" id="sideTabs" role="tablist">
|
|
181
|
+
<button type="button" data-side="inspector" class="on" title="Selected clip: transform, effects & audio">Inspector</button>
|
|
182
|
+
<button type="button" data-side="mixer" title="Track and master faders, pan, mute / solo, meters">Mixer</button>
|
|
183
|
+
<button type="button" data-side="color" title="Grade the selected clip: wheels, exposure, white balance, tone">Color</button>
|
|
184
|
+
</div>
|
|
185
|
+
<div class="inspector-body" id="inspector">
|
|
186
|
+
<div class="inspector-empty">Select a clip to edit its<br>transform, effects & audio.</div>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="mixer hidden" id="mixer"></div>
|
|
189
|
+
<div class="color-page hidden" id="colorPage"></div>
|
|
190
|
+
</aside>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div class="v-split" id="splitUpperTimeline" role="separator" aria-orientation="horizontal" title="Drag to resize · double-click to reset"></div>
|
|
194
|
+
|
|
195
|
+
<!-- ══════════ TIMELINE ══════════ -->
|
|
196
|
+
<section class="panel timeline-panel" id="timelinePanel">
|
|
197
|
+
<div class="timeline-toolbar">
|
|
198
|
+
<button class="btn tiny hidden" id="btnTrimIO" title="Trim clips to IN/OUT (⇧T)"><svg class="ico" viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="square" d="M1.25 4.5H12M4.5 1.25V12M4.5 12H14.75M12 4.5V14.75"/></svg> Trim</button>
|
|
199
|
+
<button class="btn tiny toggle hidden" id="btnWorkAreaPlay" title="Limit playback to IN/OUT (Home/End jump to markers; playhead outside = override)"><svg class="ico" viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="square" stroke-linejoin="miter" d="M1.5 2.5V13.5M14.5 2.5V13.5M4.25 8H11.75M9.35 5.6L12 8L9.35 10.4"/></svg> Limit</button>
|
|
200
|
+
<span class="tool-seg" role="group" aria-label="Edit tool"><button type="button" class="btn tiny on" data-edit-tool="select" aria-pressed="true" title="Selection tool (V) — move and trim clips"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M4 1.5v11.2l3-2.9 1.9 4.6 1.8-.8-1.9-4.4h4.2z"/></svg></button><button type="button" class="btn tiny" data-edit-tool="ripple" aria-pressed="false" title="Ripple edit (B) — drag a clip edge; everything after it moves with it"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" d="M5 2.5v11M5 8h8.5M11 5.5 13.5 8 11 10.5"/></svg></button><button type="button" class="btn tiny" data-edit-tool="roll" aria-pressed="false" title="Rolling edit (R) — drag a cut; the clips on both sides trim, nothing else moves"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" d="M8 2v12M1.5 8h4M10.5 8h4M3.5 6 1.5 8l2 2M12.5 6l2 2-2 2"/></svg></button><button type="button" class="btn tiny" data-edit-tool="slip" aria-pressed="false" title="Slip (Y) — drag a clip to change which part of the source it shows"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" d="M2.5 3v10M13.5 3v10M5 8h6M6.8 6.2 5 8l1.8 1.8M9.2 6.2 11 8l-1.8 1.8"/></svg></button><button type="button" class="btn tiny" data-edit-tool="slide" aria-pressed="false" title="Slide (U) — drag a clip along the track; its neighbours trim to make room"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><rect fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" x="5" y="4" width="6" height="8" rx="1"/><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" d="M1 8h2.5M12.5 8H15M2.3 6.7 1 8l1.3 1.3M13.7 6.7 15 8l-1.3 1.3"/></svg></button></span>
|
|
201
|
+
<button class="btn tiny" id="btnSplit" title="Split at playhead on targeted tracks (S)">✂ Split</button>
|
|
202
|
+
<button class="btn tiny" id="btnCloseGap" title="Close gap at playhead (⇧G)"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" style="vertical-align:-3px" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="miter" d="M0.75 4.5H3.5V11.5H0.75M15.25 4.5H12.5V11.5H15.25"/><path fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" d="M6.35 5.85L9.65 10.15M9.65 5.85L6.35 10.15"/></svg> Close gap</button>
|
|
203
|
+
<button class="btn tiny" id="btnNextGap" title="Find gap (G)"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" style="vertical-align:-3px" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="miter" d="M0.75 4.5H3.5V11.5H0.75M15.25 4.5H12.5V11.5H15.25"/><text x="8" y="11.1" text-anchor="middle" fill="currentColor" font-size="9.5" font-family="Segoe UI, system-ui, sans-serif" font-weight="700">?</text></svg> Find gap</button>
|
|
204
|
+
<button class="btn tiny" id="btnDelete" title="Delete selected (Del)"><svg class="ico" viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path fill="currentColor" d="M5.5 1.5h5v1.25H14v1.5H2v-1.5h3.5V1.5zM3.75 5.5h8.5v8.25a1.5 1.5 0 0 1-1.5 1.5h-5.5a1.5 1.5 0 0 1-1.5-1.5V5.5zm2 2v5h1.25v-5H5.75zm3.25 0v5H10.25v-5H9z"/></svg> Delete</button>
|
|
205
|
+
<button class="btn tiny" id="btnRippleDelete" title="Ripple delete selection (⇧Del) — closes gap on targeted tracks"><svg class="ico" viewBox="0 0 16 16" width="14" height="14" style="vertical-align:-3px" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="miter" d="M0.75 4.5H3.5V11.5H0.75M15.25 4.5H12.5V11.5H15.25"/><path fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" d="M6.8 6.2L9.2 8.6M9.2 6.2L6.8 8.6"/><path fill="currentColor" d="M7.35 9.55h1.3v1.05h-1.3V9.55zm0 1.55h1.3v1.05h-1.3v-1.05z"/></svg> Ripple delete</button>
|
|
206
|
+
<button class="btn tiny" id="btnLift" title="Lift (;) — remove IN→OUT on targeted tracks, leave the gap">Lift</button>
|
|
207
|
+
<button class="btn tiny" id="btnExtract" title="Extract (') — remove IN→OUT on targeted tracks and close the gap">Extract</button>
|
|
208
|
+
<span class="snap-seg"><button class="btn tiny toggle on" id="btnSnap" title="Toggle snapping (N)"><svg class="ico" viewBox="0 0 16 16" width="13" height="13" style="vertical-align:-3px" aria-hidden="true"><g transform="rotate(270 8 7)"><path fill="none" stroke="currentColor" stroke-width="3.25" stroke-linecap="butt" d="M4 10.25V7a4 4 0 0 1 8 0v3.25"/><path fill="currentColor" d="M2.375 10.75h3.25v2.5h-3.25zm8 0h3.25v2.5h-3.25z"/></g></svg> Snap</button><button type="button" class="btn tiny" id="btnSnapMenu" title="Snap targets — clip edges, playhead, markers, IN/OUT, keyframes, frame grid" aria-label="Snap targets">▾</button></span>
|
|
209
|
+
<button type="button" class="btn tiny" id="btnMarkers" title="Markers — list, jump, rename, recolour (M add · ⇧M next · Alt+⇧M previous)"><svg class="ico" viewBox="0 0 16 16" width="12" height="12" style="vertical-align:-2px" aria-hidden="true"><path fill="currentColor" d="M8 1.5 13.5 7 8 12.5 2.5 7z"/></svg> Markers</button>
|
|
210
|
+
<button class="btn tiny toggle" id="btnAudioHold" title="Audio Hold — while paused, loop one frame of audio at the playhead. Play/Stop turns it off."><svg class="ico" viewBox="0 0 16 16" width="13" height="13" style="vertical-align:-3px" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" d="M1.75 2.75V13.25M14.25 2.75V13.25"/><path fill="currentColor" d="M5.2 5.85h1.15v4.3H5.2V5.85zM7.05 5.85h0.55l2.85-2.2v8.7l-2.85-2.2H7.05V5.85z"/></svg> Audio hold</button>
|
|
211
|
+
<span class="flex-spacer"></span>
|
|
212
|
+
<span class="dim tiny-label">Zoom</span>
|
|
213
|
+
<input type="range" id="zoomSlider" min="1" max="300" value="60">
|
|
214
|
+
<button class="btn tiny" id="btnZoomFit" title="Zoom timeline to fit (⇧Z)"><span class="fit-icon">│<span class="fit-arrow">↔</span>│</span> Fit</button>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="timeline">
|
|
217
|
+
<div class="track-headers" id="trackHeaders">
|
|
218
|
+
<div class="track-head-tools" id="trackHeadTools">
|
|
219
|
+
<button type="button" class="btn tiny" id="btnAddV" title="Add video track">+V</button>
|
|
220
|
+
<button type="button" class="btn tiny" id="btnAddA" title="Add audio track">+A</button>
|
|
221
|
+
</div>
|
|
222
|
+
<div id="trackHeadInner"></div>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="timeline-scroll" id="timelineScroll">
|
|
225
|
+
<canvas class="ruler" id="ruler"></canvas>
|
|
226
|
+
<div class="tracks-content" id="tracksContent">
|
|
227
|
+
<div class="work-dim work-dim-l hidden" id="workDimL"></div>
|
|
228
|
+
<div class="work-dim work-dim-r hidden" id="workDimR"></div>
|
|
229
|
+
<div class="tracks" id="tracks"></div>
|
|
230
|
+
<div class="snap-line hidden" id="snapLine"></div>
|
|
231
|
+
<div class="playhead" id="playhead"><div class="playhead-cap"></div></div>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</section>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<!-- ══════════ IMPORT URL ══════════ -->
|
|
239
|
+
<div class="overlay hidden" id="importUrlOverlay">
|
|
240
|
+
<div class="dialog" id="importUrlDialog" role="dialog" aria-modal="true" aria-labelledby="importUrlTitle">
|
|
241
|
+
<h2 id="importUrlTitle">Import from URL</h2>
|
|
242
|
+
<p class="dim">Downloads an HTTPS video, audio or image into the project media folder. The file is stored locally — the URL is not used as the playback source. Remote SVGs are not imported (they can run script if opened as a document).</p>
|
|
243
|
+
<label class="import-url-field">
|
|
244
|
+
<span class="sr-only">Media URL</span>
|
|
245
|
+
<input type="url" id="importUrlInput" placeholder="https://…" autocomplete="off" spellcheck="false">
|
|
246
|
+
</label>
|
|
247
|
+
<p class="dim import-url-status hidden" id="importUrlStatus">Downloading…</p>
|
|
248
|
+
<div class="progress hidden" id="importUrlProgress"><div class="progress-fill indeterminate"></div></div>
|
|
249
|
+
<div class="dialog-actions">
|
|
250
|
+
<button class="btn" id="btnCancelImportUrl">Cancel</button>
|
|
251
|
+
<button class="btn primary" id="btnDoImportUrl">Import</button>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<!-- ══════════ EXPORT SETUP ══════════ -->
|
|
257
|
+
<div class="overlay hidden" id="exportSetup">
|
|
258
|
+
<div class="dialog">
|
|
259
|
+
<h2>Export</h2>
|
|
260
|
+
<div class="export-profile-row" id="exportRangeRow">
|
|
261
|
+
<label class="export-profile-label" for="exportRangeSel">Range</label>
|
|
262
|
+
<select class="export-profile-sel" id="exportRangeSel" aria-describedby="exportRangeNote">
|
|
263
|
+
<option value="entire">Entire timeline</option>
|
|
264
|
+
<option value="in-out">IN–OUT</option>
|
|
265
|
+
</select>
|
|
266
|
+
<p class="dim export-profile-note" id="exportRangeNote"></p>
|
|
267
|
+
</div>
|
|
268
|
+
<label class="engine-opt">
|
|
269
|
+
<input type="radio" name="engine" id="engineFast">
|
|
270
|
+
<span><b>Fast (ffmpeg)</b><br><span class="dim" id="engineFastNote">Frame-accurate ffmpeg encode. Keeps rendering if you switch tabs.</span></span>
|
|
271
|
+
</label>
|
|
272
|
+
<label class="engine-opt">
|
|
273
|
+
<input type="radio" name="engine" id="engineRealtime">
|
|
274
|
+
<span><b>WebCodecs (HW encode)</b><br><span class="dim" id="engineWebCodecsNote">Frame-accurate. Browser encodes H.264; server muxes. Needs a modern Chromium and ffmpeg.</span></span>
|
|
275
|
+
</label>
|
|
276
|
+
<div class="export-profile-row" id="exportProfileRow">
|
|
277
|
+
<label class="export-profile-label" for="exportProfileSel">Encoding profile</label>
|
|
278
|
+
<select class="export-profile-sel" id="exportProfileSel" aria-describedby="exportProfileNote exportProfileHint"></select>
|
|
279
|
+
<p class="dim export-profile-note" id="exportProfileNote"></p>
|
|
280
|
+
<p class="dim export-profile-hint" id="exportProfileHint"></p>
|
|
281
|
+
</div>
|
|
282
|
+
<div class="export-wc-opts hidden" id="exportWcOpts">
|
|
283
|
+
<label class="export-wc-field" for="exportWcBitrate">Bitrate
|
|
284
|
+
<select id="exportWcBitrate" class="export-wc-sel">
|
|
285
|
+
<option value="auto">Auto (from resolution)</option>
|
|
286
|
+
<option value="2">2 Mbps</option>
|
|
287
|
+
<option value="4">4 Mbps</option>
|
|
288
|
+
<option value="6">6 Mbps</option>
|
|
289
|
+
<option value="8">8 Mbps</option>
|
|
290
|
+
<option value="12">12 Mbps</option>
|
|
291
|
+
<option value="16">16 Mbps</option>
|
|
292
|
+
<option value="20">20 Mbps</option>
|
|
293
|
+
<option value="30">30 Mbps</option>
|
|
294
|
+
<option value="50">50 Mbps</option>
|
|
295
|
+
</select>
|
|
296
|
+
</label>
|
|
297
|
+
<label class="export-wc-field" for="exportWcMode">Rate control
|
|
298
|
+
<select id="exportWcMode" class="export-wc-sel">
|
|
299
|
+
<option value="variable">VBR (variable)</option>
|
|
300
|
+
<option value="constant">CBR (constant)</option>
|
|
301
|
+
</select>
|
|
302
|
+
</label>
|
|
303
|
+
<p class="dim export-wc-hint">WebCodecs has no CRF — quality is driven by bitrate. VBR spends bits on hard frames; CBR holds a steady rate.</p>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="export-track-warn hidden" id="exportTrackWarn" role="status"></div>
|
|
306
|
+
<div class="dialog-actions">
|
|
307
|
+
<button class="btn" id="btnCancelSetup">Cancel</button>
|
|
308
|
+
<button class="btn primary" id="btnStartExport">Export</button>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<!-- ══════════ EXPORT OVERLAY ══════════ -->
|
|
314
|
+
<div class="overlay hidden" id="exportOverlay">
|
|
315
|
+
<div class="dialog">
|
|
316
|
+
<h2 id="exportTitle">Exporting…</h2>
|
|
317
|
+
<p class="dim" id="exportNote">Rendering your sequence in real time. Keep this tab focused.</p>
|
|
318
|
+
<div class="progress"><div class="progress-fill" id="exportProgress"></div></div>
|
|
319
|
+
<div class="dialog-actions"><button class="btn" id="btnCancelExport">Cancel</button></div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<!-- ══════════ SETTINGS OVERLAY ══════════ -->
|
|
324
|
+
<div class="overlay hidden" id="settingsOverlay">
|
|
325
|
+
<div class="dialog settings" id="settingsDialog" role="dialog" aria-modal="true" aria-labelledby="settingsTitle" tabindex="-1">
|
|
326
|
+
<h2 id="settingsTitle">Settings</h2>
|
|
327
|
+
<p class="dim settings-intro">Preferences are stored in this browser only.</p>
|
|
328
|
+
<div class="settings-section">
|
|
329
|
+
<h3>Selection</h3>
|
|
330
|
+
<label class="settings-row">
|
|
331
|
+
<input type="checkbox" id="setLinkSelect">
|
|
332
|
+
<span>
|
|
333
|
+
<span class="settings-label">Link timeline and Project bin selection</span>
|
|
334
|
+
<span class="settings-hint">Selecting a timeline clip highlights its media in Project, and the reverse. Off by default.</span>
|
|
335
|
+
</span>
|
|
336
|
+
</label>
|
|
337
|
+
</div>
|
|
338
|
+
<div class="dialog-actions"><button class="btn primary" id="btnCloseSettings">Close</button></div>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<!-- ══════════ HELP OVERLAY ══════════ -->
|
|
343
|
+
<div class="overlay hidden" id="helpOverlay">
|
|
344
|
+
<div class="dialog help">
|
|
345
|
+
<h2>Keyboard shortcuts</h2>
|
|
346
|
+
<div class="keys-cols">
|
|
347
|
+
<table class="keys">
|
|
348
|
+
<tr><td><kbd>Space</kbd></td><td>Play / pause (Source or Program — whichever is active)</td></tr>
|
|
349
|
+
<tr><td>Dbl-click bin / clip</td><td>Load into Source monitor</td></tr>
|
|
350
|
+
<tr><td><kbd>,</kbd></td><td>Insert Source In→Out at the timeline playhead (ripples later clips)</td></tr>
|
|
351
|
+
<tr><td><kbd>.</kbd></td><td>Replace — overwrite at playhead, or apply new Source In/Out to a timeline-loaded clip (ripples if duration changes)</td></tr>
|
|
352
|
+
<tr><td><kbd>J</kbd> <kbd>K</kbd> <kbd>L</kbd></td><td>Shuttle — <kbd>L</kbd> plays forward, <kbd>J</kbd> in reverse (silent); tap again for 1.5× · 2× · 4×, the other key turns around; <kbd>K</kbd> stops</td></tr>
|
|
353
|
+
<tr><td><kbd>K</kbd>+<kbd>J</kbd> / <kbd>K</kbd>+<kbd>L</kbd></td><td>Hold <kbd>K</kbd> and tap to step one frame; hold both to crawl at ¼ speed</td></tr>
|
|
354
|
+
<tr><td><kbd>S</kbd></td><td>Split clip(s) at playhead (selection, else targeted tracks)</td></tr>
|
|
355
|
+
<tr><td><kbd>G</kbd></td><td>Find next shared gap (wraps; respects IN/OUT)</td></tr>
|
|
356
|
+
<tr><td><kbd>⇧</kbd>+<kbd>G</kbd></td><td>Close gap at playhead (targeted tracks)</td></tr>
|
|
357
|
+
<tr><td><kbd>Alt</kbd>+<kbd>T</kbd></td><td>Add transition at playhead (in / out by half)</td></tr>
|
|
358
|
+
<tr><td><kbd>Del</kbd></td><td>Delete selected clip(s), or clear focused transition</td></tr>
|
|
359
|
+
<tr><td><kbd>⇧</kbd>+<kbd>Del</kbd></td><td>Ripple delete — remove selection and close the gap on targeted tracks</td></tr>
|
|
360
|
+
<tr><td>Drag empty area</td><td>Marquee-select clips</td></tr>
|
|
361
|
+
<tr><td>Right-click track</td><td>Remove empty track (keeps ≥1 video + ≥1 audio)</td></tr>
|
|
362
|
+
<tr><td>Track <b>S</b></td><td>Solo track (mute all others; click again to restore)</td></tr>
|
|
363
|
+
<tr><td>Click track name</td><td>Target / untarget the track — edits touch lit (targeted) tracks only</td></tr>
|
|
364
|
+
<tr><td>Track padlock</td><td>Lock the track — nothing on it can be edited or moved</td></tr>
|
|
365
|
+
<tr><td>Right-click clip</td><td>Disable / lock / link or unlink the clip</td></tr>
|
|
366
|
+
<tr><td><kbd>V</kbd> <kbd>B</kbd> <kbd>R</kbd> <kbd>Y</kbd> <kbd>U</kbd></td><td>Tools: Selection · Ripple edit (drag an edge, the rest follows) · Rolling edit (drag a cut) · Slip (change the source under a clip) · Slide (move a clip, neighbours trim)</td></tr>
|
|
367
|
+
<tr><td><kbd>;</kbd> / <kbd>'</kbd></td><td>Lift / Extract IN→OUT on targeted tracks (Extract closes the gap)</td></tr>
|
|
368
|
+
<tr><td><kbd>⇧</kbd>+<kbd>E</kbd></td><td>Disable / enable selected clip(s) — hidden from preview and export</td></tr>
|
|
369
|
+
<tr><td><kbd>⇧</kbd>+<kbd>D</kbd></td><td>Crossfade the audio cut next to the selected clip (or at the playhead)</td></tr>
|
|
370
|
+
<tr><td><kbd>Ctrl/Cmd</kbd>+<kbd>L</kbd></td><td>Unlink / link video and its audio</td></tr>
|
|
371
|
+
<tr><td><kbd>Ctrl</kbd>+click bin</td><td>Import media files</td></tr>
|
|
372
|
+
<tr><td><kbd>Ctrl</kbd>+click clip</td><td>Add / remove from selection</td></tr>
|
|
373
|
+
<tr><td><kbd>Ctrl</kbd>+<kbd>A</kbd> / <kbd>Esc</kbd></td><td>Select all / deselect</td></tr>
|
|
374
|
+
<tr><td><kbd>←</kbd> <kbd>→</kbd></td><td>Step 1 frame (⇧ = 1 second)</td></tr>
|
|
375
|
+
<tr><td><kbd>↑</kbd> / <kbd>↓</kbd></td><td>Jump playhead to previous / next cut (selected clip In then Out; no selection → targeted tracks). Source monitor: In / Out marks</td></tr>
|
|
376
|
+
<tr><td><kbd>Ctrl/Cmd</kbd>+<kbd>←</kbd> / <kbd>Ctrl/Cmd</kbd>+<kbd>→</kbd></td><td>Go to previous / next keyframe (inspector follows)</td></tr>
|
|
377
|
+
<tr><td><kbd>Ctrl/Cmd</kbd>+click inspector label or slider</td><td>Reset property + clear all its keyframes</td></tr>
|
|
378
|
+
<tr><td><kbd>⇧</kbd>+click inspector label</td><td>Reset value at playhead, or remove that keyframe</td></tr>
|
|
379
|
+
<tr><td><kbd>[</kbd> / <kbd>]</kbd></td><td>Trim selected in / out to playhead</td></tr>
|
|
380
|
+
<tr><td><kbd>Home</kbd> / <kbd>End</kbd></td><td>Jump to start / end</td></tr>
|
|
381
|
+
</table>
|
|
382
|
+
<table class="keys">
|
|
383
|
+
<tr><td><kbd>M</kbd></td><td>Add / remove marker at playhead</td></tr>
|
|
384
|
+
<tr><td><kbd>⇧</kbd>+<kbd>M</kbd> / <kbd>Alt</kbd>+<kbd>⇧</kbd>+<kbd>M</kbd></td><td>Go to next / previous marker</td></tr>
|
|
385
|
+
<tr><td>Marker on ruler</td><td>Drag to move · click to jump · double-click or right-click to name / colour / delete · <b>Markers</b> button lists them all</td></tr>
|
|
386
|
+
<tr><td><kbd>0</kbd>–<kbd>9</kbd> / click timecode</td><td>Type a time: <code>01:15:00</code>, packed <code>1500</code> (= 15 s), <code>+30</code> / <code>-1:00</code> to offset, <code>12.5</code> seconds. Click IN / OUT readouts to type those too</td></tr>
|
|
387
|
+
<tr><td><kbd>I</kbd> / <kbd>O</kbd></td><td>Set Source In/Out (Source mode) or timeline work-area (Program; also bounds Export)</td></tr>
|
|
388
|
+
<tr><td><kbd>⇧</kbd>+<kbd>I</kbd> / <kbd>⇧</kbd>+<kbd>O</kbd></td><td>Clear Source or timeline IN / OUT</td></tr>
|
|
389
|
+
<tr><td><kbd>T</kbd></td><td>Split clips at IN/OUT markers</td></tr>
|
|
390
|
+
<tr><td><kbd>⇧</kbd>+<kbd>T</kbd></td><td>Trim clips to IN/OUT (remove heads/tails)</td></tr>
|
|
391
|
+
<tr><td>Limit (toolbar)</td><td>Play stops at OUT; Home/End use IN/OUT</td></tr>
|
|
392
|
+
<tr><td><kbd>N</kbd></td><td>Toggle snapping — <b>▾</b> picks targets (clip edges, playhead, markers, IN/OUT, keyframes, frame grid)</td></tr>
|
|
393
|
+
<tr><td><kbd>+</kbd> / <kbd>-</kbd></td><td>Zoom timeline</td></tr>
|
|
394
|
+
<tr><td><kbd>Z</kbd></td><td>Zoom to selected clip(s)</td></tr>
|
|
395
|
+
<tr><td><kbd>Alt</kbd>+<kbd>Z</kbd></td><td>Zoom to IN–OUT work area</td></tr>
|
|
396
|
+
<tr><td><kbd>⇧</kbd>+<kbd>Z</kbd></td><td>Zoom timeline to fit</td></tr>
|
|
397
|
+
<tr><td><kbd>Ctrl</kbd>+<kbd>Z</kbd> / <kbd>Ctrl</kbd>+<kbd>⇧</kbd>+<kbd>Z</kbd></td><td>Undo / redo</td></tr>
|
|
398
|
+
<tr><td><kbd>Ctrl</kbd>+wheel</td><td>Zoom timeline at cursor</td></tr>
|
|
399
|
+
<tr><td>Audio volume line</td><td>Drag to change the level · <kbd>Ctrl/Cmd</kbd>+click adds a keyframe · <kbd>Alt</kbd>+click or double-click removes one · corner grips drag fades</td></tr>
|
|
400
|
+
<tr class="keys-head"><td colspan="2">Color workspace</td></tr>
|
|
401
|
+
<tr><td>Colour wheel</td><td>Drag to tint (<kbd>⇧</kbd> = fine) · double-click resets the colour · double-click a label or slider name to reset it</td></tr>
|
|
402
|
+
<tr><td>WB pick / Pick</td><td>Click the monitor to balance, to mark a colour on the curves, or to select it in a layer's qualifier · <kbd>Esc</kbd> cancels</td></tr>
|
|
403
|
+
<tr><td>Curves</td><td>Click adds a point on the curve · drag moves it · double-click removes it</td></tr>
|
|
404
|
+
<tr><td>Layer mask on the monitor</td><td>Drag inside to move · handles resize · the knob rotates (<kbd>⇧</kbd> snaps to 15°) · poly: <kbd>Ctrl/Cmd</kbd>+click adds a point, double-click removes one</td></tr>
|
|
405
|
+
</table>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="dialog-actions"><button class="btn primary" id="btnCloseHelp">Close</button></div>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<div id="toast"></div>
|
|
412
|
+
|
|
413
|
+
<script src="loudness.js"></script>
|
|
414
|
+
<script src="ducking.js"></script>
|
|
415
|
+
<script src="audio-fx.js"></script>
|
|
416
|
+
<script src="color.js"></script>
|
|
417
|
+
<script src="edit-ops.js"></script>
|
|
418
|
+
<script src="app.js"></script>
|
|
419
|
+
</body>
|
|
420
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# FableCut asset library
|
|
2
|
+
|
|
3
|
+
Default, reusable assets. Everything here shows up live in the editor's left
|
|
4
|
+
panel tabs and can be dropped onto the timeline — files are referenced in
|
|
5
|
+
place (`/library/...`), never copied into the project.
|
|
6
|
+
|
|
7
|
+
| Folder | Editor tab | Contents |
|
|
8
|
+
| ----------- | ---------- | --------------------------------------------------------------- |
|
|
9
|
+
| `sfx/` | Sound FX | whooshes, clicks, risers, impacts… (`.mp3 .wav .ogg .m4a`) |
|
|
10
|
+
| `elements/` | Elements | overlay art: PNGs with alpha, light leaks, textures, short loops |
|
|
11
|
+
| `svg/` | SVG | vector animations authored by Claude (see CLAUDE.md conventions) |
|
|
12
|
+
| `fonts/` | (Font editor) | `.ttf .otf .woff .woff2` — auto-registered, family = file name |
|
|
13
|
+
|
|
14
|
+
Drop free assets you find online into the matching folder — the open editor
|
|
15
|
+
refreshes the list automatically. Subfolders are allowed and listed too.
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
|
2
|
+
<!-- FableCut element · drifting bokeh (loops ~8s) · blend:"screen", fit:"cover" -->
|
|
3
|
+
<style>
|
|
4
|
+
.b { animation: drift 8s ease-in-out infinite alternate; }
|
|
5
|
+
@keyframes drift {
|
|
6
|
+
from { transform: translate(0, 0); }
|
|
7
|
+
to { transform: translate(60px, -50px); }
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
<g fill="#ffffff">
|
|
11
|
+
<circle class="b" style="--d:0s" cx="140" cy="560" r="70" opacity="0.16"/>
|
|
12
|
+
<circle class="b" style="--d:-1.5s" cx="380" cy="180" r="45" opacity="0.12"/>
|
|
13
|
+
<circle class="b" style="--d:-3s" cx="720" cy="500" r="95" opacity="0.10"/>
|
|
14
|
+
<circle class="b" style="--d:-4.5s" cx="980" cy="150" r="55" opacity="0.15"/>
|
|
15
|
+
<circle class="b" style="--d:-6s" cx="1160" cy="420" r="80" opacity="0.11"/>
|
|
16
|
+
<circle class="b" style="--d:-2s" cx="560" cy="640" r="38" opacity="0.18"/>
|
|
17
|
+
<circle class="b" style="--d:-5s" cx="860" cy="300" r="28" opacity="0.20"/>
|
|
18
|
+
</g>
|
|
19
|
+
</svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
|
2
|
+
<!-- FableCut element · cool light leak · use with blend:"screen", fit:"cover", opacity ~0.7 -->
|
|
3
|
+
<defs>
|
|
4
|
+
<radialGradient id="a" cx="80%" cy="15%" r="60%">
|
|
5
|
+
<stop offset="0%" stop-color="#7cc7ff" stop-opacity="0.85"/>
|
|
6
|
+
<stop offset="50%" stop-color="#4f8cff" stop-opacity="0.35"/>
|
|
7
|
+
<stop offset="100%" stop-color="#3355ff" stop-opacity="0"/>
|
|
8
|
+
</radialGradient>
|
|
9
|
+
<radialGradient id="b" cx="10%" cy="90%" r="55%">
|
|
10
|
+
<stop offset="0%" stop-color="#b39dff" stop-opacity="0.55"/>
|
|
11
|
+
<stop offset="100%" stop-color="#7b6cff" stop-opacity="0"/>
|
|
12
|
+
</radialGradient>
|
|
13
|
+
</defs>
|
|
14
|
+
<rect width="1280" height="720" fill="url(#a)"/>
|
|
15
|
+
<rect width="1280" height="720" fill="url(#b)"/>
|
|
16
|
+
</svg>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
|
2
|
+
<!-- FableCut element · warm light leak · use with blend:"screen", fit:"cover", opacity ~0.7 -->
|
|
3
|
+
<defs>
|
|
4
|
+
<radialGradient id="a" cx="15%" cy="20%" r="55%">
|
|
5
|
+
<stop offset="0%" stop-color="#ffb36b" stop-opacity="0.95"/>
|
|
6
|
+
<stop offset="45%" stop-color="#ff7a3c" stop-opacity="0.45"/>
|
|
7
|
+
<stop offset="100%" stop-color="#ff5d2e" stop-opacity="0"/>
|
|
8
|
+
</radialGradient>
|
|
9
|
+
<radialGradient id="b" cx="85%" cy="80%" r="60%">
|
|
10
|
+
<stop offset="0%" stop-color="#ffd9a0" stop-opacity="0.6"/>
|
|
11
|
+
<stop offset="100%" stop-color="#ff8a5c" stop-opacity="0"/>
|
|
12
|
+
</radialGradient>
|
|
13
|
+
<linearGradient id="c" x1="0" y1="0" x2="1" y2="0.3">
|
|
14
|
+
<stop offset="0%" stop-color="#ff6b35" stop-opacity="0.35"/>
|
|
15
|
+
<stop offset="30%" stop-color="#ff6b35" stop-opacity="0"/>
|
|
16
|
+
<stop offset="100%" stop-color="#ff6b35" stop-opacity="0"/>
|
|
17
|
+
</linearGradient>
|
|
18
|
+
</defs>
|
|
19
|
+
<rect width="1280" height="720" fill="url(#a)"/>
|
|
20
|
+
<rect width="1280" height="720" fill="url(#b)"/>
|
|
21
|
+
<rect width="1280" height="720" fill="url(#c)"/>
|
|
22
|
+
</svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
|
2
|
+
<!-- FableCut element · VHS scanlines + edge tint · blend:"overlay" or "soft-light",
|
|
3
|
+
fit:"stretch", opacity ~0.5. Pair with rgbSplit + grain props for full VHS. -->
|
|
4
|
+
<defs>
|
|
5
|
+
<pattern id="lines" width="4" height="4" patternUnits="userSpaceOnUse">
|
|
6
|
+
<rect width="4" height="2" fill="#000000" opacity="0.55"/>
|
|
7
|
+
<rect y="2" width="4" height="2" fill="#ffffff" opacity="0.05"/>
|
|
8
|
+
</pattern>
|
|
9
|
+
<linearGradient id="edge" x1="0" y1="0" x2="0" y2="1">
|
|
10
|
+
<stop offset="0%" stop-color="#00ffc8" stop-opacity="0.14"/>
|
|
11
|
+
<stop offset="8%" stop-color="#00ffc8" stop-opacity="0"/>
|
|
12
|
+
<stop offset="92%" stop-color="#ff00a8" stop-opacity="0"/>
|
|
13
|
+
<stop offset="100%" stop-color="#ff00a8" stop-opacity="0.14"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
</defs>
|
|
16
|
+
<rect width="1280" height="720" fill="url(#lines)"/>
|
|
17
|
+
<rect width="1280" height="720" fill="url(#edge)"/>
|
|
18
|
+
</svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
|
2
|
+
<!-- FableCut element · cinematic letterbox bars + soft frame · fit:"stretch" -->
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="soft" x1="0" y1="0" x2="0" y2="1">
|
|
5
|
+
<stop offset="0%" stop-color="#000" stop-opacity="0.55"/>
|
|
6
|
+
<stop offset="12%" stop-color="#000" stop-opacity="0"/>
|
|
7
|
+
<stop offset="88%" stop-color="#000" stop-opacity="0"/>
|
|
8
|
+
<stop offset="100%" stop-color="#000" stop-opacity="0.55"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
</defs>
|
|
11
|
+
<rect width="1280" height="76" fill="#000"/>
|
|
12
|
+
<rect y="644" width="1280" height="76" fill="#000"/>
|
|
13
|
+
<rect width="1280" height="720" fill="url(#soft)"/>
|
|
14
|
+
</svg>
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|