MP4/GIF export used to importScripts() an 18.5 MB asm.js ffmpeg build from https://archive.org/download/ffmpeg_asm/ffmpeg_asm.js: no integrity check, no pinning, executed in the page, and unavailable offline. vendor.mjs now copies ffmpeg.wasm out of node_modules, where package-lock.json pins it by hash, and no CDN fallback is left anywhere in the app. @ffmpeg/core-st is the single-threaded core, chosen deliberately: the default @ffmpeg/core is built with pthreads and needs SharedArrayBuffer, which requires COOP/COEP isolation, which would break the Pixabay, Unsplash and Google Fonts requests. That core also forces two things worth knowing: - mainName: 'main' is mandatory. The loader defaults to proxy_main, which only the multi-threaded build exports, so load() compiles all 23 MB and then aborts. - Its main() calls exit(), so an instance survives exactly one command. Reusing one dies with "Program terminated with exit(0)", so convertStreams builds and tears one down per conversion (~110 ms, and the 23 MB heap comes back in between). The teardown also runs on failure: an interrupted run otherwise leaves the loader's "running" flag set and wedges every later conversion until a page reload. MP4 encodes with libx264 -crf 23 -pix_fmt yuv420p plus AAC rather than mpeg4 -b:v 6400k. Same core, better quality per byte, and yuv420p is what makes it play in Safari and QuickTime. The two @ffmpeg packages are dependencies, not devDependencies, so the Docker vendor stage can npm ci --omit=dev without pulling in electron; build.files excludes them from the asar since src/vendor/ffmpeg/ already carries the copies the app loads. WITH_FFMPEG=0 now means MP4/GIF export is unavailable and says so, rather than silently fetching an encoder at run time. Also deletes src/js/libraries/ffmpeg.min.js, an unreferenced ffmpeg.wasm loader stub that would have fetched its core from unpkg, and prunes the stale src/vendor/ffmpeg_asm.js from existing checkouts — src/vendor/ is packaged whole, so it would have shipped 18.5 MB of dead weight in every installer. Verified in Chromium against a real MediaRecorder WebM: core loads with crossOriginIsolated false, MP4 24 KB decoding to 320x240 / 2.00 s, GIF 138 KB, the two back to back, and the missing-core path reporting correctly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
55 lines
1.9 KiB
Docker
55 lines
1.9 KiB
Docker
# syntax=docker/dockerfile:1
|
|
#
|
|
# Motionity is a static app, so the runtime image is a static file server and
|
|
# nothing else: no Node, no shell tooling, ~8 MB of base image.
|
|
#
|
|
# Build: docker build -t motionity:latest .
|
|
# Run: docker run --rm -p 8080:8080 motionity:latest
|
|
#
|
|
# WITH_FFMPEG=0 drops the 23 MB ffmpeg.wasm core from the image and disables
|
|
# MP4/GIF export, which then reports itself as unavailable. It no longer falls
|
|
# back to downloading the encoder at run time: the old asm.js build came from a
|
|
# public archive.org mirror with no integrity check. Everything else, WEBM
|
|
# export included, is unaffected.
|
|
|
|
FROM node:22-alpine AS vendor
|
|
ARG WITH_FFMPEG=1
|
|
WORKDIR /app
|
|
# ffmpeg.wasm is a runtime dependency, so --omit=dev pulls it in without
|
|
# dragging electron and electron-builder (~400 MB) into the build.
|
|
COPY package.json package-lock.json ./
|
|
RUN npm ci --omit=dev --no-audit --no-fund
|
|
COPY scripts/vendor.mjs scripts/
|
|
COPY src/index.html src/
|
|
RUN if [ "$WITH_FFMPEG" = "1" ]; then \
|
|
node scripts/vendor.mjs; \
|
|
else \
|
|
node scripts/vendor.mjs --skip-ffmpeg; \
|
|
fi
|
|
|
|
FROM ghcr.io/static-web-server/static-web-server:2-alpine
|
|
|
|
COPY --chown=65534:65534 src/ /public/
|
|
COPY --from=vendor --chown=65534:65534 /app/src/vendor/ /public/vendor/
|
|
|
|
ENV SERVER_ROOT=/public \
|
|
SERVER_HOST=0.0.0.0 \
|
|
SERVER_PORT=8080 \
|
|
SERVER_COMPRESSION=true \
|
|
SERVER_COMPRESSION_LEVEL=default \
|
|
SERVER_CACHE_CONTROL_HEADERS=true \
|
|
SERVER_LOG_LEVEL=warn \
|
|
SERVER_SECURITY_HEADERS=false \
|
|
SERVER_HEALTH=true
|
|
|
|
USER 65534:65534
|
|
EXPOSE 8080
|
|
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
|
|
CMD wget -q --spider http://127.0.0.1:8080/health || exit 1
|
|
|
|
# NOTE: browsers expose WebCodecs (the fast exporter) and IndexedDB (project
|
|
# saving) only in a secure context. Reaching this container over plain http://
|
|
# from another machine disables both. Publish it behind TLS, or keep access on
|
|
# http://localhost.
|