@tikagent/video-editor-cli 0.0.0-stage → 1.5.0-preview.2

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 (87) hide show
  1. package/LICENSE +82 -0
  2. package/THIRD-PARTY-NOTICES.md +21 -0
  3. package/dist/bin/tik-video-editor-cli.js +2 -0
  4. package/dist/lib/asr.js +1 -0
  5. package/dist/lib/audio.js +1 -0
  6. package/dist/lib/auth.js +1 -0
  7. package/dist/lib/browser-zip.js +1 -0
  8. package/dist/lib/browser.js +1 -0
  9. package/dist/lib/cli.js +1 -0
  10. package/dist/lib/doctor.js +1 -0
  11. package/dist/lib/download.js +1 -0
  12. package/dist/lib/export-progress.js +1 -0
  13. package/dist/lib/import-video.js +1 -0
  14. package/dist/lib/local.js +1 -0
  15. package/dist/lib/media.js +1 -0
  16. package/dist/lib/operation.js +1 -0
  17. package/dist/lib/otlp.js +1 -0
  18. package/dist/lib/preset.js +1 -0
  19. package/dist/lib/processes.js +1 -0
  20. package/dist/lib/self.js +1 -0
  21. package/dist/lib/service-urls.js +1 -0
  22. package/dist/lib/storage.js +1 -0
  23. package/dist/lib/telemetry.js +1 -0
  24. package/dist/runtime/LICENSE +21 -0
  25. package/dist/runtime/analyze.js +1 -0
  26. package/dist/runtime/app.js +1 -0
  27. package/dist/runtime/cli/lib/browser-zip.js +1 -0
  28. package/dist/runtime/cli/lib/browser.js +1 -0
  29. package/dist/runtime/cli/lib/otlp.js +1 -0
  30. package/dist/runtime/cli/lib/processes.js +1 -0
  31. package/dist/runtime/cli/lib/telemetry.js +1 -0
  32. package/dist/runtime/export-audio.js +1 -0
  33. package/dist/runtime/export-cache.js +1 -0
  34. package/dist/runtime/export-encoder.js +1 -0
  35. package/dist/runtime/export-save.js +1 -0
  36. package/dist/runtime/export-worker.js +1 -0
  37. package/dist/runtime/favicon.svg +14 -0
  38. package/dist/runtime/i18n.js +1 -0
  39. package/dist/runtime/icons/favicon-32.png +0 -0
  40. package/dist/runtime/icons/tik-logo.png +0 -0
  41. package/dist/runtime/index.html +320 -0
  42. package/dist/runtime/library/README.md +12 -0
  43. package/dist/runtime/library/elements/bokeh-drift.svg +19 -0
  44. package/dist/runtime/library/elements/light-leak-cool.svg +16 -0
  45. package/dist/runtime/library/elements/light-leak-warm.svg +22 -0
  46. package/dist/runtime/library/elements/vhs-scanlines.svg +18 -0
  47. package/dist/runtime/library/elements/vignette-frame.svg +14 -0
  48. package/dist/runtime/library/fonts//351/230/277/351/207/214/345/267/264/345/267/264/346/231/256/346/203/240/344/275/223-/344/270/255/351/273/221.woff2 +0 -0
  49. package/dist/runtime/library/fonts//351/230/277/351/207/214/345/267/264/345/267/264/346/231/256/346/203/240/344/275/223-/345/270/270/350/247/204.woff2 +0 -0
  50. package/dist/runtime/library/fonts//351/230/277/351/207/214/345/267/264/345/267/264/346/231/256/346/203/240/344/275/223-/347/262/227/344/275/223.woff2 +0 -0
  51. package/dist/runtime/library/sfx/README.md +13 -0
  52. package/dist/runtime/library/svg/arrow-bounce.svg +18 -0
  53. package/dist/runtime/library/svg/arrow-scribble.svg +13 -0
  54. package/dist/runtime/library/svg/burst-lines.svg +30 -0
  55. package/dist/runtime/library/svg/checkmark-success.svg +19 -0
  56. package/dist/runtime/library/svg/confetti-burst.svg +23 -0
  57. package/dist/runtime/library/svg/countdown-ring.svg +92 -0
  58. package/dist/runtime/library/svg/equalizer.svg +18 -0
  59. package/dist/runtime/library/svg/glow-orbs.svg +29 -0
  60. package/dist/runtime/library/svg/heart-pop.svg +26 -0
  61. package/dist/runtime/library/svg/loading-dots.svg +16 -0
  62. package/dist/runtime/library/svg/location-pin.svg +25 -0
  63. package/dist/runtime/library/svg/lower-third.svg +17 -0
  64. package/dist/runtime/library/svg/new-badge.svg +18 -0
  65. package/dist/runtime/library/svg/progress-bar.svg +16 -0
  66. package/dist/runtime/library/svg/radial-pulse.svg +19 -0
  67. package/dist/runtime/library/svg/rating-stars.svg +25 -0
  68. package/dist/runtime/library/svg/rec-indicator.svg +41 -0
  69. package/dist/runtime/library/svg/sparkles.svg +17 -0
  70. package/dist/runtime/library/svg/speech-bubble.svg +23 -0
  71. package/dist/runtime/library/svg/subscribe-bell.svg +29 -0
  72. package/dist/runtime/library/svg/subscribe-pill.svg +22 -0
  73. package/dist/runtime/library/svg/swipe-up.svg +46 -0
  74. package/dist/runtime/library/svg/underline-swoosh.svg +15 -0
  75. package/dist/runtime/manifest.json +40 -0
  76. package/dist/runtime/meter-worklet.js +1 -0
  77. package/dist/runtime/optimized-encoder-worker.js +1 -0
  78. package/dist/runtime/optimized-export.js +1 -0
  79. package/dist/runtime/paths.js +1 -0
  80. package/dist/runtime/project-store.js +1 -0
  81. package/dist/runtime/ruler-worker.js +1 -0
  82. package/dist/runtime/server.js +1 -0
  83. package/dist/runtime/style.css +2126 -0
  84. package/dist/runtime/timeline.js +1 -0
  85. package/dist/runtime/waveform.js +1 -0
  86. package/package.json +36 -4
  87. package/README.md +0 -3
@@ -0,0 +1,320 @@
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>提客AI智能体</title>
7
+ <link rel="icon" href="icons/tik-logo.png" type="image/png">
8
+ <meta name="theme-color" content="#0e0e10">
9
+ <link rel="stylesheet" href="style.css">
10
+ </head>
11
+ <body>
12
+ <dialog id="projectLoadDialog" class="dialog project-load-dialog" aria-labelledby="projectLoadTitle" aria-describedby="projectLoadHelp">
13
+ <h2 id="projectLoadTitle"></h2>
14
+ <p id="projectLoadHelp"></p>
15
+ <p id="projectLoadId" class="project-load-id"></p>
16
+ <details><summary data-i18n="Error details">Error details</summary><p id="projectLoadDetails"></p></details>
17
+ <div class="dialog-actions"><button class="btn primary" id="btnRetryProject" data-i18n="Retry loading">Retry loading</button></div>
18
+ </dialog>
19
+ <div class="app" id="app">
20
+
21
+ <!-- ══════════ TOP BAR ══════════ -->
22
+ <header class="topbar">
23
+ <div class="logo"><img class="logo-mark" src="icons/tik-logo.png" alt=""> <b>提客AI智能体</b></div>
24
+ <div class="topbar-center">
25
+ <span id="currentProjectName" class="current-project-name"></span>
26
+ <select id="projectSelect" class="project-select" data-ui-setting="showProjectSwitcher" title="Open project" data-i18n-title="Open project"></select>
27
+ <button type="button" class="btn tiny" id="btnNewProject" data-ui-setting="showNewProject" title="Create a project" data-i18n-title="Create a project"><span data-i18n="+ Project">+ Project</span></button>
28
+ <span id="projectName" class="connection-status" data-ui-setting="showConnectionStatus"><span data-i18n="⚪ local session">⚪ local session</span></span>
29
+ </div>
30
+ <div class="topbar-right">
31
+ <span class="layout-tools" data-ui-setting="showLayoutControls">
32
+ <button type="button" class="btn tiny" id="btnLayoutReset" title="Restore default layout" data-i18n-title="Restore default layout"><span data-i18n="⊡ Layout">⊡ Layout</span></button>
33
+ <span class="btn-group" id="trackSizeGroup" title="Timeline track height" data-i18n-title="Timeline track height">
34
+ <button type="button" class="btn tiny" data-track-size="s" title="Compact tracks (no thumbnails)" data-i18n-title="Compact tracks (no thumbnails)"><span data-i18n="S">S</span></button>
35
+ <button type="button" class="btn tiny" data-track-size="m" title="Medium tracks" data-i18n-title="Medium tracks"><span data-i18n="M">M</span></button>
36
+ <button type="button" class="btn tiny" data-track-size="l" title="Large tracks" data-i18n-title="Large tracks"><span data-i18n="L">L</span></button>
37
+ </span>
38
+ </span>
39
+ <button class="btn ghost" id="btnSettings" data-ui-setting="showSettings" title="Settings" aria-label="Settings" data-i18n-title="Settings" data-i18n-aria-label="Settings">
40
+ <svg class="ico" viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
41
+ <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"/>
42
+ </svg>
43
+ </button>
44
+ <button class="btn ghost" id="btnHelp" data-ui-setting="showShortcuts" title="Keyboard shortcuts" data-i18n-title="Keyboard shortcuts">?</button>
45
+ <button class="btn primary" id="btnExport"><span data-i18n="⬇ Export">⬇ Export</span></button>
46
+ </div>
47
+ </header>
48
+
49
+ <!-- ══════════ UPPER PANELS ══════════ -->
50
+ <div class="upper">
51
+
52
+ <!-- Media bin -->
53
+ <aside class="panel bin" data-ui-setting="showAssets">
54
+ <div class="panel-head">
55
+ <span><span data-i18n="Assets">Assets</span></span>
56
+ <span class="panel-head-actions">
57
+ <button type="button" class="btn tiny" id="btnTitle" title="Add text at the playhead" data-i18n-title="Add text at the playhead"><span data-i18n="+ Text">+ Text</span></button>
58
+ <button type="button" class="btn tiny" id="btnAdjust" title="Add an adjustment layer (grades everything below it)" data-i18n-title="Add an adjustment layer (grades everything below it)"><span data-i18n="+ Adjust">+ Adjust</span></button>
59
+ <label class="btn tiny accent" id="btnImport" for="fileInput" title="Import media files" data-i18n-title="Import media files"><span data-i18n="+ Import">+ Import</span></label>
60
+ </span>
61
+ </div>
62
+ <div class="bin-tabs" id="binTabs">
63
+ <button type="button" data-tab="project" class="on" title="Media used by this project — right-click for New folder" data-i18n-title="Media used by this project — right-click for New folder"><span data-i18n="Media">Media</span></button>
64
+ <button type="button" data-tab="elements" title="Overlay art from library/elements" data-i18n-title="Overlay art from library/elements"><span data-i18n="Elements">Elements</span></button>
65
+ <button type="button" data-tab="sfx" title="Sound effects from library/sfx" data-i18n-title="Sound effects from library/sfx"><span data-i18n="Sound FX">Sound FX</span></button>
66
+ <button type="button" data-tab="svg" title="Vector animations from library/svg" data-i18n-title="Vector animations from library/svg"><span data-i18n="SVG">SVG</span></button>
67
+ </div>
68
+ <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">
69
+ <div class="bin-list" id="binList">
70
+ <div class="bin-empty" id="binEmpty">
71
+ <div class="bin-empty-icon">🎬</div>
72
+ <p><span data-i18n="Drop video, audio or images here">Drop video, audio or images here</span><br><span data-i18n="or click">or click</span> <b><span data-i18n="+ Import">+ Import</span></b></p>
73
+ <p class="hint"><span data-i18n="Then drag media onto the timeline below.">Then drag media onto the timeline below.</span></p>
74
+ </div>
75
+ </div>
76
+ <div class="bin-list hidden" id="libList"></div>
77
+ </aside>
78
+
79
+ <!-- Program monitor -->
80
+ <section class="panel monitor">
81
+ <div class="panel-head" data-ui-setting="showMonitorHeader">
82
+ <span class="panel-head-title">
83
+ <span><span data-i18n="Program Monitor">Program Monitor</span></span>
84
+ <button class="btn tiny hidden" id="btnZoom100" title="Reset monitor view to fit stage" data-i18n-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> <span data-i18n="Fit">Fit</span></button>
85
+ </span>
86
+ <span class="panel-head-actions">
87
+ <select id="aspectSel" class="head-select" title="Canvas aspect preset" data-i18n-title="Canvas aspect preset"></select>
88
+ <select id="fpsSel" class="head-select" title="Project frame rate" data-i18n-title="Project frame rate"></select>
89
+ <button class="btn tiny toggle" id="btnGuides" title="Toggle safe-area guides" data-i18n-title="Toggle safe-area guides"><span data-i18n="▦ Safe">▦ Safe</span></button>
90
+ </span>
91
+ </div>
92
+ <div class="monitor-stage" id="monitorStage">
93
+ <div class="monitor-scroll" id="monitorScroll">
94
+ <div class="monitor-zoom-inner" id="monitorZoomInner">
95
+ <canvas id="preview" width="1280" height="720"></canvas>
96
+ <div id="safeOverlay" class="hidden">
97
+ <div class="sa-action"></div>
98
+ <div class="sa-title"></div>
99
+ <div class="sa-ui-bottom"></div>
100
+ <div class="sa-ui-right"></div>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ <div class="kf-graphs" id="kfGraphs" hidden></div>
105
+ <div class="missing-media-notice" id="missingMediaNotice" role="status" aria-live="polite" hidden>
106
+ <span class="missing-media-icon" aria-hidden="true">⚠</span>
107
+ <strong id="missingMediaTitle"></strong>
108
+ <span id="missingMediaNames"></span>
109
+ <span id="missingMediaHelp"></span>
110
+ <button class="btn" id="btnRetryMedia" data-i18n="Check again">Check again</button>
111
+ </div>
112
+ <div class="vu-meter" id="vuMeter" data-ui-setting="showAudioMeter" title="Click to switch RMS / LUFS / Peak" data-i18n-title="Click to switch RMS / LUFS / Peak"></div>
113
+ </div>
114
+ <div class="transport">
115
+ <span class="timecode" id="tcCurrent">00:00:00</span>
116
+ <div class="transport-btns">
117
+ <button class="btn icon" id="btnHome" data-ui-setting="showBoundaryNavigation" title="Go to start (Home)" data-i18n-title="Go to start (Home)">⏮</button>
118
+ <button class="btn icon" id="btnBack" title="Back 1 frame (←)" data-i18n-title="Back 1 frame (←)">◀︎</button>
119
+ <button class="btn icon big" id="btnPlay" title="Play / Pause (Space)" data-i18n-title="Play / Pause (Space)">▶</button>
120
+ <button class="btn icon" id="btnFwd" title="Forward 1 frame (→)" data-i18n-title="Forward 1 frame (→)">▶︎</button>
121
+ <button class="btn icon" id="btnEnd" data-ui-setting="showBoundaryNavigation" title="Go to end (End)" data-i18n-title="Go to end (End)">⏭</button>
122
+ <button class="btn icon toggle" id="btnSpeed" title="Preview speed — click to cycle 1×/1.5×/2×/4×. While playing: L faster · J slower · K play/pause and reset to 1×. Preview only, not export." data-i18n-title="Preview speed — click to cycle 1×/1.5×/2×/4×. While playing: L faster · J slower · K play/pause and reset to 1×. Preview only, not export.">1×</button>
123
+ </div>
124
+ <span class="timecode dim" id="tcTotal">00:00:00</span>
125
+ </div>
126
+ </section>
127
+
128
+ <!-- Inspector -->
129
+ <aside class="panel inspector" data-ui-setting="showInspector">
130
+ <div class="panel-head"><span><span data-i18n="Inspector">Inspector</span></span></div>
131
+ <div class="inspector-body" id="inspector">
132
+ <div class="inspector-empty"><span data-i18n="Select a clip to edit its">Select a clip to edit its</span><br><span data-i18n="transform, effects &amp; audio.">transform, effects &amp; audio.</span></div>
133
+ </div>
134
+ </aside>
135
+ </div>
136
+
137
+ <div class="v-split" id="splitUpperTimeline" role="separator" aria-orientation="horizontal" title="Drag to resize · double-click to reset" data-i18n-title="Drag to resize · double-click to reset"></div>
138
+
139
+ <!-- ══════════ TIMELINE ══════════ -->
140
+ <section class="panel timeline-panel" id="timelinePanel">
141
+ <div class="timeline-toolbar">
142
+ <button class="btn tiny hidden" id="btnTrimIO" title="Trim clips to IN/OUT (⇧T)" data-i18n-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> <span data-i18n="Trim">Trim</span></button>
143
+ <button class="btn tiny toggle hidden" id="btnWorkAreaPlay" title="Limit playback to IN/OUT (Home/End jump to markers; playhead outside = override)" data-i18n-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> <span data-i18n="Limit">Limit</span></button>
144
+ <button class="btn tiny" id="btnSplit" title="Split at playhead (S)" data-i18n-title="Split at playhead (S)"><span data-i18n="✂ Split">✂ Split</span></button>
145
+ <button type="button" class="btn tiny" id="btnUndo" disabled title="Undo (Ctrl/Cmd+Z)" data-i18n-title="Undo (Ctrl/Cmd+Z)"><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.5 2.5 2 6l3.5 3.5M2 6h7a4 4 0 0 1 0 8"/></svg> <span data-i18n="Undo">Undo</span></button>
146
+ <button type="button" class="btn tiny" id="btnRedo" disabled title="Redo (Ctrl/Cmd+Shift+Z)" data-i18n-title="Redo (Ctrl/Cmd+Shift+Z)"><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="m10.5 2.5 3.5 3.5-3.5 3.5M14 6H7a4 4 0 0 0 0 8"/></svg> <span data-i18n="Redo">Redo</span></button>
147
+ <button class="btn tiny" id="btnCloseGap" data-ui-setting="showCloseGap" title="Close gap at playhead (⇧G)" data-i18n-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> <span data-i18n="Close gap">Close gap</span></button>
148
+ <button class="btn tiny" id="btnNextGap" data-ui-setting="showFindGap" title="Find gap (G)" data-i18n-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> <span data-i18n="Find gap">Find gap</span></button>
149
+ <button class="btn tiny" id="btnDelete" title="Delete selected (Del)" data-i18n-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> <span data-i18n="Delete">Delete</span></button>
150
+ <button class="btn tiny toggle on" id="btnSnap" data-ui-setting="showSnap" title="Toggle snapping (N)" data-i18n-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> <span data-i18n="Snap">Snap</span></button>
151
+ <button class="btn tiny toggle" id="btnAudioHold" data-ui-setting="showAudioHold" title="Audio Hold — while paused, loop one frame of audio at the playhead. Play/Stop turns it off." data-i18n-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> <span data-i18n="Audio hold">Audio hold</span></button>
152
+ <div class="thumbnail-progress" id="thumbProgress" hidden>
153
+ <label id="thumbProgressLabel" for="thumbProgressBar"></label>
154
+ <progress id="thumbProgressBar" max="1" value="0"></progress>
155
+ </div>
156
+ <div class="timeline-zoom-controls">
157
+ <span class="dim tiny-label"><span data-i18n="Zoom">Zoom</span></span>
158
+ <button type="button" class="btn tiny zoom-step" id="btnZoomOut" title="Zoom out (-)" aria-label="Zoom out (-)" data-i18n-title="Zoom out (-)" data-i18n-aria-label="Zoom out (-)">−</button>
159
+ <input type="range" id="zoomSlider" min="1" max="300" value="60" aria-label="Timeline zoom" data-i18n-aria-label="Timeline zoom">
160
+ <button type="button" class="btn tiny zoom-step" id="btnZoomIn" title="Zoom in (+)" aria-label="Zoom in (+)" data-i18n-title="Zoom in (+)" data-i18n-aria-label="Zoom in (+)">+</button>
161
+ <button class="btn tiny" id="btnZoomFit" data-ui-setting="showTimelineFit" title="Zoom timeline to fit (⇧Z)" data-i18n-title="Zoom timeline to fit (⇧Z)"><span class="fit-icon">│<span class="fit-arrow">↔</span>│</span> <span data-i18n="Fit">Fit</span></button>
162
+ </div>
163
+ </div>
164
+ <div class="timeline">
165
+ <div class="track-headers" id="trackHeaders"></div>
166
+ <div class="timeline-scroll" id="timelineScroll">
167
+ <canvas class="ruler" id="ruler"></canvas>
168
+ <div class="tracks-content" id="tracksContent">
169
+ <div class="work-dim work-dim-l hidden" id="workDimL"></div>
170
+ <div class="work-dim work-dim-r hidden" id="workDimR"></div>
171
+ <div class="tracks" id="tracks"></div>
172
+ <div class="playhead" id="playhead"><div class="playhead-cap"></div></div>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </section>
177
+ </div>
178
+
179
+ <!-- ══════════ EXPORT OVERLAY ══════════ -->
180
+ <div class="overlay hidden" id="exportOverlay">
181
+ <div class="dialog export-dialog" id="exportDialog" role="dialog" aria-modal="true" aria-labelledby="exportTitle" tabindex="-1">
182
+ <header class="export-header">
183
+ <svg class="export-header-icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="M3 5h18v15H3zM3 10h18M7 5l3 5m4-5 3 5"/></svg>
184
+ <div class="export-heading"><h2 id="exportTitle"></h2><p id="exportDuration"></p></div>
185
+ <button class="export-close" id="btnCloseExport" data-i18n-aria-label="Close" data-i18n-title="Close" aria-label="Close" title="Close">×</button>
186
+ </header>
187
+ <div class="export-body">
188
+ <div class="export-preview" id="exportPreview">
189
+ <video id="exportVideo" playsinline preload="metadata" data-i18n-aria-label="Export preview" aria-label="Export preview"></video>
190
+ <button class="export-play" id="btnExportPreview" disabled data-i18n-aria-label="Play exported video" aria-label="Play exported video"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="m9 5 10 7-10 7z"/></svg></button>
191
+ <span class="export-time" id="exportTime"></span>
192
+ </div>
193
+ </div>
194
+ <footer class="export-footer">
195
+ <div class="export-status-row"><span class="export-status-icon" aria-hidden="true"></span><span id="exportNote" role="status"></span><strong id="exportPercent">0%</strong></div>
196
+ <div class="progress" id="exportProgressTrack" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" data-i18n-aria-label="Export progress" aria-label="Export progress"><div class="progress-fill" id="exportProgress"></div></div>
197
+ <div class="export-track-warn hidden" id="exportTrackWarn" role="status"></div>
198
+ <div class="export-recovery">
199
+ <div class="dialog-actions">
200
+ <button class="btn primary export-quick" id="btnSaveExport" hidden><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12m-4-4 4 4 4-4M5 15v5h14v-5"/></svg><span id="exportSaveLabel" data-i18n="Save">Save</span></button>
201
+ <button class="btn" id="btnRetryExport" hidden data-i18n="Retry export">Retry export</button>
202
+ <button class="btn primary export-quick" id="btnExportFallback" hidden><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" aria-hidden="true"><path d="m13 2-9 12h7l-1 8 10-13h-7z"/></svg><span data-i18n="Quick export">Quick export</span></button>
203
+ <button class="btn" id="btnCancelExport" hidden data-i18n="Cancel">Cancel</button>
204
+ </div>
205
+ </div>
206
+ <p class="export-save-note" id="exportSaveNote" role="status" hidden></p>
207
+ </footer>
208
+ </div>
209
+ </div>
210
+
211
+ <!-- 取消导出需明确确认;原生模态框负责焦点限制与键盘访问。 -->
212
+ <dialog class="dialog export-cancel-dialog" id="cancelExportDialog" aria-labelledby="cancelExportTitle" aria-describedby="cancelExportDescription">
213
+ <h2 id="cancelExportTitle" data-i18n="Cancel this export?">Cancel this export?</h2>
214
+ <p id="cancelExportDescription" data-i18n="The video is still exporting. Cancelling will stop this task.">The video is still exporting. Cancelling will stop this task.</p>
215
+ <div class="dialog-actions">
216
+ <button class="btn" id="btnContinueExport" autofocus data-i18n="Continue export">Continue export</button>
217
+ <button class="btn export-cancel-confirm" id="btnConfirmCancelExport" data-i18n="Confirm cancellation">Confirm cancellation</button>
218
+ </div>
219
+ </dialog>
220
+
221
+ <!-- ══════════ SETTINGS OVERLAY ══════════ -->
222
+ <div class="overlay hidden" id="settingsOverlay">
223
+ <div class="dialog settings" id="settingsDialog" role="dialog" aria-modal="true" aria-labelledby="settingsTitle" tabindex="-1">
224
+ <h2 id="settingsTitle"><span data-i18n="Settings">Settings</span></h2>
225
+ <p class="dim settings-intro"><span data-i18n="Preferences are stored in this browser only.">Preferences are stored in this browser only.</span></p>
226
+ <div class="settings-section">
227
+ <h3><span data-i18n="Language">Language</span></h3>
228
+ <label class="settings-row language-row" for="setLanguage">
229
+ <span class="settings-label"><span data-i18n="Interface language">Interface language</span></span>
230
+ <select id="setLanguage" aria-label="Interface language" data-i18n-aria-label="Interface language">
231
+ <option value="zh-CN">简体中文</option>
232
+ <option value="en">English</option>
233
+ </select>
234
+ </label>
235
+ </div>
236
+ <div class="settings-section">
237
+ <h3><span data-i18n="Selection">Selection</span></h3>
238
+ <label class="settings-row">
239
+ <input type="checkbox" id="setLinkSelect">
240
+ <span>
241
+ <span class="settings-label"><span data-i18n="Link timeline and Project bin selection">Link timeline and Project bin selection</span></span>
242
+ <span class="settings-hint"><span data-i18n="Selecting a timeline clip highlights its media in Project, and the reverse. Off by default.">Selecting a timeline clip highlights its media in Project, and the reverse. Off by default.</span></span>
243
+ </span>
244
+ </label>
245
+ </div>
246
+ <div class="settings-section">
247
+ <h3><span data-i18n="Visible modules">Visible modules</span></h3>
248
+ <p class="settings-hint"><span data-i18n="Hidden modules keep their functions and shortcuts.">Hidden modules keep their functions and shortcuts.</span></p>
249
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showAssets"><span data-i18n="Assets panel">Assets panel</span></label>
250
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showInspector"><span data-i18n="Inspector panel">Inspector panel</span></label>
251
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showNewProject"><span data-i18n="Create a project">Create a project</span></label>
252
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showConnectionStatus"><span data-i18n="Connection status">Connection status</span></label>
253
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showSettings"><span data-i18n="Settings button">Settings button</span></label>
254
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showCloseGap"><span data-i18n="Close gap">Close gap</span></label>
255
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showFindGap"><span data-i18n="Find gap">Find gap</span></label>
256
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showSnap"><span data-i18n="Snap">Snap</span></label>
257
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showAudioHold"><span data-i18n="Audio hold">Audio hold</span></label>
258
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showProjectSwitcher"><span data-i18n="Project switcher">Project switcher</span></label>
259
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showLayoutControls"><span data-i18n="Layout controls">Layout controls</span></label>
260
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showShortcuts"><span data-i18n="Keyboard shortcuts">Keyboard shortcuts</span></label>
261
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showMonitorHeader"><span data-i18n="Monitor toolbar">Monitor toolbar</span></label>
262
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showAudioMeter"><span data-i18n="Audio meter">Audio meter</span></label>
263
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showBoundaryNavigation"><span data-i18n="Go to start / end">Go to start / end</span></label>
264
+ <label class="settings-row"><input type="checkbox" data-visibility-setting="showTimelineFit"><span data-i18n="Fit timeline">Fit timeline</span></label>
265
+ </div>
266
+ <div class="dialog-actions"><button class="btn primary" id="btnCloseSettings"><span data-i18n="Close">Close</span></button></div>
267
+ </div>
268
+ </div>
269
+
270
+ <!-- ══════════ HELP OVERLAY ══════════ -->
271
+ <div class="overlay hidden" id="helpOverlay">
272
+ <div class="dialog help">
273
+ <h2><span data-i18n="Keyboard shortcuts">Keyboard shortcuts</span></h2>
274
+ <div class="keys-cols">
275
+ <table class="keys">
276
+ <tr><td><kbd>Space</kbd></td><td><span data-i18n="Play / pause">Play / pause</span></td></tr>
277
+ <tr><td><kbd>J</kbd> <kbd>K</kbd> <kbd>L</kbd></td><td><span data-i18n="Shuttle preview —">Shuttle preview —</span> <kbd>L</kbd> <span data-i18n="faster /">faster /</span> <kbd>J</kbd> <span data-i18n="slower (1× · 1.5× · 2× · 4×);">slower (1× · 1.5× · 2× · 4×);</span> <kbd>K</kbd> <span data-i18n="play/pause + reset to 1×">play/pause + reset to 1×</span></td></tr>
278
+ <tr><td><kbd>S</kbd></td><td><span data-i18n="Split clip(s) at playhead">Split clip(s) at playhead</span></td></tr>
279
+ <tr><td><kbd>G</kbd></td><td><span data-i18n="Find next shared gap (wraps; respects IN/OUT)">Find next shared gap (wraps; respects IN/OUT)</span></td></tr>
280
+ <tr><td><kbd>⇧</kbd>+<kbd>G</kbd></td><td><span data-i18n="Close gap at playhead (enabled tracks)">Close gap at playhead (enabled tracks)</span></td></tr>
281
+ <tr><td><kbd>Alt</kbd>+<kbd>T</kbd></td><td><span data-i18n="Add transition at playhead (in / out by half)">Add transition at playhead (in / out by half)</span></td></tr>
282
+ <tr><td><kbd>Del</kbd></td><td><span data-i18n="Delete selected clip(s), or clear focused transition">Delete selected clip(s), or clear focused transition</span></td></tr>
283
+ <tr><td><span data-i18n="Drag empty area">Drag empty area</span></td><td><span data-i18n="Marquee-select clips">Marquee-select clips</span></td></tr>
284
+ <tr><td><kbd>Ctrl</kbd><span data-i18n="+click bin">+click bin</span></td><td><span data-i18n="Import media files">Import media files</span></td></tr>
285
+ <tr><td><kbd>Ctrl</kbd><span data-i18n="+click clip">+click clip</span></td><td><span data-i18n="Add / remove from selection">Add / remove from selection</span></td></tr>
286
+ <tr><td><kbd>Ctrl</kbd>+<kbd>A</kbd> / <kbd>Esc</kbd></td><td><span data-i18n="Select all / deselect">Select all / deselect</span></td></tr>
287
+ <tr><td><kbd>←</kbd> <kbd>→</kbd></td><td><span data-i18n="Step 1 frame (⇧ = 1 second)">Step 1 frame (⇧ = 1 second)</span></td></tr>
288
+ <tr><td><kbd>Ctrl</kbd>+<kbd>←</kbd> / <kbd>Ctrl</kbd>+<kbd>→</kbd></td><td><span data-i18n="Go to previous / next keyframe">Go to previous / next keyframe</span></td></tr>
289
+ <tr><td><kbd>[</kbd> / <kbd>]</kbd></td><td><span data-i18n="Trim selected in / out to playhead">Trim selected in / out to playhead</span></td></tr>
290
+ <tr><td><kbd>Home</kbd> / <kbd>End</kbd></td><td><span data-i18n="Jump to start / end">Jump to start / end</span></td></tr>
291
+ </table>
292
+ <table class="keys">
293
+ <tr><td><kbd>M</kbd></td><td><span data-i18n="Add / remove marker at playhead">Add / remove marker at playhead</span></td></tr>
294
+ <tr><td><kbd>I</kbd> / <kbd>O</kbd></td><td><span data-i18n="Set IN / OUT work-area marker">Set IN / OUT work-area marker</span></td></tr>
295
+ <tr><td><kbd>⇧</kbd>+<kbd>I</kbd> / <kbd>⇧</kbd>+<kbd>O</kbd></td><td><span data-i18n="Clear IN / OUT marker">Clear IN / OUT marker</span></td></tr>
296
+ <tr><td><kbd>T</kbd></td><td><span data-i18n="Split clips at IN/OUT markers">Split clips at IN/OUT markers</span></td></tr>
297
+ <tr><td><kbd>⇧</kbd>+<kbd>T</kbd></td><td><span data-i18n="Trim clips to IN/OUT (remove heads/tails)">Trim clips to IN/OUT (remove heads/tails)</span></td></tr>
298
+ <tr><td><span data-i18n="Limit (toolbar)">Limit (toolbar)</span></td><td><span data-i18n="Play stops at OUT; Home/End use IN/OUT">Play stops at OUT; Home/End use IN/OUT</span></td></tr>
299
+ <tr><td><kbd>N</kbd></td><td><span data-i18n="Toggle snapping">Toggle snapping</span></td></tr>
300
+ <tr><td><kbd>+</kbd> / <kbd>-</kbd></td><td><span data-i18n="Zoom timeline">Zoom timeline</span></td></tr>
301
+ <tr><td><kbd>Z</kbd></td><td><span data-i18n="Zoom to selected clip(s)">Zoom to selected clip(s)</span></td></tr>
302
+ <tr><td><kbd>Alt</kbd>+<kbd>Z</kbd></td><td><span data-i18n="Zoom to IN–OUT work area">Zoom to IN–OUT work area</span></td></tr>
303
+ <tr><td><kbd>⇧</kbd>+<kbd>Z</kbd></td><td><span data-i18n="Zoom timeline to fit">Zoom timeline to fit</span></td></tr>
304
+ <tr><td><kbd>Ctrl</kbd>+<kbd>Z</kbd> / <kbd>Ctrl</kbd>+<kbd>⇧</kbd>+<kbd>Z</kbd></td><td><span data-i18n="Undo / redo">Undo / redo</span></td></tr>
305
+ <tr><td><kbd>Ctrl</kbd><span data-i18n="+wheel">+wheel</span></td><td><span data-i18n="Zoom timeline at cursor">Zoom timeline at cursor</span></td></tr>
306
+ </table>
307
+ </div>
308
+ <div class="dialog-actions"><button class="btn primary" id="btnCloseHelp"><span data-i18n="Close">Close</span></button></div>
309
+ </div>
310
+ </div>
311
+
312
+ <div id="toast"></div>
313
+ <div id="timelineGestureHint" class="timeline-gesture-hint" role="status" hidden></div>
314
+
315
+ <script src="i18n.js"></script>
316
+ <script src="optimized-export.js"></script>
317
+ <script src="timeline.js"></script>
318
+ <script src="app.js"></script>
319
+ </body>
320
+ </html>
@@ -0,0 +1,12 @@
1
+ # FableCut 素材库
2
+
3
+ 这里是默认可复用素材。内容会实时出现在编辑器左侧面板,可以直接拖到时间线上。文件按原路径引用(`/library/...`),不会复制进项目。
4
+
5
+ | 文件夹 | 编辑器标签 | 内容 |
6
+ | --- | --- | --- |
7
+ | `sfx/` | 音效 | 呼啸、点击、上升音、冲击等(`.mp3 .wav .ogg .m4a`) |
8
+ | `elements/` | 元素 | 叠加素材:带透明通道的 PNG、漏光、纹理、短循环 |
9
+ | `svg/` | SVG | 按 CLAUDE.md 约定编写的矢量动画 |
10
+ | `fonts/` | (字体编辑器) | `.ttf .otf .woff .woff2`,自动注册,字体族名等于文件名 |
11
+
12
+ 把网上找到的可自由使用素材放进对应文件夹,已打开的编辑器会自动刷新列表。允许子文件夹,列表中也会显示。
@@ -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>
@@ -0,0 +1,13 @@
1
+ # 音效(请自行放入)
2
+
3
+ 本文件夹**不**随仓库分发。音效网站通常允许把文件用在你的视频里,但禁止把文件本身再分发到公开合集中,因此 FableCut 不附带音效。
4
+
5
+ 把 `.mp3` / `.wav` 放在这里,它们会立刻出现在编辑器的**音效**标签中(已打开的界面会实时刷新)。可以使用子文件夹。
6
+
7
+ 可用的免费音效来源:
8
+
9
+ - **freesound.org**:筛选 CC0 许可,使用限制最少
10
+ - **pixabay.com/sound-effects**:可在项目中免费使用
11
+ - **mixkit.co/free-sound-effects**:可在项目中免费使用
12
+
13
+ 实用的起步组合:一声呼啸、一声冲击或低音、一声弹出、一声快门、一声打字、一声上升音,再加几个界面点击。CLAUDE.md 里的多数剪辑配方按这些角色引用音效。
@@ -0,0 +1,18 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="240" height="360" viewBox="0 0 240 360">
2
+ <!-- FableCut animated SVG · loops · downward chevrons bouncing (swipe-up / CTA / "look here") -->
3
+ <style>
4
+ .ch { transform-box: fill-box; transform-origin: center;
5
+ animation: fall 1.6s ease-in-out infinite; }
6
+ @keyframes fall {
7
+ 0% { transform: translateY(-30px); opacity: 0; }
8
+ 40% { opacity: 1; }
9
+ 70% { transform: translateY(20px); opacity: 1; }
10
+ 100% { transform: translateY(50px); opacity: 0; }
11
+ }
12
+ </style>
13
+ <g fill="none" stroke="#fff" stroke-width="20" stroke-linecap="round" stroke-linejoin="round">
14
+ <path class="ch" style="--d:0s" d="M60 70 L120 130 L180 70"/>
15
+ <path class="ch" style="--d:0.2s" d="M60 150 L120 210 L180 150"/>
16
+ <path class="ch" style="--d:0.4s" d="M60 230 L120 290 L180 230"/>
17
+ </g>
18
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
2
+ <!-- FableCut animated SVG · one-shot (~0.7s) · hand-drawn arrow, points down-right.
3
+ Flip/rotate with clip props to point anywhere. -->
4
+ <style>
5
+ .s { stroke-dasharray: 520; stroke-dashoffset: 520; animation: draw 0.55s cubic-bezier(.3,.8,.3,1) both; }
6
+ .h { stroke-dasharray: 160; stroke-dashoffset: 160; animation: draw 0.25s ease-out both; }
7
+ @keyframes draw { to { stroke-dashoffset: 0; } }
8
+ </style>
9
+ <path class="s" style="--d:0s" d="M60 60 C 200 40, 320 140, 300 300" fill="none"
10
+ stroke="#ffd166" stroke-width="16" stroke-linecap="round"/>
11
+ <path class="h" style="--d:0.45s" d="M240 260 L 300 306 L 344 240" fill="none"
12
+ stroke="#ffd166" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
13
+ </svg>
@@ -0,0 +1,30 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="700" height="700" viewBox="0 0 700 700">
2
+ <!-- FableCut animated SVG · one-shot (~0.6s) · radial impact/speed lines. Align to a hard cut on V4. -->
3
+ <style>
4
+ .ln { stroke-dasharray: 170; stroke-dashoffset: 170;
5
+ animation: shoot 0.55s cubic-bezier(.2,.8,.3,1) both; }
6
+ @keyframes shoot {
7
+ 0% { stroke-dashoffset: 170; opacity: 1; }
8
+ 65% { stroke-dashoffset: 0; opacity: 1; }
9
+ 100% { stroke-dashoffset: -60; opacity: 0; }
10
+ }
11
+ .flash { transform-box: fill-box; transform-origin: center;
12
+ animation: fl 0.4s ease-out both; }
13
+ @keyframes fl { 0% { transform: scale(0.2); opacity: 0.9; } 100% { transform: scale(1.3); opacity: 0; } }
14
+ </style>
15
+ <circle class="flash" style="--d:0s" cx="350" cy="350" r="150" fill="#fff6d8"/>
16
+ <g stroke="#ffd166" stroke-width="16" stroke-linecap="round">
17
+ <line class="ln" style="--d:0s" x1="350.0" y1="200.0" x2="350.0" y2="40.0"/>
18
+ <line class="ln" style="--d:0.02s" x1="425.0" y1="220.1" x2="505.0" y2="81.5"/>
19
+ <line class="ln" style="--d:0.04s" x1="479.9" y1="275.0" x2="618.5" y2="195.0"/>
20
+ <line class="ln" style="--d:0.01s" x1="500.0" y1="350.0" x2="660.0" y2="350.0"/>
21
+ <line class="ln" style="--d:0.03s" x1="479.9" y1="425.0" x2="618.5" y2="505.0"/>
22
+ <line class="ln" style="--d:0.05s" x1="425.0" y1="479.9" x2="505.0" y2="618.5"/>
23
+ <line class="ln" style="--d:0s" x1="350.0" y1="500.0" x2="350.0" y2="660.0"/>
24
+ <line class="ln" style="--d:0.02s" x1="275.0" y1="479.9" x2="195.0" y2="618.5"/>
25
+ <line class="ln" style="--d:0.04s" x1="220.1" y1="425.0" x2="81.5" y2="505.0"/>
26
+ <line class="ln" style="--d:0.01s" x1="200.0" y1="350.0" x2="40.0" y2="350.0"/>
27
+ <line class="ln" style="--d:0.03s" x1="220.1" y1="275.0" x2="81.5" y2="195.0"/>
28
+ <line class="ln" style="--d:0.05s" x1="275.0" y1="220.1" x2="195.0" y2="81.5"/>
29
+ </g>
30
+ </svg>
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
2
+ <!-- FableCut animated SVG · one-shot (~1s) · success check: ring draws, badge pops, tick draws -->
3
+ <style>
4
+ .ring { fill: none; stroke: #22c55e; stroke-width: 14; stroke-linecap: round;
5
+ stroke-dasharray: 880; stroke-dashoffset: 880;
6
+ animation: draw 0.7s cubic-bezier(.3,.8,.3,1) both; }
7
+ .disc { transform-box: fill-box; transform-origin: center;
8
+ animation: pop 0.4s cubic-bezier(.34,1.56,.64,1) both; }
9
+ .tick { fill: none; stroke: #fff; stroke-width: 22; stroke-linecap: round; stroke-linejoin: round;
10
+ stroke-dasharray: 200; stroke-dashoffset: 200;
11
+ animation: draw2 0.4s cubic-bezier(.3,.8,.3,1) both; }
12
+ @keyframes draw { to { stroke-dashoffset: 0; } }
13
+ @keyframes draw2 { to { stroke-dashoffset: 0; } }
14
+ @keyframes pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
15
+ </style>
16
+ <circle class="ring" style="--d:0s" cx="200" cy="200" r="140"/>
17
+ <circle class="disc" style="--d:0.5s" cx="200" cy="200" r="120" fill="#22c55e"/>
18
+ <path class="tick" style="--d:0.7s" d="M140 205 l40 42 82 -92"/>
19
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 800 800">
2
+ <!-- FableCut animated SVG · one-shot (~1.8s) · confetti explosion from center -->
3
+ <style>
4
+ .c { transform-box: fill-box; transform-origin: center; animation: fly 1.6s cubic-bezier(.15,.7,.4,1) both; }
5
+ @keyframes fly {
6
+ 0% { transform: translate(0,0) rotate(0turn) scale(0.4); opacity: 1; }
7
+ 70% { opacity: 1; }
8
+ 100% { transform: translate(var(--tx,0px), var(--ty,-300px)) rotate(2turn) scale(1); opacity: 0; }
9
+ }
10
+ </style>
11
+ <g>
12
+ <rect class="c" style="--d:0s; --tx:-260px; --ty:-200px" x="392" y="392" width="18" height="26" fill="#ff5d73"/>
13
+ <rect class="c" style="--d:0.04s; --tx:230px; --ty:-260px" x="392" y="392" width="16" height="24" fill="#ffd166"/>
14
+ <rect class="c" style="--d:0.08s; --tx:-140px; --ty:-320px" x="392" y="392" width="14" height="22" fill="#6ee7b7"/>
15
+ <rect class="c" style="--d:0.02s; --tx:300px; --ty:-120px" x="392" y="392" width="18" height="18" fill="#7b6cff"/>
16
+ <rect class="c" style="--d:0.06s; --tx:-320px; --ty:-60px" x="392" y="392" width="16" height="20" fill="#4f8cff"/>
17
+ <circle class="c" style="--d:0.03s; --tx:120px; --ty:-340px" cx="400" cy="400" r="10" fill="#ff9f43"/>
18
+ <circle class="c" style="--d:0.07s; --tx:-60px; --ty:-380px" cx="400" cy="400" r="8" fill="#ff5d73"/>
19
+ <circle class="c" style="--d:0.05s; --tx:260px; --ty:60px" cx="400" cy="400" r="9" fill="#6ee7b7"/>
20
+ <rect class="c" style="--d:0.09s; --tx:-230px; --ty:120px" x="392" y="392" width="14" height="14" fill="#ffd166"/>
21
+ <rect class="c" style="--d:0.01s; --tx:60px; --ty:200px" x="392" y="392" width="16" height="22" fill="#7b6cff"/>
22
+ </g>
23
+ </svg>