vueseq 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="./vueseq.svg" alt="VueSeq Logo" width="200">
2
+ <img src="./vueseq.svg" alt="VueSeq Logo" >
3
3
  </p>
4
4
 
5
5
  # VueSeq
@@ -15,22 +15,97 @@ Render Vue components with GSAP animations to video. Write standard Vue + GSAP c
15
15
  - ✅ **Simple CLI** - One command to render your video
16
16
  - ✅ **Programmatic API** - Integrate into your build pipeline
17
17
  - ✅ **Full GSAP Power** - All easing, timelines, and plugins work
18
+ - ✅ **Parallel Rendering** - Distributed capture across CPU cores (20x faster)
19
+ - ✅ **In-Browser Capture** - Zero-copy absolute performance
20
+ - ✅ **Auto-Scaling** - Automatically utilizes all available CPU cores
21
+ - ✅ **WebCodecs Encoding** - Hardware-accelerated H.264 encoding, no FFmpeg required
18
22
 
19
23
  ## Demo
20
24
 
25
+ https://github.com/user-attachments/assets/84d01c02-4b4f-4d86-879e-720a7e367967
21
26
 
27
+ _This video was rendered with VueSeq from [examples/Showcase.vue](./examples/Showcase.vue)_
22
28
 
23
- https://github.com/user-attachments/assets/84d01c02-4b4f-4d86-879e-720a7e367967
29
+ ## What Can You Build?
30
+
31
+ **Your app. As a video. Using your actual components.**
32
+
33
+ Install VueSeq into your Vue project and create stunning videos that perfectly match your brand—because they _are_ your brand. No recreating UIs in After Effects. No screen recording artifacts. Just your components, animated with GSAP, rendered to pixel-perfect video.
34
+
35
+ ### 🎬 App Showcases & Demos
36
+
37
+ Create promotional videos using your real UI components. Product tours, feature walkthroughs, "What's New in v2.0" announcements—all with your exact design system, your exact colors, your exact components.
38
+
39
+ ### 📱 Social Media Content
40
+
41
+ Generate short-form videos for Twitter, LinkedIn, Instagram. Show off a feature in 15 seconds. Your followers see your actual product, not a mockup.
42
+
43
+ ### 📚 Documentation & Tutorials
44
+
45
+ Animate how your features work. Show state transitions, user flows, component interactions. Embed videos in your docs that never go stale—regenerate them when your UI changes.
46
+
47
+ ### 📊 Data Visualizations
48
+
49
+ Animated charts, dashboards, infographics. Watch your bar charts grow, your line graphs draw, your data come alive.
50
+
51
+ ### 🎓 Educational Videos
52
+
53
+ Create animated explainers, course content, and training materials. Complex concepts become clear with step-by-step animated infographics and interactive walkthroughs.
54
+
55
+ ### 🎨 Design System Demos
56
+
57
+ Showcase your component library in motion. Let designers and developers _see_ how components animate, transition, and interact.
58
+
59
+ ---
60
+
61
+ **The idea is simple:** If you can build it in Vue, you can render it to video. One command. Deterministic output. Every time.
62
+
63
+ ## Integration Modes
64
+
65
+ ### 🔌 Add to Your Existing App
66
+
67
+ Install VueSeq into your Vue project and create videos using your existing components and design system. Import your buttons, cards, charts—anything you've already built. Your videos will match your app perfectly because they _are_ your app.
68
+
69
+ ```bash
70
+ npm install vueseq
71
+ # Create a video component that imports your existing components
72
+ npx vueseq src/videos/ProductDemo.vue -o demo.mp4
73
+ ```
74
+
75
+ ### 🤖 Programmatic / AI-Generated Videos
76
+
77
+ Use the API to generate videos programmatically. Perfect for:
78
+
79
+ - **AI pipelines**: Generate videos from LLM-created storyboards
80
+ - **Automated content**: Create personalized videos at scale
81
+ - **CI/CD integration**: Regenerate demo videos on every release
82
+
83
+ ```javascript
84
+ import { renderToMp4 } from 'vueseq'
85
+
86
+ await renderToMp4({
87
+ input: '/path/to/GeneratedVideo.vue',
88
+ output: 'output.mp4',
89
+ })
90
+ ```
24
91
 
92
+ ### 📦 Standalone Projects
25
93
 
94
+ Create a dedicated video project from scratch. Ideal for marketing teams, content creators, or anyone who wants to produce videos without an existing Vue app.
26
95
 
27
- *This video was rendered with VueSeq from [examples/HelloWorld.vue](./examples/HelloWorld.vue)*
96
+ ```bash
97
+ mkdir my-video && cd my-video
98
+ npm init -y && npm install vueseq
99
+ # Create your video component and render
100
+ npx vueseq Video.vue -o video.mp4
101
+ ```
28
102
 
29
103
  ## Philosophy
30
104
 
31
- VueSeq is intentionally minimal. We bundle only the essentials: **Vue**, **GSAP**, **Playwright**, and **Vite**.
105
+ VueSeq is intentionally minimal. We bundle only the essentials: **Vue**, **GSAP**, **Playwright**, **Vite**, and **Mediabunny** (for WebCodecs-based encoding).
32
106
 
33
107
  We don't include CSS frameworks (Tailwind, UnoCSS, etc.) because:
108
+
34
109
  - Every developer has their preferred styling approach
35
110
  - Your project likely already has styling configured
36
111
  - Video components are self-contained—vanilla CSS works great
@@ -47,10 +122,7 @@ npm install vueseq
47
122
  ### Requirements
48
123
 
49
124
  - Node.js 18+
50
- - FFmpeg (for video encoding)
51
- - macOS: `brew install ffmpeg`
52
- - Ubuntu/Debian: `sudo apt install ffmpeg`
53
- - Windows: Download from [ffmpeg.org](https://ffmpeg.org/download.html)
125
+ - A modern Chromium browser (Playwright will download this automatically)
54
126
 
55
127
  ## Quick Start
56
128
 
@@ -69,25 +141,29 @@ const textRef = ref(null)
69
141
 
70
142
  onMounted(() => {
71
143
  const tl = gsap.timeline()
72
-
73
- tl.from(boxRef.value, {
74
- x: -200,
75
- opacity: 0,
144
+
145
+ tl.from(boxRef.value, {
146
+ x: -200,
147
+ opacity: 0,
76
148
  duration: 1,
77
- ease: 'power2.out'
149
+ ease: 'power2.out',
78
150
  })
79
-
80
- tl.from(textRef.value, {
81
- y: 50,
82
- opacity: 0,
83
- duration: 0.8,
84
- ease: 'back.out'
85
- }, '-=0.3')
86
-
151
+
152
+ tl.from(
153
+ textRef.value,
154
+ {
155
+ y: 50,
156
+ opacity: 0,
157
+ duration: 0.8,
158
+ ease: 'back.out',
159
+ },
160
+ '-=0.3',
161
+ )
162
+
87
163
  tl.to(boxRef.value, {
88
164
  rotation: 360,
89
165
  duration: 2,
90
- ease: 'elastic.out(1, 0.3)'
166
+ ease: 'elastic.out(1, 0.3)',
91
167
  })
92
168
  })
93
169
  </script>
@@ -133,10 +209,19 @@ span {
133
209
  ### 2. Render to Video
134
210
 
135
211
  ```bash
136
- npx vueseq MyVideo.vue -d 4 -o hello.mp4
212
+ npx vueseq examples/HelloWorld.vue -o examples/hello.mp4
213
+ ```
214
+
215
+ ### 3. Parallel Rendering (Recommended for Speed)
216
+
217
+ For complex animations or long videos, use parallel rendering to utilize all CPU cores:
218
+
219
+ ```bash
220
+ npx vueseq examples/Showcase.vue --parallel
137
221
  ```
222
+ *Automatically detects CPU cores and scales accordingly (e.g., 60s for a 20min render).*
138
223
 
139
- That's it! Your video will be rendered at 1920x1080, 30fps.
224
+ That's it! Duration is auto-detected from your timeline. Your video will be rendered at 1920x1080, 30fps.
140
225
 
141
226
  ## CLI Options
142
227
 
@@ -145,57 +230,67 @@ vueseq <Video.vue> [options]
145
230
 
146
231
  Options:
147
232
  -o, --output Output file (default: ./output.mp4)
148
- -d, --duration Duration in seconds (required)
233
+ -d, --duration Duration in seconds (auto-detected from timeline if not specified)
149
234
  -f, --fps Frames per second (default: 30)
150
235
  -w, --width Video width in pixels (default: 1920)
151
236
  -H, --height Video height in pixels (default: 1080)
237
+ --parallel Use parallel rendering (multi-process) [Recommended]
238
+ --workers Number of workers (default: auto-detected, use with --parallel)
239
+ --optimized Use optimized single-page in-browser capture
240
+ --gpu-backend Force GPU backend: vulkan, metal, d3d11, software (default: auto)
241
+ --monitor-memory Log memory usage
242
+ -v, --version Show version number
152
243
  --help Show help message
153
244
  ```
154
245
 
155
246
  ### Examples
156
247
 
157
248
  ```bash
158
- # Basic render
159
- vueseq Intro.vue -d 5 -o intro.mp4
249
+ # Simple example (auto-detects duration)
250
+ npx vueseq examples/HelloWorld.vue -o examples/hello.mp4
251
+
252
+ # Multi-scene showcase
253
+ npx vueseq examples/Showcase.vue -o examples/showcase.mp4
254
+
255
+ # Override duration (partial render)
256
+ npx vueseq examples/Showcase.vue -d 10 -o examples/partial.mp4
160
257
 
161
258
  # 4K at 60fps
162
- vueseq Intro.vue -d 10 -f 60 -w 3840 -H 2160 -o intro-4k.mp4
259
+ npx vueseq examples/HelloWorld.vue -f 60 -w 3840 -H 2160 -o examples/hello-4k.mp4
260
+
261
+ # Max Performance (Parallel + Auto-Scaling)
262
+ npx vueseq examples/Showcase.vue --parallel -o examples/showcase.mp4
263
+
264
+ # Dedicated Optimized Single-Page (Low Specs)
265
+ npx vueseq examples/Showcase.vue --optimized -o examples/showcase.mp4
163
266
 
164
- # Square for social media
165
- vueseq Story.vue -d 15 -w 1080 -H 1080 -o story.mp4
267
+ # Force Vulkan Backend
268
+ npx vueseq examples/Showcase.vue --gpu-backend vulkan --parallel
269
+
270
+ # 4K at 60fps
271
+ npx vueseq examples/HelloWorld.vue -f 60 -w 3840 -H 2160 -o examples/hello-4k.mp4
166
272
  ```
167
273
 
168
274
  ## Programmatic API
169
275
 
170
276
  ```javascript
171
- import { renderToMp4, renderFrames, encodeVideo } from 'vueseq'
277
+ import { renderToMp4, isWebCodecsSupported } from 'vueseq'
172
278
 
173
- // Render directly to MP4
279
+ // Check if WebCodecs is supported
280
+ const supported = await isWebCodecsSupported()
281
+
282
+ // Render directly to MP4 (WebCodecs encoding)
174
283
  await renderToMp4({
175
284
  input: '/path/to/MyVideo.vue',
176
- duration: 5,
285
+ duration: 5, // Optional: auto-detected from timeline if not provided
177
286
  fps: 30,
178
287
  width: 1920,
179
288
  height: 1080,
180
289
  output: './output.mp4',
181
290
  onProgress: ({ frame, total, percent }) => {
182
291
  console.log(`Rendering: ${percent}%`)
183
- }
292
+ },
184
293
  })
185
-
186
- // Or render frames separately for custom processing
187
- const { framesDir, totalFrames, cleanup } = await renderFrames({
188
- input: '/path/to/MyVideo.vue',
189
- duration: 5,
190
- fps: 30,
191
- width: 1920,
192
- height: 1080
193
- })
194
-
195
- // Process frames here...
196
-
197
- await encodeVideo({ framesDir, output: './output.mp4', fps: 30 })
198
- await cleanup()
199
294
  ```
200
295
 
201
296
  ## How It Works
@@ -206,9 +301,9 @@ VueSeq uses GSAP's deterministic timeline control:
206
301
  2. **Playwright** opens it in headless Chrome
207
302
  3. For each frame, GSAP's `globalTimeline.seek(time)` jumps to the exact moment
208
303
  4. **Screenshot** captures the frame
209
- 5. **FFmpeg** encodes all frames to video
304
+ 5. **WebCodecs API** (via Mediabunny) encodes frames to video with hardware acceleration
210
305
 
211
- This is deterministic because `seek()` applies all GSAP values synchronously—given the same time, you get the exact same DOM state every time.
306
+ This is deterministic because `seek()` applies all GSAP values synchronously—given the same time, you get the exact same DOM state every time. The WebCodecs API provides hardware-accelerated H.264 encoding without requiring FFmpeg.
212
307
 
213
308
  ## Multi-Scene Videos
214
309
 
@@ -217,16 +312,16 @@ For longer videos with multiple scenes, use nested GSAP timelines:
217
312
  ```javascript
218
313
  onMounted(() => {
219
314
  const master = gsap.timeline()
220
-
315
+
221
316
  master.add(createIntro())
222
- master.add(createMainContent(), '-=0.5') // Overlap for smooth transition
317
+ master.add(createMainContent(), '-=0.5') // Overlap for smooth transition
223
318
  master.add(createOutro())
224
319
  })
225
320
 
226
321
  function createIntro() {
227
322
  const tl = gsap.timeline()
228
323
  tl.from('.title', { opacity: 0, duration: 1 })
229
- tl.to({}, { duration: 2 }) // Hold
324
+ tl.to({}, { duration: 2 }) // Hold
230
325
  tl.to('.scene-intro', { opacity: 0, duration: 0.5 })
231
326
  return tl
232
327
  }
package/bin/cli.js CHANGED
@@ -2,90 +2,123 @@
2
2
 
3
3
  /**
4
4
  * VueSeq CLI
5
- *
5
+ *
6
6
  * Render Vue + GSAP components to video.
7
- *
7
+ *
8
8
  * Usage:
9
9
  * vueseq <Video.vue> [options]
10
- *
10
+ *
11
11
  * Example:
12
12
  * vueseq MyAnimation.vue -d 5 -o my-video.mp4
13
13
  */
14
14
 
15
15
  import { parseArgs } from 'node:util'
16
16
  import { resolve, extname } from 'node:path'
17
- import { existsSync } from 'node:fs'
17
+ import { existsSync, readFileSync } from 'node:fs'
18
18
 
19
19
  // Show help text
20
20
  function showHelp() {
21
- console.log(`
21
+ console.log(`
22
22
  VueSeq - Render Vue + GSAP components to video
23
23
 
24
24
  USAGE:
25
25
  vueseq <Video.vue> [options]
26
26
 
27
27
  OPTIONS:
28
- -o, --output Output file (default: ./output.mp4)
29
- -d, --duration Duration in seconds (required)
30
- -f, --fps Frames per second (default: 30)
31
- -w, --width Video width in pixels (default: 1920)
32
- -H, --height Video height in pixels (default: 1080)
33
- --help Show this help message
28
+ -o, --output Output file (default: ./output.mp4)
29
+ -d, --duration Duration in seconds (auto-detected if not specified)
30
+ -f, --fps Frames per second (default: 30)
31
+ -w, --width Video width in pixels (default: 1920)
32
+ -H, --height Video height in pixels (default: 1080)
33
+ --gpu-backend GPU backend: auto, vulkan, egl, metal, d3d11, software (default: auto)
34
+ --optimized Use optimized in-browser capture (eliminates PNG overhead)
35
+ --parallel Use parallel frame capture with multiple browser pages
36
+ --workers Number of parallel workers (default: auto-detected cores)
37
+ --monitor-memory Log memory usage during rendering
38
+ --benchmark Compare original vs optimized render methods
39
+ -v, --version Show version number
40
+ --help Show this help message
34
41
 
35
42
  EXAMPLE:
36
- vueseq MyAnimation.vue -d 5 -o my-video.mp4
37
- vueseq Intro.vue -d 10 -f 60 -w 3840 -H 2160 -o intro-4k.mp4
43
+ npx vueseq examples/HelloWorld.vue -o examples/hello.mp4
44
+ npx vueseq examples/HelloWorld.vue --optimized -o examples/hello.mp4
45
+ npx vueseq examples/Showcase.vue --parallel --workers 4 --monitor-memory
46
+
47
+ GPU DIAGNOSTICS:
48
+ node test-gpu.js # Run full GPU diagnostics
49
+ node test-gpu.js --benchmark # Include render benchmarks
38
50
  `)
39
51
  }
40
52
 
41
53
  // Parse command line arguments
42
54
  const { values, positionals } = parseArgs({
43
- allowPositionals: true,
44
- options: {
45
- output: { type: 'string', short: 'o', default: './output.mp4' },
46
- duration: { type: 'string', short: 'd' },
47
- fps: { type: 'string', short: 'f', default: '30' },
48
- width: { type: 'string', short: 'w', default: '1920' },
49
- height: { type: 'string', short: 'H', default: '1080' },
50
- help: { type: 'boolean' }
51
- }
55
+ allowPositionals: true,
56
+ options: {
57
+ output: { type: 'string', short: 'o', default: './output.mp4' },
58
+ duration: { type: 'string', short: 'd' },
59
+ fps: { type: 'string', short: 'f', default: '30' },
60
+ width: { type: 'string', short: 'w', default: '1920' },
61
+ height: { type: 'string', short: 'H', default: '1080' },
62
+ 'gpu-backend': { type: 'string', default: 'auto' },
63
+ optimized: { type: 'boolean', default: false },
64
+ parallel: { type: 'boolean', default: false },
65
+ workers: { type: 'string' },
66
+ 'monitor-memory': { type: 'boolean', default: false },
67
+ benchmark: { type: 'boolean', default: false },
68
+ version: { type: 'boolean', short: 'v' },
69
+ help: { type: 'boolean' },
70
+ },
52
71
  })
53
72
 
73
+ // Show version if requested
74
+ if (values.version) {
75
+ try {
76
+ const pkgPath = new URL('../package.json', import.meta.url)
77
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
78
+ console.log(`vueseq v${pkg.version}`)
79
+ } catch (e) {
80
+ console.error('Error reading version:', e.message)
81
+ }
82
+ process.exit(0)
83
+ }
84
+
54
85
  // Show help if requested
55
86
  if (values.help) {
56
- showHelp()
57
- process.exit(0)
87
+ showHelp()
88
+ process.exit(0)
58
89
  }
59
90
 
60
91
  // Validate input file
61
92
  const input = positionals[0]
62
93
  if (!input) {
63
- console.error('Error: Please specify a .vue file\n')
64
- showHelp()
65
- process.exit(1)
94
+ console.error('Error: Please specify a .vue file\n')
95
+ showHelp()
96
+ process.exit(1)
66
97
  }
67
98
 
68
99
  const inputPath = resolve(input)
69
100
  if (!existsSync(inputPath)) {
70
- console.error(`Error: File not found: ${inputPath}`)
71
- process.exit(1)
101
+ console.error(`Error: File not found: ${inputPath}`)
102
+ process.exit(1)
72
103
  }
73
104
 
74
105
  if (extname(inputPath) !== '.vue') {
75
- console.error('Error: Input must be a .vue file')
76
- process.exit(1)
106
+ console.error('Error: Input must be a .vue file')
107
+ process.exit(1)
77
108
  }
78
109
 
79
- // Validate duration
80
- if (!values.duration) {
81
- console.error('Error: Duration is required. Use -d or --duration to specify duration in seconds.')
82
- process.exit(1)
83
- }
110
+ // Parse duration if provided
111
+ let duration = null
112
+ let durationAuto = false
84
113
 
85
- const duration = parseFloat(values.duration)
86
- if (isNaN(duration) || duration <= 0) {
114
+ if (values.duration) {
115
+ duration = parseFloat(values.duration)
116
+ if (isNaN(duration) || duration <= 0) {
87
117
  console.error('Error: Duration must be a positive number')
88
118
  process.exit(1)
119
+ }
120
+ } else {
121
+ durationAuto = true
89
122
  }
90
123
 
91
124
  // Parse numeric options
@@ -94,47 +127,134 @@ const width = parseInt(values.width)
94
127
  const height = parseInt(values.height)
95
128
 
96
129
  if (isNaN(fps) || fps <= 0) {
97
- console.error('Error: FPS must be a positive number')
98
- process.exit(1)
130
+ console.error('Error: FPS must be a positive number')
131
+ process.exit(1)
99
132
  }
100
133
 
101
134
  if (isNaN(width) || width <= 0 || isNaN(height) || height <= 0) {
102
- console.error('Error: Width and height must be positive numbers')
103
- process.exit(1)
135
+ console.error('Error: Width and height must be positive numbers')
136
+ process.exit(1)
104
137
  }
105
138
 
106
139
  // Import renderer and start rendering
107
- console.log(`\nVueSeq - Rendering ${input}`)
108
- console.log(` Duration: ${duration}s at ${fps}fps (${Math.ceil(duration * fps)} frames)`)
109
- console.log(` Resolution: ${width}x${height}`)
110
- console.log(` Output: ${values.output}\n`)
111
-
112
140
  try {
113
- const { renderToMp4 } = await import('../src/renderer/encode.js')
114
-
115
- const startTime = Date.now()
116
- let lastLoggedPercent = -1
117
-
118
- await renderToMp4({
119
- input: inputPath,
120
- duration,
121
- fps,
122
- width,
123
- height,
124
- output: values.output,
125
- onProgress: ({ frame, total, percent }) => {
126
- // Only log every 5% to reduce noise
127
- if (percent % 5 === 0 && percent !== lastLoggedPercent) {
128
- lastLoggedPercent = percent
129
- process.stdout.write(`\rRendering: ${percent}% (${frame + 1}/${total} frames)`)
130
- }
131
- }
141
+ const { renderToMp4, renderToMp4Optimized, benchmarkRenderMethods } =
142
+ await import('../src/renderer/encode.js')
143
+ const { renderToMp4Parallel } = await import(
144
+ '../src/renderer/encode-parallel.js'
145
+ )
146
+ const { getTimelineDuration } = await import('../src/renderer/render.js')
147
+ const { detectBestGPUConfig, clearGPUCache } = await import(
148
+ '../src/renderer/gpu.js'
149
+ )
150
+
151
+ // Get GPU backend preference
152
+ const gpuBackend = values['gpu-backend'] || 'auto'
153
+
154
+ // Clear cache if specific backend requested (force re-detection)
155
+ if (gpuBackend !== 'auto') {
156
+ await clearGPUCache()
157
+ }
158
+
159
+ // Check GPU acceleration status
160
+ const gpuConfig = await detectBestGPUConfig({
161
+ preferBackend: gpuBackend !== 'auto' ? gpuBackend : undefined,
162
+ })
163
+
164
+ const gpuIcon = gpuConfig.isHardwareAccelerated ? '✓' : '○'
165
+ const gpuMode = gpuConfig.isHardwareAccelerated ? 'Hardware' : 'Software'
166
+ console.log(`\nGPU: ${gpuIcon} ${gpuMode}(${gpuConfig.label})`)
167
+ console.log(` Renderer: ${gpuConfig.renderer}`)
168
+
169
+ // Run benchmark mode if requested
170
+ if (values.benchmark) {
171
+ console.log('\n📊 Running render benchmark...')
172
+ await benchmarkRenderMethods({
173
+ input: inputPath,
174
+ duration: duration || 2,
175
+ fps,
176
+ width,
177
+ height,
132
178
  })
179
+ process.exit(0)
180
+ }
181
+
182
+ // Auto-detect duration if not provided
183
+ if (durationAuto) {
184
+ console.log(`\nVueSeq - Detecting timeline duration...`)
185
+ duration = await getTimelineDuration({ input: inputPath, width, height })
186
+ if (!duration || duration <= 0) {
187
+ console.error(
188
+ 'Error: Could not auto-detect duration. Use -d to specify manually.',
189
+ )
190
+ process.exit(1)
191
+ }
192
+ console.log(` Auto - detected: ${duration.toFixed(2)}s`)
193
+ }
194
+
195
+ // Select renderer based on flags
196
+ const useParallel = values.parallel
197
+ const useOptimized = values.optimized
198
+ const numWorkers = values.workers ? parseInt(values.workers, 10) : undefined
199
+ const monitorMemory = values['monitor-memory']
200
+
201
+ let renderMethod
202
+ if (useParallel) {
203
+ renderMethod = `Parallel(${numWorkers || 'Auto'} workers)`
204
+ } else if (useOptimized) {
205
+ renderMethod = 'Optimized (in-browser capture)'
206
+ } else {
207
+ renderMethod = 'Standard (PNG-based)'
208
+ }
133
209
 
134
- const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
135
- console.log(`\n\n✓ Video saved to ${values.output} (${elapsed}s)`)
210
+ console.log(`\nVueSeq - Rendering ${input} `)
211
+ console.log(` Method: ${renderMethod} `)
212
+ console.log(
213
+ ` Duration: ${duration}s at ${fps} fps(${Math.ceil(duration * fps)} frames)${durationAuto ? ' (auto)' : ''} `,
214
+ )
215
+ console.log(` Resolution: ${width}x${height} `)
216
+ console.log(` Output: ${values.output} \n`)
136
217
 
218
+ const startTime = Date.now()
219
+ let lastLoggedPercent = -1
220
+
221
+ // Select render function
222
+ let renderFn
223
+ if (useParallel) {
224
+ renderFn = renderToMp4Parallel
225
+ } else if (useOptimized) {
226
+ renderFn = renderToMp4Optimized
227
+ } else {
228
+ renderFn = renderToMp4
229
+ }
230
+
231
+ await renderFn({
232
+ input: inputPath,
233
+ duration,
234
+ fps,
235
+ width,
236
+ height,
237
+ output: values.output,
238
+ workers: numWorkers,
239
+ monitorMemory,
240
+ onProgress: ({ frame, total, percent, workerId }) => {
241
+ // Only log every 5% to reduce noise
242
+ if (percent % 5 === 0 && percent !== lastLoggedPercent) {
243
+ lastLoggedPercent = percent
244
+ const workerInfo = workerId !== undefined ? ` [W${workerId}]` : ''
245
+ process.stdout.write(
246
+ `\rRendering: ${percent}% (${frame + 1}/${total} frames)${workerInfo} `,
247
+ )
248
+ }
249
+ },
250
+ })
251
+
252
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
253
+ console.log(`\n\n✓ Video saved to ${values.output} (${elapsed}s)`)
137
254
  } catch (error) {
138
- console.error(`\nError: ${error.message}`)
139
- process.exit(1)
255
+ console.error(`\nError: ${error.message} `)
256
+ process.exit(1)
140
257
  }
258
+
259
+
260
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueseq",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A minimal, deterministic video renderer for Vue 3 + GSAP",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,10 +38,15 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "gsap": "^3.12.0",
41
- "playwright": "^1.40.0"
41
+ "html2canvas": "^1.4.1",
42
+ "mediabunny": "^1.31.0",
43
+ "playwright": "^1.58.0"
42
44
  },
43
45
  "devDependencies": {
46
+ "@semantic-release/changelog": "^6.0.3",
47
+ "@semantic-release/git": "^10.0.1",
44
48
  "@vitejs/plugin-vue": "^5.0.0",
49
+ "semantic-release": "^25.0.2",
45
50
  "vite": "^5.0.0",
46
51
  "vue": "^3.4.0"
47
52
  },
@@ -51,4 +56,4 @@
51
56
  "engines": {
52
57
  "node": ">=18.0.0"
53
58
  }
54
- }
59
+ }
package/src/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * VueSeq - Public API
3
- *
3
+ *
4
4
  * A minimal, deterministic video renderer for Vue 3 + GSAP.
5
+ * Uses WebCodecs API for hardware-accelerated video encoding.
5
6
  */
6
7
 
7
8
  export { renderFrames } from './renderer/render.js'
8
- export { encodeVideo, renderToMp4 } from './renderer/encode.js'
9
+ export { renderToMp4, isWebCodecsSupported } from './renderer/encode.js'
9
10
  export { createVideoServer } from './bundler/vite.js'