Skip to content

Repository files navigation

demoflow

Screenshots in, a launch film out. Drop #011 of Openware · replaces Clueso.

Describe your product, drop in a few screenshots, and flowy writes the script against your own model, animates it into a beat-locked motion-graphics film, and renders the 1080p MP4 on your machine. No account, no credits, no export minutes, no watermark.

cp .env.example .env   # add a model, or leave it and use the built-in outline
docker compose up
# http://localhost:4327

What this doesn't do

Read this part first.

  • The render engine is Remotion, which is source-available, not MIT. It is free for individuals, non-profits, and for-profit companies with up to 3 employees. A larger for-profit needs a company licence from Remotion. flowy's own code is MIT; the engine underneath it is not, and no amount of self-hosting changes that. It is the one place in this repo where the thing you cloned still has a pricing page behind it. Everything else here — the script, the score, the type, the render — is yours.
  • 16:9 only. No vertical, no square. The engine's board grammar is composed for a wide frame and would need real work, not a config flag, to do anything else.
  • It does not record your screen. You bring screenshots; it makes motion graphics out of them. If you want a cursor moving through your product, this is the wrong tool.
  • There is no narration. Films are scored, not spoken. The engine has the timing machinery for per-scene voiceover — audio-plan already ducks the music around it — but nothing in this drop produces the audio, and shipping an untested integration against a paid API I could not exercise would be worse than saying so. The script the model writes still contains the spoken lines, so wiring a voice in later is a route and a file, not a redesign.
  • Rendering is CPU-bound, and slower in Docker than you will expect. Measured on a 12-core M-series Mac: a 32.6-second film in 83 seconds natively and 195 seconds in the container — Docker on macOS runs this workload about two and a half times slower than the host. There is no queue to wait behind, but there is no render farm either. Native is npm run dev.
  • The three background worlds and the stock stills are fixed assets. flowy composes and scores your film; it does not generate new footage.
  • One render at a time, and a restart loses the one in flight. The queue lives in the web process, because a queue that needs its own service is a second command. An interrupted render is marked failed on the next boot rather than left spinning.

What it does

  • Your model writes the script. One call, over the same LLM_BASE_URL / LLM_MODEL / LLM_API_KEY contract every drop in this repo uses. Ollama, OpenRouter, Groq, Cerebras, anything OpenAI-compatible.
  • Or nothing does. The built-in outline builds a complete, usable script from the brief alone, with no model involved. It is a button you press on purpose, not a degraded mode you get silently when a key is wrong.
  • A real film, not a slideshow. Beat-locked cuts, camera moves, morph carries between boards, kinetic type, a screenshot collage cold open, and a stat scene that counts up to its number with the digits grouped, so a million reads as 1 000 000 while it rolls rather than as a wall of zeroes. Write the stat as 1,000,000, not 1M1M parses as the number one with an "M" after it, and counting from zero to one looks static.
  • Pace is a dial. film.pace multiplies every board's length: 1 is the composed pacing, 0.55 is a hard cut roughly every 1.8 seconds, which is what a vertical feed wants. The end card's floor scales with it — at the composed pacing it was 40% of a ten-second cut. Accents are clamped back inside their board, so shortening one never fires a bloom over the next.
  • An original score. Two tracks, composed offline by npm run synth:tracks — supersaw pads, sidechain pump, drum bus, ping-pong plucks, Schroeder reverb — at an exact 118 BPM. The film's beat grid is derived from the track, so every cut lands on the music rather than near it.
  • Live preview before you render. The browser plays the actual composition, fully animated, at full quality. Editing a scene changes the preview immediately. The MP4 is the same thing, encoded.
  • Everything on disk. One data/ directory: the database, your screenshots, your renders. Back it up by copying a folder.

Configuration

demoflow reads .env beside the compose file. All of it is optional.

Variable Default What it does
LLM_BASE_URL http://localhost:11434/v1 Any OpenAI-compatible endpoint
LLM_MODEL qwen2.5-coder:7b The model that writes the script
LLM_API_KEY Empty for a local model
RENDER_CONCURRENCY 2 in Docker, Remotion's choice otherwise Frames rendered at once
RENDER_TIMEOUT_MS 600000 Ceiling on one render step. A deadlock bound, not a budget

With no model configured at all, the health strip on the home page says so in the words you would need to fix it, and the outline button still produces a film.

Running it without Docker

npm install
npm run dev        # http://localhost:4327
npm test           # 76 tests
npm run studio     # Remotion Studio, for working on the engine itself

The first render outside Docker builds the composition bundle once (about twenty seconds) and caches it in data/bundle. The container builds it into the image instead, so a containerised render never pays for it.


How it fits together

Piece Where Note
The film engine src/remotion/film/ Beat grid, board plan, camera, transitions, stations. Pure TypeScript, 42 tests, no React in the planners
Script writing src/lib/script.ts Model or outline. Scene durations are computed in code — a language model asked for frame counts returns a film that is eight seconds or four minutes long
Rendering src/lib/render.ts · src/lib/queue.ts @remotion/renderer in-process, one at a time
Storage src/lib/store.ts SQLite, three tables, no user_id on anything
Typography public/fonts/ Self-hosted. See below

The fonts are in the repo on purpose

The engine used to load Poppins, Geist, Inter and Instrument Serif through @remotion/google-fonts, which ships no font files at all — it injects @font-face rules pointing at fonts.gstatic.com, 54 of them for Poppins alone. Every render fetched its typography from Google, and on a machine with no route to the internet the film rendered in fallback system fonts without failing, because a render resolves whether or not the font arrived. The only symptom was that the type looked wrong.

All five families are now committed as woff2, latin subset, 220 KB total, under the SIL Open Font License. next/font/local serves the app chrome from the same files, so the build does not need the network either.

The film goes one step further and embeds its eight faces as data URIs (font-data.ts, regenerate with npx tsx scripts/inline-fonts.ts). Remotion keeps more browser pages open than it renders with, Chrome throttles resource loading in a page that is not in the foreground, and an idle page would start eight font requests and finish none of them — holding a delayRender handle open until it aged past the timeout and killed a render that was otherwise going perfectly. Nothing to fetch, nothing to stall.


Credits

Built on Remotion — see the licence note at the top. The score is synthesized by scripts/compose-tracks.ts. The three background loops and the stock stills were generated for this project; provenance is in public/film/README.md. Fonts are OFL — see public/fonts/LICENSE.md.

flowy's own code is MIT.

About

Screenshots in, a scored 1080p launch film out, rendered on your machine. Drop #011 of Openware — replaces Clueso.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages