shellfie-cli 2.0.0 → 2.0.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.
- package/README.md +1 -1
- package/dist/animator.d.ts +8 -0
- package/dist/animator.d.ts.map +1 -0
- package/dist/animator.js +210 -0
- package/dist/animator.js.map +1 -0
- package/dist/cli.js +16 -1
- package/dist/cli.js.map +1 -1
- package/dist/dvd-executor-v2.d.ts +76 -0
- package/dist/dvd-executor-v2.d.ts.map +1 -0
- package/dist/dvd-executor-v2.js +258 -0
- package/dist/dvd-executor-v2.js.map +1 -0
- package/dist/dvd-executor.d.ts +144 -0
- package/dist/dvd-executor.d.ts.map +1 -0
- package/dist/dvd-executor.js +669 -0
- package/dist/dvd-executor.js.map +1 -0
- package/dist/dvd-parser.d.ts +96 -0
- package/dist/dvd-parser.d.ts.map +1 -0
- package/dist/dvd-parser.js +279 -0
- package/dist/dvd-parser.js.map +1 -0
- package/dist/dvd.d.ts +31 -0
- package/dist/dvd.d.ts.map +1 -0
- package/dist/dvd.js +154 -0
- package/dist/dvd.js.map +1 -0
- package/dist/frame-animator.d.ts +21 -0
- package/dist/frame-animator.d.ts.map +1 -0
- package/dist/frame-animator.js +254 -0
- package/dist/frame-animator.js.map +1 -0
- package/dist/frame-capture.d.ts +16 -0
- package/dist/frame-capture.d.ts.map +1 -0
- package/dist/frame-capture.js +162 -0
- package/dist/frame-capture.js.map +1 -0
- package/dist/svg-animator-v2.d.ts +23 -0
- package/dist/svg-animator-v2.d.ts.map +1 -0
- package/dist/svg-animator-v2.js +134 -0
- package/dist/svg-animator-v2.js.map +1 -0
- package/dist/svg-animator.d.ts +23 -0
- package/dist/svg-animator.d.ts.map +1 -0
- package/dist/svg-animator.js +134 -0
- package/dist/svg-animator.js.map +1 -0
- package/dist/terminal-renderer.d.ts +34 -0
- package/dist/terminal-renderer.d.ts.map +1 -0
- package/dist/terminal-renderer.js +229 -0
- package/dist/terminal-renderer.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Frame } from './frame-capture';
|
|
2
|
+
import { type shellfieOptions } from 'shellfie';
|
|
3
|
+
export interface FrameAnimationOptions {
|
|
4
|
+
fps: number;
|
|
5
|
+
loop: boolean;
|
|
6
|
+
maxDuration: number;
|
|
7
|
+
maxSizeKB: number;
|
|
8
|
+
shellfieOptions: shellfieOptions;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generates an animated SVG from multiple frames.
|
|
12
|
+
* Uses SMIL visibility toggling for efficient frame switching.
|
|
13
|
+
* Aggressively deduplicates content at multiple levels:
|
|
14
|
+
* 1. Consecutive identical frames are merged
|
|
15
|
+
* 2. Individual text lines are stored once and referenced via <use>
|
|
16
|
+
* 3. Glyph patterns are shared across frames
|
|
17
|
+
*
|
|
18
|
+
* Enforces size and duration limits by progressively reducing frames.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateFrameAnimatedSvg(frames: Frame[], options: FrameAnimationOptions): Promise<string>;
|
|
21
|
+
//# sourceMappingURL=frame-animator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-animator.d.ts","sourceRoot":"","sources":["../src/frame-animator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAE/D,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,eAAe,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateFrameAnimatedSvg = generateFrameAnimatedSvg;
|
|
4
|
+
const shellfie_1 = require("shellfie");
|
|
5
|
+
/**
|
|
6
|
+
* Generates an animated SVG from multiple frames.
|
|
7
|
+
* Uses SMIL visibility toggling for efficient frame switching.
|
|
8
|
+
* Aggressively deduplicates content at multiple levels:
|
|
9
|
+
* 1. Consecutive identical frames are merged
|
|
10
|
+
* 2. Individual text lines are stored once and referenced via <use>
|
|
11
|
+
* 3. Glyph patterns are shared across frames
|
|
12
|
+
*
|
|
13
|
+
* Enforces size and duration limits by progressively reducing frames.
|
|
14
|
+
*/
|
|
15
|
+
async function generateFrameAnimatedSvg(frames, options) {
|
|
16
|
+
if (frames.length === 0) {
|
|
17
|
+
throw new Error('No frames to animate');
|
|
18
|
+
}
|
|
19
|
+
if (frames.length === 1) {
|
|
20
|
+
return (0, shellfie_1.shellfieAsync)(frames[0].content, options.shellfieOptions);
|
|
21
|
+
}
|
|
22
|
+
// Apply duration limit first - cap frames based on max duration
|
|
23
|
+
const maxFramesByDuration = Math.floor(options.maxDuration * options.fps);
|
|
24
|
+
let cappedFrames = frames.slice(0, maxFramesByDuration);
|
|
25
|
+
// Try generating with current frame count, reduce if size exceeds limit
|
|
26
|
+
let result = await generateWithFrames(cappedFrames, options);
|
|
27
|
+
// If size exceeds limit, progressively reduce frames
|
|
28
|
+
const maxSizeBytes = options.maxSizeKB * 1024;
|
|
29
|
+
let attempts = 0;
|
|
30
|
+
const maxAttempts = 5;
|
|
31
|
+
while (result.length > maxSizeBytes && cappedFrames.length > 2 && attempts < maxAttempts) {
|
|
32
|
+
// Reduce frame count by sampling (keep every Nth frame)
|
|
33
|
+
const reductionFactor = Math.ceil(cappedFrames.length / Math.max(2, cappedFrames.length * 0.6));
|
|
34
|
+
cappedFrames = sampleFrames(cappedFrames, reductionFactor);
|
|
35
|
+
result = await generateWithFrames(cappedFrames, options);
|
|
36
|
+
attempts++;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Samples frames by keeping every Nth frame, always keeping first and last.
|
|
42
|
+
*/
|
|
43
|
+
function sampleFrames(frames, step) {
|
|
44
|
+
if (frames.length <= 2 || step <= 1)
|
|
45
|
+
return frames;
|
|
46
|
+
const sampled = [frames[0]];
|
|
47
|
+
for (let i = step; i < frames.length - 1; i += step) {
|
|
48
|
+
sampled.push(frames[i]);
|
|
49
|
+
}
|
|
50
|
+
sampled.push(frames[frames.length - 1]);
|
|
51
|
+
// Re-index the frames
|
|
52
|
+
return sampled.map((frame, index) => ({
|
|
53
|
+
...frame,
|
|
54
|
+
index,
|
|
55
|
+
timestamp: index * (1000 / 10), // Approximate timing
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Internal function to generate animated SVG from frames.
|
|
60
|
+
*/
|
|
61
|
+
async function generateWithFrames(frames, options) {
|
|
62
|
+
// Deduplicate identical consecutive frames
|
|
63
|
+
const deduplicatedFrames = deduplicateConsecutiveFrames(frames);
|
|
64
|
+
// Generate SVG only for unique frames
|
|
65
|
+
const uniqueFrameSvgs = await Promise.all(deduplicatedFrames.uniqueFrames.map(frame => (0, shellfie_1.shellfieAsync)(frame.content, options.shellfieOptions)));
|
|
66
|
+
// Extract and deduplicate content at line level
|
|
67
|
+
const { lineLibrary, glyphLibrary, frameLineRefs, frameGlyphRefs } = buildContentLibrary(uniqueFrameSvgs);
|
|
68
|
+
// Build animated SVG with shared content library
|
|
69
|
+
const baseSvg = uniqueFrameSvgs[0];
|
|
70
|
+
return injectFrameAnimationsWithLibrary(baseSvg, lineLibrary, glyphLibrary, frameLineRefs, frameGlyphRefs, deduplicatedFrames.frameDurations, options.fps, options.loop);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Builds a shared library of unique lines and glyphs across all frames.
|
|
74
|
+
* Returns references for each frame to reconstruct content.
|
|
75
|
+
*/
|
|
76
|
+
function buildContentLibrary(frameSvgs) {
|
|
77
|
+
const lineLibrary = new Map();
|
|
78
|
+
const glyphLibrary = new Map();
|
|
79
|
+
const frameLineRefs = [];
|
|
80
|
+
const frameGlyphRefs = [];
|
|
81
|
+
let lineCounter = 0;
|
|
82
|
+
let glyphCounter = 0;
|
|
83
|
+
for (const svg of frameSvgs) {
|
|
84
|
+
const textContent = extractTextContent(svg);
|
|
85
|
+
const glyphContent = extractGlyphsContent(svg);
|
|
86
|
+
// Parse individual text elements (lines)
|
|
87
|
+
const lineRefs = [];
|
|
88
|
+
const textElements = textContent.match(/<text[^>]*>[\s\S]*?<\/text>/g) || [];
|
|
89
|
+
for (const textEl of textElements) {
|
|
90
|
+
if (!lineLibrary.has(textEl)) {
|
|
91
|
+
const lineId = `L${lineCounter++}`;
|
|
92
|
+
lineLibrary.set(textEl, lineId);
|
|
93
|
+
}
|
|
94
|
+
lineRefs.push(lineLibrary.get(textEl));
|
|
95
|
+
}
|
|
96
|
+
frameLineRefs.push(lineRefs);
|
|
97
|
+
// Parse individual glyph elements
|
|
98
|
+
const glyphRefs = [];
|
|
99
|
+
// Match rect, path, or other glyph elements
|
|
100
|
+
const glyphElements = glyphContent.match(/<(?:rect|path|line|polygon)[^>]*\/?>/g) || [];
|
|
101
|
+
for (const glyphEl of glyphElements) {
|
|
102
|
+
if (!glyphLibrary.has(glyphEl)) {
|
|
103
|
+
const glyphId = `G${glyphCounter++}`;
|
|
104
|
+
glyphLibrary.set(glyphEl, glyphId);
|
|
105
|
+
}
|
|
106
|
+
glyphRefs.push(glyphLibrary.get(glyphEl));
|
|
107
|
+
}
|
|
108
|
+
frameGlyphRefs.push(glyphRefs);
|
|
109
|
+
}
|
|
110
|
+
return { lineLibrary, glyphLibrary, frameLineRefs, frameGlyphRefs };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Deduplicates identical consecutive frames.
|
|
114
|
+
* Returns unique frames and their durations.
|
|
115
|
+
*/
|
|
116
|
+
function deduplicateConsecutiveFrames(frames) {
|
|
117
|
+
if (frames.length === 0) {
|
|
118
|
+
return { uniqueFrames: [], frameDurations: [] };
|
|
119
|
+
}
|
|
120
|
+
const uniqueFrames = [frames[0]];
|
|
121
|
+
const frameDurations = [1];
|
|
122
|
+
for (let i = 1; i < frames.length; i++) {
|
|
123
|
+
const current = frames[i];
|
|
124
|
+
const lastUnique = uniqueFrames[uniqueFrames.length - 1];
|
|
125
|
+
if (current.content === lastUnique.content) {
|
|
126
|
+
// Same content - extend duration of last unique frame
|
|
127
|
+
frameDurations[frameDurations.length - 1]++;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Different content - add new unique frame
|
|
131
|
+
uniqueFrames.push(current);
|
|
132
|
+
frameDurations.push(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { uniqueFrames, frameDurations };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Extracts the text content group from an SVG.
|
|
139
|
+
* Sanitizes any remaining control characters that are invalid in XML.
|
|
140
|
+
*/
|
|
141
|
+
function extractTextContent(svg) {
|
|
142
|
+
// Extract everything inside <g class="text">...</g>
|
|
143
|
+
const match = svg.match(/<g class="text">([\s\S]*?)<\/g>/);
|
|
144
|
+
if (!match)
|
|
145
|
+
return '';
|
|
146
|
+
// Remove any control characters (ASCII 0-31 except tab, newline, carriage return)
|
|
147
|
+
// These are invalid in XML and can cause parsing errors
|
|
148
|
+
const content = match[1];
|
|
149
|
+
const sanitized = content.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
|
|
150
|
+
return sanitized;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Extracts the glyphs content group from an SVG.
|
|
154
|
+
*/
|
|
155
|
+
function extractGlyphsContent(svg) {
|
|
156
|
+
// Extract everything inside <g class="glyphs">...</g>
|
|
157
|
+
const match = svg.match(/<g class="glyphs">([\s\S]*?)<\/g>/);
|
|
158
|
+
return match ? match[1] : '';
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Injects frame animation using a shared content library.
|
|
162
|
+
* Content is defined once in <defs> and referenced via <use>.
|
|
163
|
+
* This dramatically reduces file size for animations with repeated content.
|
|
164
|
+
*/
|
|
165
|
+
function injectFrameAnimationsWithLibrary(baseSvg, lineLibrary, glyphLibrary, frameLineRefs, frameGlyphRefs, frameDurations, fps, loop) {
|
|
166
|
+
const baseFrameDuration = 1 / fps;
|
|
167
|
+
const totalFrameUnits = frameDurations.reduce((sum, d) => sum + d, 0);
|
|
168
|
+
const totalDuration = totalFrameUnits * baseFrameDuration;
|
|
169
|
+
// Build the content library in <defs>
|
|
170
|
+
let defsContent = '\n <!-- Shared content library -->\n';
|
|
171
|
+
// Add all unique lines to defs
|
|
172
|
+
for (const [content, id] of lineLibrary) {
|
|
173
|
+
// Wrap in a group with id for referencing
|
|
174
|
+
defsContent += ` <g id="${id}">${content}</g>\n`;
|
|
175
|
+
}
|
|
176
|
+
// Add all unique glyphs to defs
|
|
177
|
+
for (const [content, id] of glyphLibrary) {
|
|
178
|
+
defsContent += ` <g id="${id}">${content}</g>\n`;
|
|
179
|
+
}
|
|
180
|
+
// Calculate start times for each frame
|
|
181
|
+
const startTimes = [];
|
|
182
|
+
let currentTime = 0;
|
|
183
|
+
for (const duration of frameDurations) {
|
|
184
|
+
startTimes.push(currentTime);
|
|
185
|
+
currentTime += duration * baseFrameDuration;
|
|
186
|
+
}
|
|
187
|
+
// Build frame groups that reference the shared content via <use>
|
|
188
|
+
// Use simpler SMIL: animate visibility with keyTimes for precise control
|
|
189
|
+
const frameGroups = frameLineRefs.map((lineRefs, index) => {
|
|
190
|
+
const glyphRefs = frameGlyphRefs[index] || [];
|
|
191
|
+
const startTime = startTimes[index];
|
|
192
|
+
const duration = frameDurations[index] * baseFrameDuration;
|
|
193
|
+
const isFirstFrame = index === 0;
|
|
194
|
+
const isLastFrame = index === frameLineRefs.length - 1;
|
|
195
|
+
// Build <use> references for glyphs and lines
|
|
196
|
+
const glyphUses = glyphRefs.map(id => `<use href="#${id}"/>`).join('');
|
|
197
|
+
const lineUses = lineRefs.map(id => `<use href="#${id}"/>`).join('');
|
|
198
|
+
// Simple SMIL: show at startTime, hide at startTime + duration
|
|
199
|
+
// First frame starts visible, others start hidden
|
|
200
|
+
const initialVisibility = isFirstFrame ? 'visible' : 'hidden';
|
|
201
|
+
let smilTags = '';
|
|
202
|
+
if (loop) {
|
|
203
|
+
// For looping: use animate with values and keyTimes
|
|
204
|
+
const showStart = startTime / totalDuration;
|
|
205
|
+
const showEnd = (startTime + duration) / totalDuration;
|
|
206
|
+
smilTags = `
|
|
207
|
+
<animate attributeName="visibility" values="hidden;visible;hidden" keyTimes="0;${showStart.toFixed(4)};${showEnd.toFixed(4)}" dur="${totalDuration.toFixed(3)}s" repeatCount="indefinite" calcMode="discrete"/>`;
|
|
208
|
+
}
|
|
209
|
+
else if (isLastFrame) {
|
|
210
|
+
// Last frame: show and keep visible
|
|
211
|
+
if (isFirstFrame) {
|
|
212
|
+
// Single frame - just stay visible
|
|
213
|
+
smilTags = '';
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
smilTags = `
|
|
217
|
+
<set attributeName="visibility" to="visible" begin="${startTime.toFixed(3)}s" fill="freeze"/>`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (isFirstFrame) {
|
|
221
|
+
// First frame: start visible, hide when next frame starts
|
|
222
|
+
smilTags = `
|
|
223
|
+
<set attributeName="visibility" to="hidden" begin="${(startTime + duration).toFixed(3)}s" fill="freeze"/>`;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// Middle frames: show at start, hide at end
|
|
227
|
+
smilTags = `
|
|
228
|
+
<set attributeName="visibility" to="visible" begin="${startTime.toFixed(3)}s" fill="freeze"/>
|
|
229
|
+
<set attributeName="visibility" to="hidden" begin="${(startTime + duration).toFixed(3)}s" fill="freeze"/>`;
|
|
230
|
+
}
|
|
231
|
+
return `
|
|
232
|
+
<g class="frame" id="frame-${index}" visibility="${initialVisibility}">
|
|
233
|
+
${glyphUses}${lineUses}${smilTags}
|
|
234
|
+
</g>`;
|
|
235
|
+
}).join('');
|
|
236
|
+
// Insert defs content and replace frame groups
|
|
237
|
+
let animatedSvg = baseSvg;
|
|
238
|
+
// Add library to defs
|
|
239
|
+
const defsMatch = animatedSvg.match(/<defs>/);
|
|
240
|
+
if (defsMatch) {
|
|
241
|
+
animatedSvg = animatedSvg.replace(/<defs>/, `<defs>${defsContent}`);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// Create defs section
|
|
245
|
+
animatedSvg = animatedSvg.replace(/<svg([^>]*)>/, `<svg$1>\n<defs>${defsContent}</defs>`);
|
|
246
|
+
}
|
|
247
|
+
// Remove glyphs group (content is now in defs)
|
|
248
|
+
animatedSvg = animatedSvg.replace(/<g class="glyphs">[\s\S]*?<\/g>\s*/g, '');
|
|
249
|
+
// Replace the text content with frame groups
|
|
250
|
+
animatedSvg = animatedSvg.replace(/<g class="text">[\s\S]*?<\/g>/, `<g class="animation">${frameGroups}
|
|
251
|
+
</g>`);
|
|
252
|
+
return animatedSvg;
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=frame-animator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-animator.js","sourceRoot":"","sources":["../src/frame-animator.ts"],"names":[],"mappings":";;AAqBA,4DAiCC;AArDD,uCAA+D;AAU/D;;;;;;;;;GASG;AACI,KAAK,UAAU,wBAAwB,CAC5C,MAAe,EACf,OAA8B;IAE9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,IAAA,wBAAa,EAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE,CAAC;IAED,gEAAgE;IAChE,MAAM,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1E,IAAI,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAExD,wEAAwE;IACxE,IAAI,MAAM,GAAG,MAAM,kBAAkB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAE7D,qDAAqD;IACrD,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAC9C,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,WAAW,GAAG,CAAC,CAAC;IAEtB,OAAO,MAAM,CAAC,MAAM,GAAG,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;QACzF,wDAAwD;QACxD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;QAChG,YAAY,GAAG,YAAY,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QAC3D,MAAM,GAAG,MAAM,kBAAkB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzD,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,MAAe,EAAE,IAAY;IACjD,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAEnD,MAAM,OAAO,GAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAExC,sBAAsB;IACtB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,GAAG,KAAK;QACR,KAAK;QACL,SAAS,EAAE,KAAK,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,qBAAqB;KACtD,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAC/B,MAAe,EACf,OAA8B;IAE9B,2CAA2C;IAC3C,MAAM,kBAAkB,GAAG,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAEhE,sCAAsC;IACtC,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,kBAAkB,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAC1C,IAAA,wBAAa,EAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CACtD,CACF,CAAC;IAEF,gDAAgD;IAChD,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,GAChE,mBAAmB,CAAC,eAAe,CAAC,CAAC;IAEvC,iDAAiD;IACjD,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACnC,OAAO,gCAAgC,CACrC,OAAO,EACP,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,kBAAkB,CAAC,cAAc,EACjC,OAAO,CAAC,GAAG,EACX,OAAO,CAAC,IAAI,CACb,CAAC;AACJ,CAAC;AASD;;;GAGG;AACH,SAAS,mBAAmB,CAAC,SAAmB;IAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,MAAM,aAAa,GAAe,EAAE,CAAC;IACrC,MAAM,cAAc,GAAe,EAAE,CAAC;IAEtC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAE/C,yCAAyC;QACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,8BAA8B,CAAC,IAAI,EAAE,CAAC;QAE7E,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,EAAE,CAAC;gBACnC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC;QAC1C,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE7B,kCAAkC;QAClC,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,4CAA4C;QAC5C,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,uCAAuC,CAAC,IAAI,EAAE,CAAC;QAExF,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,EAAE,CAAC;gBACrC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACrC,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,CAAC;QAC7C,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,SAAS,4BAA4B,CAAC,MAAe;IAInD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IAClD,CAAC;IAED,MAAM,YAAY,GAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAa,CAAC,CAAC,CAAC,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEzD,IAAI,OAAO,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC;YAC3C,sDAAsD;YACtD,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,2CAA2C;YAC3C,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACrC,oDAAoD;IACpD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,kFAAkF;IAClF,wDAAwD;IACxD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;IAEvE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAW;IACvC,sDAAsD;IACtD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,SAAS,gCAAgC,CACvC,OAAe,EACf,WAAgC,EAChC,YAAiC,EACjC,aAAyB,EACzB,cAA0B,EAC1B,cAAwB,EACxB,GAAW,EACX,IAAa;IAEb,MAAM,iBAAiB,GAAG,CAAC,GAAG,GAAG,CAAC;IAClC,MAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,aAAa,GAAG,eAAe,GAAG,iBAAiB,CAAC;IAE1D,sCAAsC;IACtC,IAAI,WAAW,GAAG,uCAAuC,CAAC;IAE1D,+BAA+B;IAC/B,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC;QACxC,0CAA0C;QAC1C,WAAW,IAAI,YAAY,EAAE,KAAK,OAAO,QAAQ,CAAC;IACpD,CAAC;IAED,gCAAgC;IAChC,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;QACzC,WAAW,IAAI,YAAY,EAAE,KAAK,OAAO,QAAQ,CAAC;IACpD,CAAC;IAED,uCAAuC;IACvC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;QACtC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7B,WAAW,IAAI,QAAQ,GAAG,iBAAiB,CAAC;IAC9C,CAAC;IAED,iEAAiE;IACjE,yEAAyE;IACzE,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;QACxD,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,iBAAiB,CAAC;QAC3D,MAAM,YAAY,GAAG,KAAK,KAAK,CAAC,CAAC;QACjC,MAAM,WAAW,GAAG,KAAK,KAAK,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;QAEvD,8CAA8C;QAC9C,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAErE,+DAA+D;QAC/D,kDAAkD;QAClD,MAAM,iBAAiB,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;QAE9D,IAAI,QAAQ,GAAG,EAAE,CAAC;QAClB,IAAI,IAAI,EAAE,CAAC;YACT,oDAAoD;YACpD,MAAM,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;YAC5C,MAAM,OAAO,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,aAAa,CAAC;YACvD,QAAQ,GAAG;qFACoE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,mDAAmD,CAAC;QACjN,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,oCAAoC;YACpC,IAAI,YAAY,EAAE,CAAC;gBACjB,mCAAmC;gBACnC,QAAQ,GAAG,EAAE,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG;0DACuC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;YAC7F,CAAC;QACH,CAAC;aAAM,IAAI,YAAY,EAAE,CAAC;YACxB,0DAA0D;YAC1D,QAAQ,GAAG;yDACwC,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAC3G,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,QAAQ,GAAG;0DACyC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;yDACrB,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAC3G,CAAC;QAED,OAAO;+BACoB,KAAK,iBAAiB,iBAAiB;MAChE,SAAS,GAAG,QAAQ,GAAG,QAAQ;OAC9B,CAAC;IACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,+CAA+C;IAC/C,IAAI,WAAW,GAAG,OAAO,CAAC;IAE1B,sBAAsB;IACtB,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,sBAAsB;QACtB,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,cAAc,EAAE,kBAAkB,WAAW,SAAS,CAAC,CAAC;IAC5F,CAAC;IAED,+CAA+C;IAC/C,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;IAE7E,6CAA6C;IAC7C,WAAW,GAAG,WAAW,CAAC,OAAO,CAC/B,+BAA+B,EAC/B,wBAAwB,WAAW;OAChC,CACJ,CAAC;IAEF,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface CaptureOptions {
|
|
2
|
+
mode: 'clear' | 'time';
|
|
3
|
+
fps: number;
|
|
4
|
+
maxFrames: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Frame {
|
|
7
|
+
content: string;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
index: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Captures frames from terminal animation input.
|
|
13
|
+
* Supports two modes: clear-screen detection and time-based buffering.
|
|
14
|
+
*/
|
|
15
|
+
export declare function captureFrames(input: string, options: CaptureOptions): Frame[];
|
|
16
|
+
//# sourceMappingURL=frame-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-capture.d.ts","sourceRoot":"","sources":["../src/frame-capture.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,KAAK,EAAE,CAMT"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.captureFrames = captureFrames;
|
|
4
|
+
/**
|
|
5
|
+
* Captures frames from terminal animation input.
|
|
6
|
+
* Supports two modes: clear-screen detection and time-based buffering.
|
|
7
|
+
*/
|
|
8
|
+
function captureFrames(input, options) {
|
|
9
|
+
if (options.mode === 'clear') {
|
|
10
|
+
return captureByClearScreen(input, options);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
return captureByTime(input, options);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Strips common cursor control sequences that shouldn't be rendered.
|
|
18
|
+
*/
|
|
19
|
+
function stripCursorControls(text) {
|
|
20
|
+
return text
|
|
21
|
+
.replace(/\x1B\[\?25l/g, '') // Hide cursor
|
|
22
|
+
.replace(/\x1B\[\?25h/g, '') // Show cursor
|
|
23
|
+
.replace(/\x1B\[H/g, '') // Move cursor to home
|
|
24
|
+
.replace(/\x1B\[\d+;\d+H/g, '') // Move cursor to position
|
|
25
|
+
.replace(/\x1B\[K/g, '') // Clear line from cursor
|
|
26
|
+
.replace(/\x1B\[J/g, ''); // Clear screen from cursor
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks if content has any visible text (not just whitespace/control chars).
|
|
30
|
+
*/
|
|
31
|
+
function hasVisibleContent(text) {
|
|
32
|
+
const stripped = stripCursorControls(text).trim();
|
|
33
|
+
return stripped.length > 0;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Captures frames by detecting clear screen commands.
|
|
37
|
+
* Each clear command marks the boundary between frames.
|
|
38
|
+
*/
|
|
39
|
+
function captureByClearScreen(input, options) {
|
|
40
|
+
const CLEAR_PATTERNS = [
|
|
41
|
+
'\x1Bc', // Full reset (used by chartscii)
|
|
42
|
+
'\x1B[2J', // Clear entire screen (ESC[2J)
|
|
43
|
+
'\x1B[H\x1B[2J', // Move to home + clear
|
|
44
|
+
'\x1Bc', // Alternative reset
|
|
45
|
+
];
|
|
46
|
+
const frames = [];
|
|
47
|
+
let remainingInput = input;
|
|
48
|
+
// Try to split by each clear pattern
|
|
49
|
+
for (const pattern of CLEAR_PATTERNS) {
|
|
50
|
+
if (remainingInput.includes(pattern)) {
|
|
51
|
+
const parts = remainingInput.split(pattern);
|
|
52
|
+
// First part is before any clear (skip it)
|
|
53
|
+
// Subsequent parts are frames
|
|
54
|
+
for (let i = 1; i < parts.length && frames.length < options.maxFrames; i++) {
|
|
55
|
+
const stripped = stripCursorControls(parts[i]);
|
|
56
|
+
const content = stripped.trim();
|
|
57
|
+
// Only include frames with actual visible content
|
|
58
|
+
if (content && hasVisibleContent(content)) {
|
|
59
|
+
frames.push({
|
|
60
|
+
content,
|
|
61
|
+
timestamp: frames.length * (1000 / options.fps),
|
|
62
|
+
index: frames.length,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// If we found frames with this pattern, stop trying other patterns
|
|
67
|
+
if (frames.length > 0) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// If no frames were captured (no clear commands found), treat entire input as single frame
|
|
73
|
+
if (frames.length === 0) {
|
|
74
|
+
const stripped = stripCursorControls(input);
|
|
75
|
+
const content = stripped.trim();
|
|
76
|
+
if (content && hasVisibleContent(content)) {
|
|
77
|
+
frames.push({
|
|
78
|
+
content,
|
|
79
|
+
timestamp: 0,
|
|
80
|
+
index: 0,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return frames;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Captures frames based on time intervals.
|
|
88
|
+
* Simulates terminal state at regular intervals by replaying the input stream.
|
|
89
|
+
*
|
|
90
|
+
* This works by:
|
|
91
|
+
* 1. Parsing the input for timing information (escape sequences, delays, etc.)
|
|
92
|
+
* 2. Building a virtual terminal buffer
|
|
93
|
+
* 3. Snapshotting the buffer at regular intervals (based on fps)
|
|
94
|
+
*
|
|
95
|
+
* For inputs without timing info, it distributes content evenly across frames.
|
|
96
|
+
*/
|
|
97
|
+
function captureByTime(input, options) {
|
|
98
|
+
const intervalMs = 1000 / options.fps; // e.g., 100ms for 10fps
|
|
99
|
+
// Try to detect if input has timing markers or clear sequences
|
|
100
|
+
const clearPattern = /\x1Bc|\x1B\[2J|\x1B\[H\x1B\[2J/g;
|
|
101
|
+
const hasClearSequences = clearPattern.test(input);
|
|
102
|
+
if (hasClearSequences) {
|
|
103
|
+
// If we have clear sequences, use them as frame boundaries with timestamps
|
|
104
|
+
return captureByTimeWithClearMarkers(input, options, intervalMs);
|
|
105
|
+
}
|
|
106
|
+
// No clear sequences - this is static content (like lolcat output)
|
|
107
|
+
// Return as a single frame instead of progressive reveal
|
|
108
|
+
const stripped = stripCursorControls(input);
|
|
109
|
+
const content = stripped.trim();
|
|
110
|
+
if (content && hasVisibleContent(content)) {
|
|
111
|
+
return [{
|
|
112
|
+
content,
|
|
113
|
+
timestamp: 0,
|
|
114
|
+
index: 0,
|
|
115
|
+
}];
|
|
116
|
+
}
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Captures frames using clear sequences as boundaries, but assigns proper timestamps.
|
|
121
|
+
*/
|
|
122
|
+
function captureByTimeWithClearMarkers(input, options, intervalMs) {
|
|
123
|
+
const CLEAR_PATTERNS = [
|
|
124
|
+
'\x1Bc', // Full reset
|
|
125
|
+
'\x1B[2J', // Clear entire screen
|
|
126
|
+
'\x1B\[H\x1B\[2J', // Move to home + clear
|
|
127
|
+
];
|
|
128
|
+
const frames = [];
|
|
129
|
+
let remainingInput = input;
|
|
130
|
+
for (const pattern of CLEAR_PATTERNS) {
|
|
131
|
+
if (remainingInput.includes(pattern)) {
|
|
132
|
+
const parts = remainingInput.split(pattern);
|
|
133
|
+
for (let i = 1; i < parts.length && frames.length < options.maxFrames; i++) {
|
|
134
|
+
const stripped = stripCursorControls(parts[i]);
|
|
135
|
+
const content = stripped.trim();
|
|
136
|
+
if (content && hasVisibleContent(content)) {
|
|
137
|
+
frames.push({
|
|
138
|
+
content,
|
|
139
|
+
timestamp: frames.length * intervalMs,
|
|
140
|
+
index: frames.length,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (frames.length > 0)
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Fallback: treat entire input as single frame
|
|
149
|
+
if (frames.length === 0) {
|
|
150
|
+
const stripped = stripCursorControls(input);
|
|
151
|
+
const content = stripped.trim();
|
|
152
|
+
if (content && hasVisibleContent(content)) {
|
|
153
|
+
frames.push({
|
|
154
|
+
content,
|
|
155
|
+
timestamp: 0,
|
|
156
|
+
index: 0,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return frames;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=frame-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-capture.js","sourceRoot":"","sources":["../src/frame-capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG Animator V2
|
|
3
|
+
* Combines pre-rendered terminal SVGs into animated SVG
|
|
4
|
+
*/
|
|
5
|
+
import type { TerminalFrame } from './dvd-executor-v2';
|
|
6
|
+
export interface AnimationOptions {
|
|
7
|
+
fps?: number;
|
|
8
|
+
loop?: boolean;
|
|
9
|
+
pauseAtEnd?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create animated SVG from frames
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAnimatedSVG(frames: TerminalFrame[], options?: AnimationOptions): Promise<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Get animation metadata
|
|
17
|
+
*/
|
|
18
|
+
export declare function getAnimationMetadata(frames: TerminalFrame[]): {
|
|
19
|
+
duration: number;
|
|
20
|
+
frameCount: number;
|
|
21
|
+
fps: number;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=svg-animator-v2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-animator-v2.d.ts","sourceRoot":"","sources":["../src/svg-animator-v2.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAqDjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAUA"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SVG Animator V2
|
|
4
|
+
* Combines pre-rendered terminal SVGs into animated SVG
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createAnimatedSVG = createAnimatedSVG;
|
|
8
|
+
exports.getAnimationMetadata = getAnimationMetadata;
|
|
9
|
+
/**
|
|
10
|
+
* Extract SVG body content (everything inside <svg>)
|
|
11
|
+
*/
|
|
12
|
+
function extractSVGBody(svg, frameId) {
|
|
13
|
+
const contentMatch = svg.match(/<svg[^>]*>([\s\S]*)<\/svg>/);
|
|
14
|
+
if (!contentMatch)
|
|
15
|
+
return '';
|
|
16
|
+
let content = contentMatch[1];
|
|
17
|
+
// Make IDs unique
|
|
18
|
+
content = content
|
|
19
|
+
.replace(/id="([^"]*)"/g, `id="$1-${frameId}"`)
|
|
20
|
+
.replace(/url\(#([^)]*)\)/g, `url(#$1-${frameId})`)
|
|
21
|
+
.replace(/class="([^"]*)"/g, `class="$1 ${frameId}"`);
|
|
22
|
+
return content;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get SVG dimensions from first frame
|
|
26
|
+
*/
|
|
27
|
+
function getSVGDimensions(svg) {
|
|
28
|
+
const widthMatch = svg.match(/width="(\d+)"/);
|
|
29
|
+
const heightMatch = svg.match(/height="(\d+)"/);
|
|
30
|
+
return {
|
|
31
|
+
width: widthMatch ? parseInt(widthMatch[1], 10) : 800,
|
|
32
|
+
height: heightMatch ? parseInt(heightMatch[1], 10) : 600,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create CSS keyframes for animation
|
|
37
|
+
*/
|
|
38
|
+
function createKeyframes(frames) {
|
|
39
|
+
if (frames.length === 0)
|
|
40
|
+
return '';
|
|
41
|
+
const totalDuration = frames[frames.length - 1].timestamp;
|
|
42
|
+
let css = '';
|
|
43
|
+
frames.forEach((frame, i) => {
|
|
44
|
+
const startPercent = i === 0 ? 0 : (frames[i - 1].timestamp / totalDuration) * 100;
|
|
45
|
+
const endPercent = (frame.timestamp / totalDuration) * 100;
|
|
46
|
+
const nextPercent = i < frames.length - 1
|
|
47
|
+
? (frames[i + 1].timestamp / totalDuration) * 100
|
|
48
|
+
: 100;
|
|
49
|
+
css += `
|
|
50
|
+
@keyframes frame-${i}-anim {
|
|
51
|
+
0% { opacity: 0; }
|
|
52
|
+
${startPercent.toFixed(2)}% { opacity: 0; }
|
|
53
|
+
${endPercent.toFixed(2)}% { opacity: 1; }
|
|
54
|
+
${nextPercent.toFixed(2)}% { opacity: 1; }
|
|
55
|
+
${(nextPercent + 0.01).toFixed(2)}% { opacity: 0; }
|
|
56
|
+
100% { opacity: 0; }
|
|
57
|
+
}`;
|
|
58
|
+
});
|
|
59
|
+
// First frame special case
|
|
60
|
+
const firstEnd = (frames[1]?.timestamp / totalDuration) * 100 || 100;
|
|
61
|
+
css = `
|
|
62
|
+
@keyframes frame-0-anim {
|
|
63
|
+
0% { opacity: 1; }
|
|
64
|
+
${firstEnd.toFixed(2)}% { opacity: 1; }
|
|
65
|
+
${(firstEnd + 0.01).toFixed(2)}% { opacity: 0; }
|
|
66
|
+
100% { opacity: 0; }
|
|
67
|
+
}` + css.substring(css.indexOf('@keyframes frame-1-anim'));
|
|
68
|
+
return css;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Create animated SVG from frames
|
|
72
|
+
*/
|
|
73
|
+
async function createAnimatedSVG(frames, options = {}) {
|
|
74
|
+
if (frames.length === 0) {
|
|
75
|
+
throw new Error('No frames to animate');
|
|
76
|
+
}
|
|
77
|
+
// Get dimensions from first frame
|
|
78
|
+
const { width, height } = getSVGDimensions(frames[0].svg);
|
|
79
|
+
// Calculate duration
|
|
80
|
+
const totalDuration = frames[frames.length - 1].timestamp;
|
|
81
|
+
const pauseAtEnd = options.pauseAtEnd || 1000;
|
|
82
|
+
const animationDuration = ((totalDuration + pauseAtEnd) / 1000).toFixed(2);
|
|
83
|
+
const animationIterationCount = options.loop !== false ? 'infinite' : '1';
|
|
84
|
+
// Create keyframes
|
|
85
|
+
const keyframes = createKeyframes(frames);
|
|
86
|
+
// Extract frame contents
|
|
87
|
+
const frameBodies = frames.map((frame, i) => ({
|
|
88
|
+
id: `frame-${i}`,
|
|
89
|
+
content: extractSVGBody(frame.svg, `f${i}`),
|
|
90
|
+
}));
|
|
91
|
+
// Build animated SVG
|
|
92
|
+
const svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
93
|
+
<style>
|
|
94
|
+
${keyframes}
|
|
95
|
+
|
|
96
|
+
.frame {
|
|
97
|
+
animation-duration: ${animationDuration}s;
|
|
98
|
+
animation-timing-function: step-end;
|
|
99
|
+
animation-iteration-count: ${animationIterationCount};
|
|
100
|
+
animation-fill-mode: forwards;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
${frames.map((_, i) => `
|
|
104
|
+
.frame-${i} {
|
|
105
|
+
animation-name: frame-${i}-anim;
|
|
106
|
+
}`).join('')}
|
|
107
|
+
</style>
|
|
108
|
+
|
|
109
|
+
<defs>
|
|
110
|
+
${frameBodies.map((frame) => `
|
|
111
|
+
<g id="${frame.id}">
|
|
112
|
+
${frame.content}
|
|
113
|
+
</g>`).join('')}
|
|
114
|
+
</defs>
|
|
115
|
+
|
|
116
|
+
${frameBodies.map((frame, i) => `
|
|
117
|
+
<use href="#${frame.id}" class="frame frame-${i}" />`).join('')}
|
|
118
|
+
</svg>`;
|
|
119
|
+
return svg;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get animation metadata
|
|
123
|
+
*/
|
|
124
|
+
function getAnimationMetadata(frames) {
|
|
125
|
+
const duration = frames.length > 0 ? frames[frames.length - 1].timestamp : 0;
|
|
126
|
+
const frameCount = frames.length;
|
|
127
|
+
const fps = frameCount > 1 ? frameCount / (duration / 1000) : 0;
|
|
128
|
+
return {
|
|
129
|
+
duration,
|
|
130
|
+
frameCount,
|
|
131
|
+
fps: Math.round(fps * 10) / 10,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=svg-animator-v2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-animator-v2.js","sourceRoot":"","sources":["../src/svg-animator-v2.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAoFH,8CAwDC;AAKD,oDAcC;AArJD;;GAEG;AACH,SAAS,cAAc,CAAC,GAAW,EAAE,OAAe;IAClD,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAC7D,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,CAAC;IAE7B,IAAI,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9B,kBAAkB;IAClB,OAAO,GAAG,OAAO;SACd,OAAO,CAAC,eAAe,EAAE,UAAU,OAAO,GAAG,CAAC;SAC9C,OAAO,CAAC,kBAAkB,EAAE,WAAW,OAAO,GAAG,CAAC;SAClD,OAAO,CAAC,kBAAkB,EAAE,aAAa,OAAO,GAAG,CAAC,CAAC;IAExD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAEhD,OAAO;QACL,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;QACrD,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;KACzD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAuB;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1D,IAAI,GAAG,GAAG,EAAE,CAAC;IAEb,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;QACnF,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;QAC3D,MAAM,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC;YACvC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,GAAG,aAAa,CAAC,GAAG,GAAG;YACjD,CAAC,CAAC,GAAG,CAAC;QAER,GAAG,IAAI;uBACY,CAAC;;QAEhB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QACvB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;QACrB,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;;MAEjC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;IACrE,GAAG,GAAG;;;QAGA,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnB,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;;MAE9B,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAE7D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,iBAAiB,CACrC,MAAuB,EACvB,UAA4B,EAAE;IAE9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,kCAAkC;IAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAE1D,qBAAqB;IACrB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;IAC9C,MAAM,iBAAiB,GAAG,CAAC,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,uBAAuB,GAAG,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;IAE1E,mBAAmB;IACnB,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAE1C,yBAAyB;IACzB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5C,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC;KAC5C,CAAC,CAAC,CAAC;IAEJ,qBAAqB;IACrB,MAAM,GAAG,GAAG,eAAe,KAAK,aAAa,MAAM;;MAE/C,SAAS;;;4BAGa,iBAAiB;;mCAEV,uBAAuB;;;;MAIpD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;aACd,CAAC;8BACgB,CAAC;MACzB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;;MAIV,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;aACpB,KAAK,CAAC,EAAE;QACb,KAAK,CAAC,OAAO;SACZ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;IAGf,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClB,KAAK,CAAC,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;OAC1D,CAAC;IAEN,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,MAAuB;IAK1D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,MAAM,GAAG,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,QAAQ;QACR,UAAU;QACV,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;KAC/B,CAAC;AACJ,CAAC"}
|