- Python 86.4%
- JavaScript 7.1%
- HTML 4.3%
- Just 1.5%
- Dockerfile 0.4%
- Other 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| app | ||
| deploy | ||
| docs | ||
| performance-reports | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| Dockerfile | ||
| justfile | ||
| mise.toml | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
Brainrot — Article Cinema
Working local prototype for brainrot.waylonwalker.com. Turn an article into a Kokoro-narrated 9:16 MP4 with precisely timed captions, regular gameplay cuts, and subtle zoom on every shot. Anyone can watch the public infinite-scroll feed. Creators log in to submit articles and render videos; each finished video appears in the feed automatically.
One-command local run
Requires mise and just installed. From the extracted project directory:
just dev
Open http://127.0.0.1:8018. Public feed works without login. Select Create → Log in, developer password dev, to access the creator studio. This local development password works only when BRAINROT_DEV_MODE=1; never expose just dev to the network. The first just dev installs dependencies via mise/uv, including the spaCy English model required by Kokoro. First real narration may download Kokoro model weights; subsequent renders reuse its cache. A pip-managed espeakng-loader supplies the native shared library when possible; if your local Kokoro installation still reports an eSpeak error, install espeak-ng with pacman as a fallback.
If you just want to inspect the UI without installing Kokoro, use just dev-light (real article renders require the tts extra). just check runs the full local gate; just test and just render-smoke are available for focused checks.
mise.toml selects Python 3.14, uv, just and FFmpeg via conda:ffmpeg so just calls mise exec for all needed tools. FFmpeg requires support for libx264, zoompan and libass. If your conda build omits a codec/filter, use a system FFmpeg build with those capabilities and remove the conda tool line. The supported Python range is Python 3.14 only; uv.lock pins the complete runtime and development dependency set.
Getting real Dropper footage
No PAT is packaged in this ZIP. The app automatically looks for Dropper's existing production PAT at:
~/git/dropper/.dropper-auth/dropper-prod.pat
Or set DROPPER_PAT_FILE=... in .env (copy .env.example to .env). The game picker uses Dropper's authenticated GET /api/games index when available, then checks each title's paginated /api/games/{title}/media results and only shows titles with media_kind: video; displayed counts are video counts, so image-only titles do not appear. Older Dropper deployments fall back to grouping video results from GET /api/media/search?q=type:video by metadata_summary.game. Imports use the result's original file_url after checking it stays on Dropper and matches the selected filename. category is the broad value gaming; it does not represent a genre. Legacy Minecraft, Silksong, and skateboarding choices remain available while Dropper metadata is being populated. Videos without game metadata are not guessed into a title. Use manual uploads to fill the gaps.
Usage: On the first article render, Brainrot attempts to import up to three matching clips if a Dropper PAT is available. To curate the footage, choose a game in the studio → Browse Dropper → Import. Set AUTO_DROPPER_IMPORT=0 in .env to turn off automatic imports. Media is cached in .data/footage/{game}/. You may also upload clips or copy owned MP4/WebM files into that directory. Use only recordings/footage you have the rights to reuse. Rendering requires real gameplay footage; without it, the job fails and asks you to import clips or connect Dropper.
Render behavior
- By default, takes up to ~110 words from consecutive extracted article sections; choose starting section and word budget in the creator form.
- Synthesizes only selected sections; rest of the article is not queued for TTS.
- Uses Kokoro
result.tokens[*].start_ts/end_tsalready implemented in Listen, so no WhisperX or GPU alignment step. - Merges 24 kHz mono WAV sections and offsets their word timings by the actual segment durations. Each paragraph boundary adds a brief 0.1 s pause.
- FFmpeg holds gameplay shots for about 12–18 s. Jump cut style skips a randomized 1–2 s from the middle of each shot, then resumes the same clip with no zoom. Punch style cuts to a 1.5× crop. Neither style uses continuous camera drift. It alternates among available clips and resumes each clip at its next unused frame, so longer gameplay events can continue across later shots without repeating footage. A job fails clearly if its available gameplay is too short to cover the narration without reuse.
- Burns active-word-only captions into a vertical H.264/AAC MP4. Article title and author stay in video metadata and the public viewer HUD; the renderer removes a repeated article title from the narration opening when possible. Source URL is embedded in MP4 metadata and attached in the public viewer, where it remains clickable.
- Outputs to
.data/videos/{id}.mp4and{id}.words.json. One queued FFmpeg job at a time. - Finished videos are public automatically and appear in the feed. Login is required to submit an article or request a render.
The public feed contains ready, published videos, including RSS imports. The bundled demo-footage.mp4 remains a sample asset; the render smoke check generates time-varying synthetic footage to verify unique source ranges.
Public video lookup API
GET https://brainrot.waylonwalker.com/api/lookup?url={article-url} checks for a ready, public Brainrot video and supports cross-origin browser requests. It ignores fragments, trailing slashes, common tracking parameters, and URL scheme or www differences. If a query string does not match exactly, it only ignores it when the base URL identifies one stored article, so distinct query-selected articles are not confused.
{
"found": true,
"match": "query_ignored",
"video": {
"id": "…",
"title": "…",
"source_url": "https://example.com/article",
"url": "https://brainrot.waylonwalker.com/api/videos/…/media",
"media_url": "https://brainrot.waylonwalker.com/api/videos/…/media",
"poster_url": "https://brainrot.waylonwalker.com/api/videos/…/poster"
}
}
When no matching public video is ready, the API returns {"found": false, "video": null}. The media URL can be linked directly from an RSS reader or another site.
Useful commands
just dev # complete localhost app, real Kokoro engine
just dev-light # UI, feed, extraction only — TTS extra not installed
just test # unit/API tests
just check # tests, Ruff lint + format, and strict ty checks
just format # apply Ruff's safe fixes and formatting
just render-smoke # real FFmpeg output with synthetic WAV + word timing fixture
just doctor # dependency info
just clips # currently imported gameplay videos
Homelab deployment
The app has an Argo-ready Helm chart in deploy/helm and a child Application in deploy/argo-application.yaml. Production keeps the feed and finished videos public; creator endpoints use Hlab Auth with the brainrot:create scope. Traefik strips incoming X-Hlab-* headers, applies ForwardAuth to creator routes, and a NetworkPolicy only allows Traefik to reach the pod.
To prepare the GitOps checkout:
- Commit the app changes, authenticate to
registry.wayl.one, and runjust publish. Record the printed image tag. - Copy
deploy/helmto~/git/homelab-argo/k8s/brainrot/helm-chart, copydeploy/argo-application.yamlto~/git/homelab-argo/argo-apps/apps/brainrot.yaml, and set the published image tag in the chart values. - Register
brainrot.waylonwalker.comand thebrainrot:createscope in Hlab Auth. - Commit and push
homelab-argo, then verify the Brainrot Argo Application is synced and healthy before checkinghttps://brainrot.waylonwalker.com.
The chart runs one replica because SQLite and the render worker share /data. Its default 100 GiB longhorn-backup PVC holds the database, uploaded footage, renders, and Kokoro model cache. Monitor capacity as videos accumulate; the app currently uses local filesystem storage only. A missing optional brainrot-dropper Secret disables automatic Dropper imports, but creators can upload footage in the studio.
Production deployment still needs backups and a retention plan before the media library grows. Crediting an author and linking to the article do not grant republication rights; Minecraft footage is subject to its usage guidelines.
Background music
Brainrot's original music is dedicated to the public domain under CC0. The studio offers one 8-bit loop, ambient, lo-fi, synthwave, and cinematic styles, with a 10-second preview for each preset. Previous videos can still render with the older 8-bit selections. Regenerate the generated loops with python scripts/generate_music_presets.py and python scripts/generate_generic_music.py.
Known limits: Localhost dev has only one creator identity; no online video hosting/CDN integration, multiuser account separation beyond identity strings, editing subtitles, or automatic rights verification; extraction inherits Listen's known DNS-rebinding caveat; long articles generate one section range per requested video (multi-part orchestration remains future work). Kokoro's word timing is model-predicted and may differ a little from audible boundaries.