chore(video): rename sidecar to video-renderer + add system ffmpeg for HyperFrames

This commit is contained in:
Renn F
2026-07-06 02:17:57 +02:00
parent 608051e2ca
commit 068a1e9b9c
15 changed files with 66 additions and 60 deletions
+3 -3
View File
@@ -33,13 +33,13 @@ panel/out
panel/coverage panel/coverage
panel/tsconfig.tsbuildinfo panel/tsconfig.tsbuildinfo
# motion/ (Remotion compositions) + remotion-renderer (its render sidecar) — # motion/ (HyperFrames compositions) + video-renderer (its render sidecar) —
# re-generated by pnpm install; each Dockerfile installs its own inside the # re-generated by pnpm install; each Dockerfile installs its own inside the
# image, and every build shares this root context, so an un-ignored # image, and every build shares this root context, so an un-ignored
# node_modules here would bloat every image's build-context upload, not # node_modules here would bloat every image's build-context upload, not
# just remotion.Dockerfile's. # just video-renderer.Dockerfile's.
motion/node_modules motion/node_modules
remotion-renderer/node_modules video-renderer/node_modules
# Local stateful data (postgres, redis, ollama, workspaces) — never in images # Local stateful data (postgres, redis, ollama, workspaces) — never in images
data/ data/
+1 -1
View File
@@ -90,7 +90,7 @@ jobs:
declare -A IMAGES=( declare -A IMAGES=(
[roboco-orchestrator]=docker/orchestrator.Dockerfile [roboco-orchestrator]=docker/orchestrator.Dockerfile
[roboco-panel]=docker/panel.Dockerfile [roboco-panel]=docker/panel.Dockerfile
[roboco-remotion]=docker/remotion.Dockerfile [roboco-video-renderer]=docker/video-renderer.Dockerfile
[roboco-agent-pm]=docker/agent-pm.Dockerfile [roboco-agent-pm]=docker/agent-pm.Dockerfile
[roboco-agent-dev-be]=docker/agent-dev-be.Dockerfile [roboco-agent-dev-be]=docker/agent-dev-be.Dockerfile
[roboco-agent-dev-fe]=docker/agent-dev-fe.Dockerfile [roboco-agent-dev-fe]=docker/agent-dev-fe.Dockerfile
+2 -2
View File
@@ -104,9 +104,9 @@ panel/tsconfig.tsbuildinfo
panel/.env.local panel/.env.local
panel/.env.*.local panel/.env.*.local
# motion/ (Remotion compositions) + remotion-renderer (its render sidecar) # motion/ (HyperFrames compositions) + video-renderer (its render sidecar)
motion/node_modules/ motion/node_modules/
remotion-renderer/node_modules/ video-renderer/node_modules/
# hyperframes lint/preview generates index.html in each composition dir — # hyperframes lint/preview generates index.html in each composition dir —
# regenerated locally as needed, not tracked (the sidecar renders # regenerated locally as needed, not tracked (the sidecar renders
# <orientation>.html directly, never index.html) # <orientation>.html directly, never index.html)
+1 -1
View File
@@ -449,7 +449,7 @@ clean:
@cd .. @cd ..
@cd motion && rm -rf node_modules/ @cd motion && rm -rf node_modules/
@cd .. @cd ..
@cd remotion-renderer && rm -rf node_modules/ @cd video-renderer && rm -rf node_modules/
@cd .. @cd ..
# Security # Security
+11 -11
View File
@@ -116,15 +116,15 @@ services:
echo "=== All models ready! ===" echo "=== All models ready! ==="
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Remotion Renderer - sidecar for the video-generation engine (bundles + # Video Renderer - sidecar for the video-generation engine (renders
# renders motion/ compositions to MP4). Harmless when idle — it only # motion/ compositions to MP4 with HyperFrames). Harmless when idle — it
# renders when POSTed; the video_engine_* feature flags (off by default in # only renders when POSTed; the video_engine_* feature flags (off by
# this compose) gate whether the orchestrator ever sends it work. No DB # default in this compose) gate whether the orchestrator ever sends it
# access, no git, no credentials. # work. No DB access, no git, no credentials.
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
remotion-renderer: video-renderer:
image: ${ROBOCO_REGISTRY:-ghcr.io/rennf93}/roboco-remotion:${ROBOCO_VERSION:-latest} image: ${ROBOCO_REGISTRY:-ghcr.io/rennf93}/roboco-video-renderer:${ROBOCO_VERSION:-latest}
container_name: roboco-remotion container_name: roboco-video-renderer
restart: unless-stopped restart: unless-stopped
networks: networks:
- default - default
@@ -249,10 +249,10 @@ services:
ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud
ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b
ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434 ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434
# Remotion renderer sidecar (use container name). The video engine # Video renderer sidecar (use container name). The video engine
# itself is default-off (video_engine_enabled); this just points the # itself is default-off (video_engine_enabled); this just points the
# client at the sidecar for when it's armed. # client at the sidecar for when it's armed.
ROBOCO_REMOTION_BASE_URL: http://roboco-remotion:3001 ROBOCO_VIDEO_RENDERER_BASE_URL: http://roboco-video-renderer:3001
# Spawn the PRE-BUILT agent images from the same registry instead of # Spawn the PRE-BUILT agent images from the same registry instead of
# building them from source (the orchestrator pulls any it lacks). # building them from source (the orchestrator pulls any it lacks).
ROBOCO_AGENT_IMAGE_REGISTRY: ${ROBOCO_REGISTRY:-ghcr.io/rennf93} ROBOCO_AGENT_IMAGE_REGISTRY: ${ROBOCO_REGISTRY:-ghcr.io/rennf93}
@@ -289,7 +289,7 @@ services:
ROBOCO_SELF_HEAL_ORIGINATE_ENABLED: ${ROBOCO_SELF_HEAL_ORIGINATE_ENABLED:-false} ROBOCO_SELF_HEAL_ORIGINATE_ENABLED: ${ROBOCO_SELF_HEAL_ORIGINATE_ENABLED:-false}
ROBOCO_SELF_HEAL_PROJECT_SLUG: ${ROBOCO_SELF_HEAL_PROJECT_SLUG:-roboco-api} ROBOCO_SELF_HEAL_PROJECT_SLUG: ${ROBOCO_SELF_HEAL_PROJECT_SLUG:-roboco-api}
ROBOCO_SELF_HEAL_CI_WORKFLOW: ${ROBOCO_SELF_HEAL_CI_WORKFLOW:-ci.yml} ROBOCO_SELF_HEAL_CI_WORKFLOW: ${ROBOCO_SELF_HEAL_CI_WORKFLOW:-ci.yml}
# Video engine (Remotion): NAS-default-on, OFF in public registry — # Video engine (HyperFrames): NAS-default-on, OFF in public registry —
# heavier optional feature. Arm via .env + uncomment the video-renders # heavier optional feature. Arm via .env + uncomment the video-renders
# bind mount above so renders persist. # bind mount above so renders persist.
ROBOCO_VIDEO_ENGINE_ENABLED: ${ROBOCO_VIDEO_ENGINE_ENABLED:-false} ROBOCO_VIDEO_ENGINE_ENABLED: ${ROBOCO_VIDEO_ENGINE_ENABLED:-false}
+14 -14
View File
@@ -152,19 +152,19 @@ services:
echo "=== All models ready! ===" echo "=== All models ready! ==="
# ========================================================================== # ==========================================================================
# Remotion Renderer - sidecar for the video-generation engine (bundles + # Video Renderer - sidecar for the video-generation engine (renders
# renders motion/ compositions to MP4). Mirrors the ollama sidecar pattern: # motion/ compositions to MP4 with HyperFrames). Mirrors the ollama sidecar
# a plain HTTP service the orchestrator talks to, nothing more. Harmless # pattern: a plain HTTP service the orchestrator talks to, nothing more.
# when idle — it only renders when POSTed; the video_engine_* feature # Harmless when idle — it only renders when POSTed; the video_engine_*
# flags gate whether the orchestrator ever sends it work. No DB access, no # feature flags gate whether the orchestrator ever sends it work. No DB
# git, no credentials — it only ever reads what it's POSTed. # access, no git, no credentials — it only ever reads what it's POSTed.
# ========================================================================== # ==========================================================================
remotion-renderer: video-renderer:
build: build:
context: . context: .
dockerfile: docker/remotion.Dockerfile dockerfile: docker/video-renderer.Dockerfile
image: roboco-remotion image: roboco-video-renderer
container_name: roboco-remotion container_name: roboco-video-renderer
restart: unless-stopped restart: unless-stopped
networks: networks:
- default - default
@@ -396,10 +396,10 @@ services:
ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud
ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b
ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434 ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434
# Remotion renderer sidecar (use container name). The video engine # Video renderer sidecar (use container name). The video engine
# itself is default-off (video_engine_enabled); this just points the # itself is default-off (video_engine_enabled); this just points the
# client at the sidecar for when it's armed. # client at the sidecar for when it's armed.
ROBOCO_REMOTION_BASE_URL: http://roboco-remotion:3001 ROBOCO_VIDEO_RENDERER_BASE_URL: http://roboco-video-renderer:3001
# MinIO object storage for rendered videos (use container name). Empty # MinIO object storage for rendered videos (use container name). Empty
# endpoint = disabled (FileResponse fallback); armed here for the NAS # endpoint = disabled (FileResponse fallback); armed here for the NAS
# deploy, left OFF in docker-compose.registry.yml. # deploy, left OFF in docker-compose.registry.yml.
@@ -486,9 +486,9 @@ services:
# the Product Owner, who proposes a themed cycle of roadmap items; # the Product Owner, who proposes a themed cycle of roadmap items;
# the CEO approves each item individually into the backlog. # the CEO approves each item individually into the backlog.
ROBOCO_ROADMAP_ENGINE_ENABLED: ${ROBOCO_ROADMAP_ENGINE_ENABLED:-true} ROBOCO_ROADMAP_ENGINE_ENABLED: ${ROBOCO_ROADMAP_ENGINE_ENABLED:-true}
# Video-generation engine: a UX/UI dev authors a bespoke Remotion video # Video-generation engine: a UX/UI dev authors a bespoke HyperFrames video
# per release/spotlight/on-demand trigger through the normal delivery # per release/spotlight/on-demand trigger through the normal delivery
# lifecycle; the render loop above renders it via the remotion-renderer # lifecycle; the render loop above renders it via the video-renderer
# sidecar and holds the clip as a CEO-approval draft — nothing # sidecar and holds the clip as a CEO-approval draft — nothing
# auto-posts. Config default is OFF; ARMED here for the NAS deploy like # auto-posts. Config default is OFF; ARMED here for the NAS deploy like
# the rest. Left OFF in docker-compose.registry.yml so the published # the rest. Left OFF in docker-compose.registry.yml so the published
+14 -14
View File
@@ -152,19 +152,19 @@ services:
echo "=== All models ready! ===" echo "=== All models ready! ==="
# ========================================================================== # ==========================================================================
# Remotion Renderer - sidecar for the video-generation engine (bundles + # Video Renderer - sidecar for the video-generation engine (renders
# renders motion/ compositions to MP4). Mirrors the ollama sidecar pattern: # motion/ compositions to MP4 with HyperFrames). Mirrors the ollama sidecar
# a plain HTTP service the orchestrator talks to, nothing more. Harmless # pattern: a plain HTTP service the orchestrator talks to, nothing more.
# when idle — it only renders when POSTed; the video_engine_* feature # Harmless when idle — it only renders when POSTed; the video_engine_*
# flags gate whether the orchestrator ever sends it work. No DB access, no # feature flags gate whether the orchestrator ever sends it work. No DB
# git, no credentials — it only ever reads what it's POSTed. # access, no git, no credentials — it only ever reads what it's POSTed.
# ========================================================================== # ==========================================================================
remotion-renderer: video-renderer:
build: build:
context: . context: .
dockerfile: docker/remotion.Dockerfile dockerfile: docker/video-renderer.Dockerfile
image: roboco-remotion image: roboco-video-renderer
container_name: roboco-remotion container_name: roboco-video-renderer
restart: unless-stopped restart: unless-stopped
networks: networks:
- default - default
@@ -396,10 +396,10 @@ services:
ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud ROBOCO_LOCAL_LLM_MODEL: glm-5.2:cloud
ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b
ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434 ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434
# Remotion renderer sidecar (use container name). The video engine # Video renderer sidecar (use container name). The video engine
# itself is default-off (video_engine_enabled); this just points the # itself is default-off (video_engine_enabled); this just points the
# client at the sidecar for when it's armed. # client at the sidecar for when it's armed.
ROBOCO_REMOTION_BASE_URL: http://roboco-remotion:3001 ROBOCO_VIDEO_RENDERER_BASE_URL: http://roboco-video-renderer:3001
# MinIO object storage for rendered videos (use container name). Empty # MinIO object storage for rendered videos (use container name). Empty
# endpoint = disabled (FileResponse fallback); armed here for the NAS # endpoint = disabled (FileResponse fallback); armed here for the NAS
# deploy, left OFF in docker-compose.registry.yml. # deploy, left OFF in docker-compose.registry.yml.
@@ -486,9 +486,9 @@ services:
# the Product Owner, who proposes a themed cycle of roadmap items; # the Product Owner, who proposes a themed cycle of roadmap items;
# the CEO approves each item individually into the backlog. # the CEO approves each item individually into the backlog.
ROBOCO_ROADMAP_ENGINE_ENABLED: ${ROBOCO_ROADMAP_ENGINE_ENABLED:-true} ROBOCO_ROADMAP_ENGINE_ENABLED: ${ROBOCO_ROADMAP_ENGINE_ENABLED:-true}
# Video-generation engine: a UX/UI dev authors a bespoke Remotion video # Video-generation engine: a UX/UI dev authors a bespoke HyperFrames video
# per release/spotlight/on-demand trigger through the normal delivery # per release/spotlight/on-demand trigger through the normal delivery
# lifecycle; the render loop above renders it via the remotion-renderer # lifecycle; the render loop above renders it via the video-renderer
# sidecar and holds the clip as a CEO-approval draft — nothing # sidecar and holds the clip as a CEO-approval draft — nothing
# auto-posts. Config default is OFF; ARMED here for the NAS deploy like # auto-posts. Config default is OFF; ARMED here for the NAS deploy like
# the rest. Left OFF in docker-compose.registry.yml so the published # the rest. Left OFF in docker-compose.registry.yml so the published
@@ -1,18 +1,23 @@
# remotion-renderer sidecar — untars a motion/ composition source, bundles # video-renderer sidecar — untars a motion/ composition source, renders one
# it, renders one MP4 cut with Remotion, and streams the bytes back. # MP4 cut with HyperFrames, and streams the bytes back.
# #
# Debian (not Alpine): musl slows renders past 10s and has known Chrome # Debian (not Alpine): musl slows renders past 10s and has known Chrome
# Headless Shell compatibility issues (verified against Remotion's own # Headless Shell compatibility issues (verified against upstream
# Docker guidance). FFmpeg is bundled inside @remotion/renderer since v4 — # headless-Chrome Docker guidance). HyperFrames' @hyperframes/producer
# no system ffmpeg package here. # encodes via a system ffmpeg binary — unlike @remotion/renderer (which
# bundled ffmpeg), the producer shells out to ffmpeg on PATH, so install
# it here.
# #
# Build context is the project root, like every other service under # Build context is the project root, like every other service under
# docker/ — paths below are relative to the repo root. # docker/ — paths below are relative to the repo root.
FROM node:22-bookworm-slim FROM node:22-bookworm-slim
# Chrome/Puppeteer runtime libraries — Remotion's documented Debian # Chrome/Puppeteer runtime libraries — the documented Debian dependency
# dependency list for headless rendering. A missing one surfaces as an # list for headless rendering (per Puppeteer/Chrome guidance). A missing
# opaque Puppeteer "Target closed" crash, not a clear missing-library error. # one surfaces as an opaque Puppeteer "Target closed" crash, not a clear
# missing-library error.
# ffmpeg: required by @hyperframes/producer's local render mode — see top
# comment; without it renders fail with "FFmpeg not found".
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
libnss3 \ libnss3 \
libdbus-1-3 \ libdbus-1-3 \
@@ -28,10 +33,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libpango-1.0-0 \ libpango-1.0-0 \
libcairo2 \ libcairo2 \
libcups2 \ libcups2 \
ffmpeg \
ca-certificates \ ca-certificates \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Activate the exact version remotion-renderer/package.json pins # Activate the exact version video-renderer/package.json pins
# (packageManager: pnpm@11.10.0) rather than trusting corepack's bundled # (packageManager: pnpm@11.10.0) rather than trusting corepack's bundled
# default — a future node:22-alpine shipping a different pnpm would silently # default — a future node:22-alpine shipping a different pnpm would silently
# change the build's package manager. # change the build's package manager.
@@ -50,15 +56,15 @@ ENV CI=true
# pnpm-workspace.yaml carries the `allowBuilds: esbuild: true` approval — # pnpm-workspace.yaml carries the `allowBuilds: esbuild: true` approval —
# without it pnpm 11 hard-errors with [ERR_PNPM_IGNORED_BUILDS] (exit 1) # without it pnpm 11 hard-errors with [ERR_PNPM_IGNORED_BUILDS] (exit 1)
# because esbuild's postinstall is unapproved, breaking the image build. # because esbuild's postinstall is unapproved, breaking the image build.
COPY remotion-renderer/package.json remotion-renderer/pnpm-lock.yaml remotion-renderer/pnpm-workspace.yaml ./ COPY video-renderer/package.json video-renderer/pnpm-lock.yaml video-renderer/pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile RUN pnpm install --frozen-lockfile
# Pre-warm Chrome Headless Shell at build time so the container's first # Pre-warm Chrome Headless Shell at build time so the container's first
# real render isn't also the first time it downloads a browser. # real render isn't also the first time it downloads a browser.
COPY remotion-renderer/ensure-browser.mjs ./ COPY video-renderer/ensure-browser.mjs ./
RUN node ensure-browser.mjs RUN node ensure-browser.mjs
COPY remotion-renderer/server.js remotion-renderer/render.js ./ COPY video-renderer/server.js video-renderer/render.js ./
EXPOSE 3001 EXPOSE 3001
ENV PORT=3001 ENV PORT=3001
+1 -1
View File
@@ -1,6 +1,6 @@
# motion # motion
In-repo [HyperFrames](https://github.com/heygen-com/hyperframes) composition package. UX/UI devs author bespoke marketing-video compositions here on a normal delivery branch; once a composition merges, the orchestrator's render loop tars this directory and POSTs it to the `remotion-renderer` sidecar (T1 rewrote its render core to `@hyperframes/producer`), which renders the HTML to MP4 with Chromium. This package never renders itself — its own gate (`pnpm test`) is static: a vitest HTML-structure smoke against the authored files. The render-truth check happens on the sidecar, against the merged files. In-repo [HyperFrames](https://github.com/heygen-com/hyperframes) composition package. UX/UI devs author bespoke marketing-video compositions here on a normal delivery branch; once a composition merges, the orchestrator's render loop tars this directory and POSTs it to the `video-renderer` sidecar (T1 rewrote its render core to `@hyperframes/producer`), which renders the HTML to MP4 with Chromium. This package never renders itself — its own gate (`pnpm test`) is static: a vitest HTML-structure smoke against the authored files. The render-truth check happens on the sidecar, against the merged files.
## Adding a composition ## Adding a composition
@@ -1,5 +1,5 @@
{ {
"name": "remotion-renderer", "name": "video-renderer",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"packageManager": "pnpm@11.10.0", "packageManager": "pnpm@11.10.0",