kawaandClaude Opus 5 a6ec6c980a fix: audit src/js and add a frame-accurate export path
Two halves of one pass; TODO-FIXES.md lists every finding.

The audit fixed, among ~90 items: MP4 export dead-ending and locking the UI
behind a stuck "Downloading..." button; height keyframes storing the width;
shadow defaults and keyframes storing undefined because fabric's get() is not
a path getter; every letter animation writing to the last letter; keyframe
times drifting on each drag because data-time was layer-relative on expanded
rows; O(n^2 log n) playback, now indexed once per frame; and a save() that
rebuilt the record canvas on every edit, now debounced.

Exports also lost audio-layer sound outright: MediaRecorder records only the
first audio track, so every source now mixes through one AudioContext into one
destination.

The new half is src/js/render.js, an offline renderer. Real-time capture was
the root cause of dropped frames on heavy scenes and smeared video layers: a
bare currentTime assignment is async, so drawing straight after it captures the
previous frame. Each frame is now seeked, awaited on 'seeked', drawn, and
pushed through a VideoEncoder; audio is mixed in one OfflineAudioContext pass
and encoded to Opus. webm-writer2.js gained a second Opus track and lost three
bugs, including a MAX_CLUSTER_DURATION_MSEC of ~58 days that overflowed the
signed 16-bit block timecode past ~32s.

Real-time capture remains the fallback: the hand-rolled muxer's output is
decoded in a <video> element before being handed over, and any failure returns
null so record() falls back transparently.

test/webm-muxer.test.js parses the muxer output with an EBML reader in plain
Node. It caught the fixed-256-byte header overflow that inspection missed.

Not verified in a browser: node --check passes on every script and the muxer
test passes, but a running Chrome held the Playwright profile lock, so the
manual pass listed at the end of TODO-FIXES.md is still outstanding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 12:58:51 +02:00
2026-08-12 12:58:07 +02:00
2026-08-11 15:58:47 +02:00
2026-08-11 15:58:47 +02:00
2026-08-12 12:58:07 +02:00

Motionity

This is a fork of the original project aiming to fix issues and add features.

Running it

npm run vendor   # downloads the third-party libraries into src/vendor/
npm start        # http://127.0.0.1:8080

Three packaged distributions are available — desktop (Windows .exe, Linux AppImage and Flatpak), a Docker image, and a bare-metal install. Build instructions for all of them are in PACKAGING.md.

npm run dev            # desktop app from source
npm run dist:win       # Windows installer + portable exe
npm run dist:linux     # AppImage + Flatpak
npm run docker:build   # container image

Releasing

./scripts/build-release.ps1                 # installers + SHA256SUMS.txt in dist/
./scripts/publish.ps1 -PublishRelease       # + image push and Gitea release upload

build-release.ps1 needs no credentials. publish.ps1 needs a Gitea token with package read/write (image push) and write:repository (release upload), read from $env:GITEA_TOKEN or prompted for. -BinariesOnly -NoBinaryBuild retries a failed upload without rebuilding.

One rule applies to every target: browsers expose WebCodecs (the fast exporter) and IndexedDB (project saving) only in a secure context. http://localhost qualifies; a plain-HTTP LAN address does not. Serve it over TLS anywhere else.

S
Description
This is a fork of the original project aiming to fix issues and add features.
Readme MIT
42 MiB
2026-08-14 11:00:58 +02:00
Languages
JavaScript 80.1%
PowerShell 9.1%
CSS 8%
HTML 2.6%
Dockerfile 0.2%