rollberry 0.1.8 → 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.
Files changed (45) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +189 -7
  3. package/dist/capture/actions.d.ts +11 -0
  4. package/dist/capture/actions.js +81 -0
  5. package/dist/capture/browser-install.d.ts +3 -0
  6. package/dist/capture/browser-install.js +1 -1
  7. package/dist/capture/browser.d.ts +13 -0
  8. package/dist/capture/browser.js +16 -10
  9. package/dist/capture/capture.d.ts +8 -0
  10. package/dist/capture/capture.js +566 -55
  11. package/dist/capture/constants.d.ts +15 -0
  12. package/dist/capture/constants.js +7 -0
  13. package/dist/capture/ffmpeg.d.ts +41 -0
  14. package/dist/capture/ffmpeg.js +457 -36
  15. package/dist/capture/logger.d.ts +15 -0
  16. package/dist/capture/preflight.d.ts +4 -0
  17. package/dist/capture/preflight.js +8 -2
  18. package/dist/capture/progress.d.ts +7 -0
  19. package/dist/capture/progress.js +50 -0
  20. package/dist/capture/scroll-plan.d.ts +9 -0
  21. package/dist/capture/scroll-plan.js +7 -1
  22. package/dist/capture/stabilize.d.ts +7 -0
  23. package/dist/capture/stabilize.js +11 -5
  24. package/dist/capture/types.d.ts +216 -0
  25. package/dist/capture/utils.d.ts +14 -0
  26. package/dist/capture/utils.js +30 -3
  27. package/dist/cli.d.ts +2 -0
  28. package/dist/cli.js +86 -5
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.js +6 -0
  31. package/dist/options.d.ts +42 -0
  32. package/dist/options.js +229 -115
  33. package/dist/project.d.ts +27 -0
  34. package/dist/project.js +722 -0
  35. package/dist/render-plan.d.ts +103 -0
  36. package/dist/render-plan.js +144 -0
  37. package/dist/run-capture.d.ts +3 -0
  38. package/dist/run-capture.js +20 -10
  39. package/dist/run-render.d.ts +17 -0
  40. package/dist/run-render.js +434 -0
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.js +1 -0
  43. package/package.json +10 -3
  44. package/rollberry.project.sample.json +92 -0
  45. package/rollberry.project.schema.json +474 -0
@@ -0,0 +1,50 @@
1
+ export function createProgressReporter() {
2
+ const isTTY = process.stderr.isTTY === true;
3
+ let lastUpdateTime = 0;
4
+ let lastReportedMilestone = -1;
5
+ function clearLine() {
6
+ if (isTTY) {
7
+ process.stderr.write('\r\x1b[K');
8
+ }
9
+ }
10
+ return {
11
+ onPageStart(pageIndex, totalPages, url) {
12
+ clearLine();
13
+ lastReportedMilestone = -1;
14
+ const displayUrl = url.length > 60 ? `${url.slice(0, 57)}...` : url;
15
+ process.stderr.write(`Capturing page ${pageIndex + 1}/${totalPages}: ${displayUrl}\n`);
16
+ },
17
+ onFrameRendered(frameIndex, totalFrames) {
18
+ const now = Date.now();
19
+ const isLast = frameIndex + 1 === totalFrames;
20
+ if (!isLast && now - lastUpdateTime < 100) {
21
+ return;
22
+ }
23
+ lastUpdateTime = now;
24
+ const progress = (frameIndex + 1) / totalFrames;
25
+ const percent = Math.round(progress * 100);
26
+ if (isTTY) {
27
+ const barWidth = 20;
28
+ const filled = Math.round(barWidth * progress);
29
+ const bar = '#'.repeat(filled) + '-'.repeat(barWidth - filled);
30
+ process.stderr.write(`\r [${bar}] ${percent}% (${frameIndex + 1}/${totalFrames} frames)`);
31
+ if (isLast) {
32
+ process.stderr.write('\n');
33
+ }
34
+ }
35
+ else {
36
+ const milestone = Math.floor(percent / 25) * 25;
37
+ if (isLast || (milestone > lastReportedMilestone && milestone > 0)) {
38
+ lastReportedMilestone = milestone;
39
+ process.stderr.write(` Progress: ${percent}% (${frameIndex + 1}/${totalFrames} frames)\n`);
40
+ }
41
+ }
42
+ },
43
+ onPageComplete(_pageIndex) {
44
+ // Line already advanced after last frame render
45
+ },
46
+ onEncodeComplete() {
47
+ // Summary is printed by cli.ts
48
+ },
49
+ };
50
+ }
@@ -0,0 +1,9 @@
1
+ import type { MotionCurve } from './types.js';
2
+ export declare function resolveDurationSeconds(requestedDuration: number | 'auto', maxScroll: number): number;
3
+ export declare function buildScrollFrames(options: {
4
+ fps: number;
5
+ durationSeconds: number;
6
+ maxScroll: number;
7
+ motion: MotionCurve;
8
+ }): number[];
9
+ export declare function resolveTimelineDurationSeconds(distance: number): number;
@@ -1,4 +1,4 @@
1
- import { AUTO_DURATION_MAX_SECONDS, AUTO_DURATION_MIN_SECONDS, AUTO_DURATION_PIXELS_PER_SECOND, } from './constants.js';
1
+ import { AUTO_DURATION_MAX_SECONDS, AUTO_DURATION_MIN_SECONDS, AUTO_DURATION_PIXELS_PER_SECOND, MAX_TOTAL_FRAMES, TIMELINE_AUTO_DURATION_MAX_SECONDS, TIMELINE_AUTO_DURATION_MIN_SECONDS, TIMELINE_AUTO_DURATION_PIXELS_PER_SECOND, } from './constants.js';
2
2
  import { clamp } from './utils.js';
3
3
  export function resolveDurationSeconds(requestedDuration, maxScroll) {
4
4
  if (requestedDuration !== 'auto') {
@@ -8,6 +8,9 @@ export function resolveDurationSeconds(requestedDuration, maxScroll) {
8
8
  }
9
9
  export function buildScrollFrames(options) {
10
10
  const frameCount = Math.max(1, Math.ceil(options.durationSeconds * options.fps));
11
+ if (frameCount > MAX_TOTAL_FRAMES) {
12
+ throw new Error(`Frame count ${frameCount} exceeds maximum ${MAX_TOTAL_FRAMES}. Reduce --fps or --duration.`);
13
+ }
11
14
  if (frameCount === 1) {
12
15
  return [0];
13
16
  }
@@ -17,6 +20,9 @@ export function buildScrollFrames(options) {
17
20
  return Number((options.maxScroll * easedProgress).toFixed(3));
18
21
  });
19
22
  }
23
+ export function resolveTimelineDurationSeconds(distance) {
24
+ return clamp(distance / TIMELINE_AUTO_DURATION_PIXELS_PER_SECOND, TIMELINE_AUTO_DURATION_MIN_SECONDS, TIMELINE_AUTO_DURATION_MAX_SECONDS);
25
+ }
20
26
  function easeInOutSine(value) {
21
27
  return -(Math.cos(Math.PI * value) - 1) / 2;
22
28
  }
@@ -0,0 +1,7 @@
1
+ import type { Page } from 'playwright';
2
+ import type { WaitForCondition } from './types.js';
3
+ export declare function stabilizePage(options: {
4
+ page: Page;
5
+ waitFor: WaitForCondition;
6
+ hideSelectors: string[];
7
+ }): Promise<void>;
@@ -1,5 +1,5 @@
1
- import { STABILIZE_DELAY_MS } from './constants.js';
2
- import { delay, waitForAnimationFrames } from './utils.js';
1
+ import { FONT_LOADING_TIMEOUT_MS, STABILIZE_DELAY_MS } from './constants.js';
2
+ import { delay, validateHideSelector, waitForAnimationFrames, } from './utils.js';
3
3
  export async function stabilizePage(options) {
4
4
  await options.page.addStyleTag({
5
5
  content: buildStabilizingCss(options.hideSelectors),
@@ -13,6 +13,9 @@ export async function stabilizePage(options) {
13
13
  await waitForAnimationFrames(options.page);
14
14
  }
15
15
  function buildStabilizingCss(hideSelectors) {
16
+ for (const selector of hideSelectors) {
17
+ validateHideSelector(selector);
18
+ }
16
19
  const hiddenSelectorBlock = hideSelectors.length > 0
17
20
  ? `${hideSelectors.join(', ')} { display: none !important; visibility: hidden !important; }\n`
18
21
  : '';
@@ -47,10 +50,13 @@ async function waitForRequestedCondition(page, waitFor) {
47
50
  await delay(waitFor.ms);
48
51
  }
49
52
  async function waitForFonts(page) {
50
- await page.evaluate(async () => {
53
+ await page.evaluate(async (timeoutMs) => {
51
54
  if (!('fonts' in document)) {
52
55
  return;
53
56
  }
54
- await document.fonts.ready;
55
- });
57
+ await Promise.race([
58
+ document.fonts.ready,
59
+ new Promise((resolve) => setTimeout(resolve, timeoutMs)),
60
+ ]);
61
+ }, FONT_LOADING_TIMEOUT_MS);
56
62
  }
@@ -0,0 +1,216 @@
1
+ export type MotionCurve = 'ease-in-out-sine' | 'linear';
2
+ export type NonEmptyArray<T> = [T, ...T[]];
3
+ export type ScrollAlignment = 'start' | 'center' | 'end';
4
+ export type OutputFormat = 'mp4' | 'webm';
5
+ export type SubtitleFormat = 'srt' | 'webvtt';
6
+ export type SubtitleMode = 'soft' | 'burn-in';
7
+ export type H264Preset = 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow' | 'slower' | 'veryslow' | 'placebo';
8
+ export type Vp9Deadline = 'best' | 'good' | 'realtime';
9
+ export type WaitForCondition = {
10
+ kind: 'load';
11
+ } | {
12
+ kind: 'selector';
13
+ selector: string;
14
+ } | {
15
+ kind: 'delay';
16
+ ms: number;
17
+ };
18
+ export interface Viewport {
19
+ width: number;
20
+ height: number;
21
+ }
22
+ export interface CaptureOptions {
23
+ urls: NonEmptyArray<URL>;
24
+ outPath: string;
25
+ manifestPath: string;
26
+ logFilePath: string;
27
+ viewport: Viewport;
28
+ fps: number;
29
+ duration: number | 'auto';
30
+ motion: MotionCurve;
31
+ timeoutMs: number;
32
+ waitFor: WaitForCondition;
33
+ hideSelectors: string[];
34
+ pageGapSeconds: number;
35
+ debugFramesDir?: string;
36
+ force: boolean;
37
+ }
38
+ export type CaptureAction = {
39
+ kind: 'wait';
40
+ ms: number;
41
+ } | {
42
+ kind: 'click';
43
+ selector: string;
44
+ } | {
45
+ kind: 'hover';
46
+ selector: string;
47
+ } | {
48
+ kind: 'press';
49
+ key: string;
50
+ } | {
51
+ kind: 'type';
52
+ selector: string;
53
+ text: string;
54
+ clear: boolean;
55
+ } | {
56
+ kind: 'scroll-to';
57
+ selector: string;
58
+ block: ScrollAlignment;
59
+ };
60
+ export type CaptureTimelineScrollTarget = {
61
+ kind: 'bottom';
62
+ } | {
63
+ kind: 'absolute';
64
+ top: number;
65
+ } | {
66
+ kind: 'relative';
67
+ delta: number;
68
+ } | {
69
+ kind: 'selector';
70
+ selector: string;
71
+ block: ScrollAlignment;
72
+ };
73
+ export type CaptureTimelineSegment = {
74
+ kind: 'scroll';
75
+ duration: number | 'auto';
76
+ motion: MotionCurve;
77
+ target: CaptureTimelineScrollTarget;
78
+ } | {
79
+ kind: 'pause';
80
+ durationSeconds: number;
81
+ } | {
82
+ kind: 'action';
83
+ action: Exclude<CaptureAction, {
84
+ kind: 'wait';
85
+ }>;
86
+ holdAfterSeconds: number;
87
+ };
88
+ export interface CaptureScene {
89
+ name?: string;
90
+ url: URL;
91
+ duration: number | 'auto';
92
+ motion: MotionCurve;
93
+ waitFor: WaitForCondition;
94
+ hideSelectors: string[];
95
+ holdAfterSeconds: number;
96
+ actions: CaptureAction[];
97
+ timeline: CaptureTimelineSegment[];
98
+ }
99
+ export interface CaptureJob {
100
+ scenes: NonEmptyArray<CaptureScene>;
101
+ outPath: string;
102
+ format: OutputFormat;
103
+ viewport: Viewport;
104
+ fps: number;
105
+ timeoutMs: number;
106
+ audio?: CaptureAudioTrack;
107
+ subtitles?: CaptureSubtitleTrack;
108
+ transition?: CaptureTransition;
109
+ videoEncoding?: CaptureVideoEncodingSettings;
110
+ debugFramesDir?: string;
111
+ includeHoldAfterFinalScene?: boolean;
112
+ force: boolean;
113
+ }
114
+ export interface CaptureVideoEncodingSettings {
115
+ preset: H264Preset;
116
+ crf: number;
117
+ }
118
+ export interface IntermediateArtifactProfile {
119
+ format: 'mp4';
120
+ extension: '.mp4';
121
+ videoEncoding: CaptureVideoEncodingSettings;
122
+ }
123
+ export interface CaptureAudioTrack {
124
+ sourcePath: string;
125
+ volume: number;
126
+ loop: boolean;
127
+ }
128
+ export interface CaptureSubtitleTrack {
129
+ sourcePath: string;
130
+ format: SubtitleFormat;
131
+ mode: SubtitleMode;
132
+ }
133
+ export type CaptureTransition = {
134
+ kind: 'fade-in';
135
+ durationSeconds: number;
136
+ } | {
137
+ kind: 'crossfade';
138
+ durationSeconds: number;
139
+ };
140
+ export type FinalVideoEncodingSettings = {
141
+ format: 'mp4';
142
+ preset: H264Preset;
143
+ crf: number;
144
+ } | {
145
+ format: 'webm';
146
+ deadline: Vp9Deadline;
147
+ crf: number;
148
+ };
149
+ export interface ResolvedCaptureOptions extends CaptureOptions {
150
+ durationSeconds: number;
151
+ }
152
+ export interface PageMetrics {
153
+ scrollHeight: number;
154
+ viewportHeight: number;
155
+ maxScroll: number;
156
+ }
157
+ export interface PreflightResult extends PageMetrics {
158
+ truncated: boolean;
159
+ }
160
+ export interface PageCaptureResult {
161
+ name?: string;
162
+ url: string;
163
+ frameCount: number;
164
+ durationSeconds: number;
165
+ scrollHeight: number;
166
+ truncated: boolean;
167
+ }
168
+ export interface CaptureResult {
169
+ outPath: string;
170
+ frameCount: number;
171
+ durationSeconds: number;
172
+ pages: PageCaptureResult[];
173
+ truncated: boolean;
174
+ }
175
+ export interface CaptureRunResult {
176
+ capture: CaptureResult;
177
+ manifestPath: string;
178
+ logFilePath: string;
179
+ }
180
+ export interface CaptureManifest {
181
+ schemaVersion: 2;
182
+ status: 'succeeded' | 'failed' | 'cancelled';
183
+ startedAt: string;
184
+ finishedAt: string;
185
+ durationMs: number;
186
+ environment: {
187
+ nodeVersion: string;
188
+ platform: NodeJS.Platform;
189
+ arch: string;
190
+ };
191
+ options: {
192
+ urls: string[];
193
+ viewport: Viewport;
194
+ fps: number;
195
+ duration: number | 'auto';
196
+ motion: MotionCurve;
197
+ timeoutMs: number;
198
+ waitFor: WaitForCondition;
199
+ hideSelectors: string[];
200
+ pageGapSeconds: number;
201
+ };
202
+ artifacts: {
203
+ videoPath: string;
204
+ manifestPath: string;
205
+ logFilePath: string;
206
+ debugFramesDir?: string;
207
+ videoCreated: boolean;
208
+ };
209
+ result?: CaptureResult;
210
+ warnings: string[];
211
+ error?: {
212
+ name: string;
213
+ message: string;
214
+ stack?: string;
215
+ };
216
+ }
@@ -0,0 +1,14 @@
1
+ import type { Page } from 'playwright';
2
+ import type { PageMetrics } from './types.js';
3
+ export declare function clamp(value: number, min: number, max: number): number;
4
+ export declare function isLocalUrl(url: URL): boolean;
5
+ export declare function parseCaptureUrl(rawUrl: string): URL;
6
+ export declare function sanitizeUrl(url: URL): string;
7
+ export declare function formatFileSize(bytes: number): string;
8
+ export declare function validateHideSelector(selector: string): void;
9
+ export declare function fileExists(path: string): Promise<boolean>;
10
+ export declare function ensureParentDirectory(filePath: string): Promise<void>;
11
+ export declare function ensureDirectory(path: string): Promise<void>;
12
+ export declare function delay(ms: number): Promise<void>;
13
+ export declare function waitForAnimationFrames(page: Page, frameCount?: number): Promise<void>;
14
+ export declare function measurePage(page: Page): Promise<PageMetrics>;
@@ -1,4 +1,4 @@
1
- import { mkdir } from 'node:fs/promises';
1
+ import { access, mkdir } from 'node:fs/promises';
2
2
  import { dirname } from 'node:path';
3
3
  const LOCALHOST_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);
4
4
  export function clamp(value, min, max) {
@@ -13,13 +13,40 @@ export function parseCaptureUrl(rawUrl) {
13
13
  url = new URL(rawUrl);
14
14
  }
15
15
  catch {
16
- throw new Error(`無効なURLです: ${rawUrl}`);
16
+ throw new Error(`Invalid URL: ${rawUrl}\n Expected format: http://example.com or https://localhost:3000`);
17
17
  }
18
18
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
19
- throw new Error(`サポート対象外のURLです: ${rawUrl} (http/https のみ対応)`);
19
+ throw new Error(`Unsupported URL: ${rawUrl} (only http:// and https:// are supported)`);
20
20
  }
21
21
  return url;
22
22
  }
23
+ export function sanitizeUrl(url) {
24
+ const sanitized = new URL(url.toString());
25
+ sanitized.username = '';
26
+ sanitized.password = '';
27
+ return sanitized.toString();
28
+ }
29
+ export function formatFileSize(bytes) {
30
+ if (bytes < 1024)
31
+ return `${bytes} B`;
32
+ if (bytes < 1024 * 1024)
33
+ return `${(bytes / 1024).toFixed(1)} KB`;
34
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
35
+ }
36
+ export function validateHideSelector(selector) {
37
+ if (selector.includes('{') || selector.includes('}')) {
38
+ throw new Error(`Invalid CSS selector for --hide-selector: "${selector}". Selectors must not contain { or } characters.`);
39
+ }
40
+ }
41
+ export async function fileExists(path) {
42
+ try {
43
+ await access(path);
44
+ return true;
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
23
50
  export async function ensureParentDirectory(filePath) {
24
51
  await mkdir(dirname(filePath), { recursive: true });
25
52
  }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js CHANGED
@@ -1,13 +1,70 @@
1
1
  #!/usr/bin/env node
2
- import { CliError, formatUsage, parseCliArgs } from './options.js';
2
+ import { statSync } from 'node:fs';
3
+ import { basename } from 'node:path';
4
+ import { AbortError } from './capture/capture.js';
5
+ import { createProgressReporter } from './capture/progress.js';
6
+ import { formatFileSize } from './capture/utils.js';
7
+ import { CliError, formatUsage, HelpRequest, parseCommandArgs, VersionRequest, } from './options.js';
3
8
  import { runCaptureCommand } from './run-capture.js';
9
+ import { runRenderCommand } from './run-render.js';
4
10
  async function main() {
5
11
  try {
6
- const options = parseCliArgs();
7
- const result = await runCaptureCommand(options);
8
- process.stdout.write(`${result.capture.outPath}\n`);
12
+ const command = parseCommandArgs();
13
+ const controller = new AbortController();
14
+ const onSignal = () => {
15
+ controller.abort();
16
+ };
17
+ process.on('SIGINT', onSignal);
18
+ process.on('SIGTERM', onSignal);
19
+ const progress = createProgressReporter();
20
+ try {
21
+ if (command.kind === 'capture') {
22
+ const result = await runCaptureCommand(command.options, progress, controller.signal);
23
+ process.stdout.write(`${result.capture.outPath}\n`);
24
+ process.stderr.write(`${formatOutputSummary({
25
+ label: 'Capture complete',
26
+ outPath: result.capture.outPath,
27
+ durationSeconds: result.capture.durationSeconds,
28
+ frameCount: result.capture.frameCount,
29
+ fps: command.options.fps,
30
+ sceneCount: result.capture.pages.length,
31
+ manifestPath: result.manifestPath,
32
+ })}\n`);
33
+ }
34
+ else {
35
+ const result = await runRenderCommand(command.options, progress, controller.signal);
36
+ process.stdout.write(`${result.outputs.map((output) => output.capture.outPath).join('\n')}\n`);
37
+ const blocks = result.outputs.map((output) => formatOutputSummary({
38
+ label: `Render complete: ${output.name}`,
39
+ outPath: output.capture.outPath,
40
+ durationSeconds: output.capture.durationSeconds,
41
+ frameCount: output.capture.frameCount,
42
+ fps: output.fps,
43
+ sceneCount: output.capture.pages.length,
44
+ manifestPath: output.manifestPath,
45
+ }));
46
+ process.stderr.write(`\n${blocks.join('\n\n')}\n Summary: ${basename(result.summaryManifestPath)}\n`);
47
+ }
48
+ }
49
+ finally {
50
+ process.off('SIGINT', onSignal);
51
+ process.off('SIGTERM', onSignal);
52
+ }
9
53
  }
10
54
  catch (error) {
55
+ if (error instanceof HelpRequest) {
56
+ process.stdout.write(`${error.message}\n`);
57
+ return;
58
+ }
59
+ if (error instanceof VersionRequest) {
60
+ process.stdout.write(`${error.version}\n`);
61
+ return;
62
+ }
63
+ if (error instanceof AbortError) {
64
+ process.stderr.write('\nCapture cancelled.\n');
65
+ process.exitCode = 130;
66
+ return;
67
+ }
11
68
  if (error instanceof CliError) {
12
69
  process.stderr.write(`${error.message}\n`);
13
70
  if (error.showUsage) {
@@ -16,8 +73,32 @@ async function main() {
16
73
  process.exitCode = 1;
17
74
  return;
18
75
  }
19
- process.stderr.write(`${error instanceof Error ? error.message : '予期しないエラーが発生しました。'}\n`);
76
+ process.stderr.write(`${error instanceof Error ? error.message : 'An unexpected error occurred.'}\n`);
20
77
  process.exitCode = 1;
21
78
  }
22
79
  }
80
+ function formatOutputSummary(input) {
81
+ const fileName = basename(input.outPath);
82
+ let fileSizeStr = '';
83
+ try {
84
+ const stat = statSync(input.outPath);
85
+ fileSizeStr = formatFileSize(stat.size);
86
+ }
87
+ catch {
88
+ // File size unavailable
89
+ }
90
+ const lines = [
91
+ '',
92
+ `${input.label}: ${fileName}`,
93
+ ` Duration: ${input.durationSeconds.toFixed(1)}s (${input.frameCount} frames at ${input.fps.toFixed(0)}fps)`,
94
+ ];
95
+ if (fileSizeStr) {
96
+ lines.push(` File size: ${fileSizeStr}`);
97
+ }
98
+ if (input.sceneCount > 1) {
99
+ lines.push(` Scenes: ${input.sceneCount}`);
100
+ }
101
+ lines.push(` Manifest: ${basename(input.manifestPath)}`);
102
+ return lines.join('\n');
103
+ }
23
104
  await main();
@@ -0,0 +1,7 @@
1
+ export { captureSceneVideo, captureVideo } from './capture/capture.js';
2
+ export type { CaptureAction, CaptureAudioTrack, CaptureJob, CaptureOptions, CaptureResult, CaptureScene, CaptureSubtitleTrack, CaptureTimelineScrollTarget, CaptureTimelineSegment, CaptureTransition, CaptureVideoEncodingSettings, FinalVideoEncodingSettings, H264Preset, IntermediateArtifactProfile, MotionCurve, OutputFormat, PageCaptureResult, Viewport, Vp9Deadline, WaitForCondition, } from './capture/types.js';
3
+ export { DEFAULT_DURATION, DEFAULT_FPS, DEFAULT_MOTION, DEFAULT_OUT_FILE, DEFAULT_TIMEOUT_MS, DEFAULT_VIEWPORT, formatUsage, type ParsedCliCommand, parseCliArgs, parseCommandArgs, type RenderCliOptions, } from './options.js';
4
+ export { loadRenderProject, type ResolvedRenderOutput, type ResolvedRenderProject, } from './project.js';
5
+ export { buildArtifactMetrics, buildCaptureMetrics, buildComposedCaptureResult, buildProbeWarningEvent, buildSceneCaptureArtifact, buildSceneClipProbeFailureMessage, collectProbeWarnings, createRenderPlan, type PlannedComposition, type PlannedSceneCapture, type RenderArtifactMetrics, type RenderCaptureMetrics, type RenderPlan, type SceneCaptureArtifact, shouldFailOnSceneClipProbe, } from './render-plan.js';
6
+ export { runCaptureCommand } from './run-capture.js';
7
+ export { type RenderCommandResult, type RenderOutputResult, runRenderCommand, } from './run-render.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { captureSceneVideo, captureVideo } from './capture/capture.js';
2
+ export { DEFAULT_DURATION, DEFAULT_FPS, DEFAULT_MOTION, DEFAULT_OUT_FILE, DEFAULT_TIMEOUT_MS, DEFAULT_VIEWPORT, formatUsage, parseCliArgs, parseCommandArgs, } from './options.js';
3
+ export { loadRenderProject, } from './project.js';
4
+ export { buildArtifactMetrics, buildCaptureMetrics, buildComposedCaptureResult, buildProbeWarningEvent, buildSceneCaptureArtifact, buildSceneClipProbeFailureMessage, collectProbeWarnings, createRenderPlan, shouldFailOnSceneClipProbe, } from './render-plan.js';
5
+ export { runCaptureCommand } from './run-capture.js';
6
+ export { runRenderCommand, } from './run-render.js';
@@ -0,0 +1,42 @@
1
+ import type { CaptureOptions, MotionCurve, WaitForCondition } from './capture/types.js';
2
+ export declare const DEFAULT_OUT_FILE = "rollberry.mp4";
3
+ export declare const DEFAULT_VIEWPORT = "1440x900";
4
+ export declare const DEFAULT_FPS = 60;
5
+ export declare const DEFAULT_DURATION = "auto";
6
+ export declare const DEFAULT_MOTION: MotionCurve;
7
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
8
+ export interface RenderCliOptions {
9
+ projectPath: string;
10
+ outputNames: string[];
11
+ force: boolean;
12
+ }
13
+ export type ParsedCliCommand = {
14
+ kind: 'capture';
15
+ options: CaptureOptions;
16
+ } | {
17
+ kind: 'render';
18
+ options: RenderCliOptions;
19
+ };
20
+ export declare class CliError extends Error {
21
+ readonly showUsage: boolean;
22
+ constructor(message: string, showUsage?: boolean);
23
+ }
24
+ export declare class HelpRequest extends Error {
25
+ constructor(message: string);
26
+ }
27
+ export declare class VersionRequest extends Error {
28
+ readonly version = "0.1.9";
29
+ constructor();
30
+ }
31
+ export declare function parseCommandArgs(argv?: string[]): ParsedCliCommand;
32
+ export declare function parseCliArgs(argv?: string[]): CaptureOptions;
33
+ export declare function formatUsage(): string;
34
+ export declare function parseWithCliError<T>(rawValue: string, parser: (value: string) => T): T;
35
+ export declare function resolveOutPath(path: string): string;
36
+ export declare function deriveSidecarPath(path: string, suffix: string): string;
37
+ export declare function parseViewport(rawViewport: string): CaptureOptions['viewport'];
38
+ export declare function parsePositiveInt(rawValue: string): number;
39
+ export declare function parsePositiveNumber(rawValue: string): number;
40
+ export declare function parseNonNegativeNumber(rawValue: string): number;
41
+ export declare function parseMotion(rawMotion: string): MotionCurve;
42
+ export declare function parseWaitFor(rawWaitFor: string): WaitForCondition;