0.16.0: animated GIF / APNG export + transparent canvas
- New frame-by-frame export pipeline in src/lib/frameExport.ts: loads scene images, walks rangeIn..rangeOut at scene.fps, drawSceneFrame to an offscreen canvas, awaits a per-frame callback, yields every 4 frames to keep progress responsive, honours AbortSignal. - Animated GIF via gifenc (per-frame quantize/palette, ~5 KB lib). - Animated PNG via UPNG.js + pako (lossless RGBA, alpha-aware, ~30 KB). - drawSceneFrame now clearRects first and skips the background fill when scene.canvas.background === 'transparent' — prerequisite for the alpha to reach the APNG output. - DocumentDrawer: new checkerboard toggle next to the colour picker flips the stage between its last-picked colour and transparent; disabled swatch + 'Transparent' hex label make the state obvious. - ExportDialog: three new option rows — Animated GIF, Animated PNG, and an APNG preview page that bundles the rendered APNG into a standalone HTML with a checkerboard backdrop + dark/light toggles for verifying transparency at a glance. - Tests: renderFrames frame count + abort, GIF header magic, APNG acTL presence, transparent round-trip (decoded alpha == 0 on un-painted pixels), preview HTML structure, and the two UI tests covering ExportDialog's new rows and the progress-view transition. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
827d80bfd0
commit
fcfd21428d
12 files changed
+956
-14
No files matched your search
@@ -395,6 +395,8 @@ export const en = {
|
||||
width: 'Width',
|
||||
height: 'Height',
|
||||
background: 'Background',
|
||||
backgroundTransparent: 'Transparent',
|
||||
backgroundTransparentTooltip: 'Transparent background (APNG exports keep alpha)',
|
||||
duration: 'Duration (s)',
|
||||
fps: 'FPS',
|
||||
timelineHint: 'Timeline length sets the ruler scale. Playback stops at the last keyframe.',
|
||||
@@ -417,11 +419,21 @@ export const en = {
|
||||
webmBadge: 'Browser · Realtime',
|
||||
webmDesc: 'No server — recorded in real time',
|
||||
webmNotSupported: 'Browser does not support MediaRecorder',
|
||||
gifBadge: 'Browser · Frame-by-frame',
|
||||
gifDesc: '256-colour palette, broadest compatibility',
|
||||
apngBadge: 'Browser · Lossless',
|
||||
apngDesc: 'Full RGBA with transparency — .png file',
|
||||
apngPreviewTitle: 'APNG preview page',
|
||||
apngPreviewBadge: 'HTML · Checkerboard',
|
||||
apngPreviewDesc: 'Standalone HTML with a checkerboard backdrop so you can verify transparency',
|
||||
cancel: 'Cancel',
|
||||
failed: 'Export failed',
|
||||
back: 'Back',
|
||||
labelWebm: 'Rendering WebM (browser, realtime)…',
|
||||
labelMp4: 'Rendering MP4 (server)…',
|
||||
labelGif: 'Rendering GIF (browser, frame-by-frame)…',
|
||||
labelApng: 'Rendering APNG (browser, frame-by-frame)…',
|
||||
labelApngPreview: 'Rendering APNG + preview page…',
|
||||
skipHidden: 'Skip hidden tracks',
|
||||
skipHiddenDesc: 'Drop layers toggled off in the editor from every format below.',
|
||||
skipHiddenNone: 'No editor-hidden tracks in the scene.',
|
||||
@@ -1174,6 +1186,8 @@ export const de: DeepPartial<Messages> = {
|
||||
width: 'Breite',
|
||||
height: 'Höhe',
|
||||
background: 'Hintergrund',
|
||||
backgroundTransparent: 'Transparent',
|
||||
backgroundTransparentTooltip: 'Transparenter Hintergrund (beim APNG-Export bleibt Alpha erhalten)',
|
||||
duration: 'Dauer (s)',
|
||||
fps: 'FPS',
|
||||
timelineHint: 'Die Timeline-Länge bestimmt die Skala im Lineal. Die Wiedergabe stoppt am Ende.',
|
||||
@@ -1195,11 +1209,21 @@ export const de: DeepPartial<Messages> = {
|
||||
webmBadge: 'Browser · Echtzeit',
|
||||
webmDesc: 'Ohne Server: direkt im Browser aufgenommen.',
|
||||
webmNotSupported: 'Dieser Browser unterstützt MediaRecorder nicht.',
|
||||
gifBadge: 'Browser · Frame-für-Frame',
|
||||
gifDesc: '256-Farben-Palette, maximale Kompatibilität.',
|
||||
apngBadge: 'Browser · Verlustfrei',
|
||||
apngDesc: 'Volles RGBA mit Transparenz — .png-Datei.',
|
||||
apngPreviewTitle: 'APNG-Vorschauseite',
|
||||
apngPreviewBadge: 'HTML · Schachbrett',
|
||||
apngPreviewDesc: 'Eigenständige HTML-Datei mit Schachbrett-Hintergrund zum Transparenz-Check.',
|
||||
cancel: 'Abbrechen',
|
||||
failed: 'Export fehlgeschlagen',
|
||||
back: 'Zurück',
|
||||
labelWebm: 'WebM wird gerendert (Browser, Echtzeit)…',
|
||||
labelMp4: 'MP4 wird gerendert (Server)…',
|
||||
labelGif: 'GIF wird gerendert (Browser, frame-für-frame)…',
|
||||
labelApng: 'APNG wird gerendert (Browser, frame-für-frame)…',
|
||||
labelApngPreview: 'APNG + Vorschau werden gerendert…',
|
||||
skipHidden: 'Versteckte Tracks überspringen',
|
||||
skipHiddenDesc: 'Lässt editor-versteckte Ebenen in allen Exportformaten weg.',
|
||||
skipHiddenNone: 'In dieser Szene gibt es keine editor-versteckten Tracks.',
|
||||
|
||||
Reference in new issue
Block a user