{"_id":"@45ck/content-machine","name":"@45ck/content-machine","dist-tags":{"latest":"0.2.2"},"versions":{"0.2.2":{"name":"@45ck/content-machine","version":"0.2.2","description":"CLI-first automated short-form video generator for TikTok, Reels, and Shorts","license":"MIT","type":"module","main":"dist/index.js","types":"dist/index.d.ts","bin":{"cm":"dist/cli/index.cjs"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"build":"npm run build:cli && npm run build:lib && npm run build:lib:cjs","build:cli":"esbuild src/cli/index.ts --bundle --platform=node --format=cjs --packages=external --log-override:empty-import-meta=silent --outfile=dist/cli/index.cjs","build:lib":"esbuild src/index.ts --bundle --platform=node --format=esm --packages=external --log-override:empty-import-meta=silent --sourcemap --outfile=dist/index.js","build:lib:cjs":"esbuild src/index.ts --bundle --platform=node --format=cjs --packages=external --log-override:empty-import-meta=silent --sourcemap --outfile=dist/index.cjs","build:types":"tsc -p tsconfig.build.json --emitDeclarationOnly","dev":"tsx watch src/cli/index.ts","cm":"tsx src/cli/index.ts","glossary:gen":"node scripts/gen-glossary.mjs","glossary:check":"node scripts/quality/check-ubiquitous-language.mjs","ul:gen":"node scripts/gen-ubiquitous-language-ts.mjs","repo-facts:gen":"scripts/quality/with-node20.sh node scripts/gen-repo-facts.mjs","repo-facts:check":"scripts/quality/with-node20.sh node scripts/quality/check-repo-facts.mjs","prompts:check":"scripts/quality/with-node20.sh node scripts/quality/check-prompts.mjs","docs:lint":"scripts/quality/with-node20.sh node scripts/quality/docs-lint.mjs","docs:linkcheck":"scripts/quality/with-node20.sh node scripts/quality/check-doc-links.mjs","docs:check":"npm run docs:lint && npm run docs:linkcheck","cspell:gen":"node scripts/gen-cspell.mjs","cspell:check":"scripts/quality/with-node20.sh npx --no-install cspell lint --config cspell.json --no-progress README.md docs/reference/**/*.md docs/README.md src/cli/**/*.{ts,tsx,js,mjs,cjs}","test":"vitest","test:run":"vitest run","test:coverage":"scripts/quality/with-node20.sh sh -c \"node scripts/quality/clean-coverage.mjs && CM_COVERAGE_SINGLE_WORKER=1 scripts/quality/vitest-coverage-retry.sh\"","test:coverage:push":"scripts/quality/with-node20.sh sh -c \"node scripts/quality/clean-coverage.mjs && CM_COVERAGE_SINGLE_WORKER=1 scripts/quality/vitest-coverage-retry.sh --exclude tests/vv/**/*.visual.test.ts --exclude tests/e2e/**/*.playwright.test.ts\"","mutation":"stryker run","mutation:node20":"npx -y node@20.18.1 ./node_modules/.bin/stryker run","lint":"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix","format":"prettier . --write","format:check":"prettier . --check","typecheck":"tsc --noEmit","dup:check":"jscpd --config .jscpd.json","quality":"npm run glossary:check && npm run repo-facts:check && npm run prompts:check && npm run cspell:check && npm run docs:check && npm run typecheck && npm run lint && npm run format:check && npm run test:coverage && npm run dup:check","quality:push":"npm run glossary:check && npm run repo-facts:check && npm run prompts:check && npm run cspell:check && npm run docs:check && npm run typecheck && npm run lint && npm run format:check && npm run test:coverage:push && npm run dup:check","quality:full":"npm run quality && npm run mutation","size":"size-limit","size:check":"size-limit --json","docs":"typedoc","docs:watch":"typedoc --watch","eval":"npx promptfoo eval","eval:script":"npx promptfoo eval -c evals/configs/cm-script.yaml","prepack":"npm run build && npm run build:types","prepublishOnly":"npm run build && npm run build:types","prepare":"husky || true"},"dependencies":{"@anthropic-ai/sdk":"^0.71.2","@google/generative-ai":"^0.24.1","@iarna/toml":"^3.0.0","@remotion/animation-utils":"^4.0.402","@remotion/bundler":"^4.0.0","@remotion/captions":"^4.0.402","@remotion/cli":"^4.0.0","@remotion/install-whisper-cpp":"^4.0.399","@remotion/layout-utils":"^4.0.402","@remotion/player":"^4.0.0","@remotion/renderer":"^4.0.0","@tavily/core":"^0.6.4","adm-zip":"^0.5.16","boxen":"^7.1.1","chalk":"^5.3.0","commander":"^14.0.2","dotenv":"^17.2.3","fastmcp":"^3.30.0","inquirer":"^13.1.0","kokoro-js":"^1.2.1","mustache":"^4.2.0","openai":"^4.77.0","ora":"^9.0.0","pexels":"^1.4.0","pino":"^10.1.1","pino-pretty":"^13.1.3","react":"^18.2.0","react-dom":"^18.2.0","remotion":"^4.0.0","tesseract.js":"^7.0.0","yaml":"^2.4.0","zod":"^3.23.0"},"overrides":{"esbuild":"0.27.2"},"devDependencies":{"@eslint/js":"^9.39.2","@size-limit/file":"^12.0.0","@stryker-mutator/core":"^9.5.1","@types/adm-zip":"^0.5.7","@types/inquirer":"^9.0.0","@types/mustache":"^4.2.0","@types/node":"^25.0.6","@types/react":"^18.2.0","@typescript-eslint/eslint-plugin":"^8.52.0","@typescript-eslint/parser":"^8.51.0","@vitest/coverage-istanbul":"^2.1.9","@vitest/coverage-v8":"^2.1.9","cspell":"^9.2.0","esbuild":"0.27.2","eslint":"^9.0.0","eslint-plugin-jsdoc":"^50.8.0","eslint-plugin-sonarjs":"^3.0.5","globals":"^17.0.0","husky":"^9.1.7","jscpd":"^4.0.5","lint-staged":"^16.2.7","markdownlint-cli2":"^0.18.1","msw":"^2.0.0","playwright":"^1.58.2","pngjs":"^7.0.0","prettier":"^3.7.4","promptfoo":"^0.120.11","size-limit":"^12.0.0","tsx":"^4.19.0","typedoc":"^0.28.15","typescript":"^5.7.0","vitest":"^2.0.0"},"engines":{"node":">=20"},"packageManager":"npm@10.8.2","repository":{"type":"git","url":"git+https://github.com/45ck/content-machine.git"},"homepage":"https://github.com/45ck/content-machine#readme","bugs":{"url":"https://github.com/45ck/content-machine/issues"},"publishConfig":{"access":"public"},"keywords":["video-generation","short-form","tiktok","reels","shorts","remotion","automation","content-creation","cli"],"lint-staged":{"registry/repo-facts.yaml":["node scripts/quality/lintstaged-repo-facts-gen.mjs"],"*.{ts,tsx}":["eslint --cache --cache-location .cache/eslint/ --max-warnings 0 --fix","prettier --write"],"*.{json,md,yml,yaml}":["prettier --write"]},"size-limit":[{"path":"dist/cli/index.cjs","limit":"5 MB"}],"_id":"@45ck/content-machine@0.2.2","gitHead":"3864c13eb9d5079253bc704666d60ff66d14e7e1","_nodeVersion":"18.20.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-AwqH+DDaNfge/cO+vF+ENnr1GH/1U8bGeIvOoqgSPN46ELt7tG4Bm7vp0eiHusrHLIBjOKsM5WW4EHJp5euMOw==","shasum":"a6168c63e32682c4018de93a8c3ea0ef9e2d5c57","tarball":"https://registry.npmjs.org/@45ck/content-machine/-/content-machine-0.2.2.tgz","fileCount":334,"unpackedSize":6087821,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFq52i1WWx8wYyhOwQVzTaVumOZcYYtdbkTHTHRh8fCaAiEApnTvo6QbiHCTIrwGBV5zCpDFMINfdJTFHKP6TLXvIGY="}]},"_npmUser":{"name":"45ck","email":"ajax@aquinus.net"},"directories":{},"maintainers":[{"name":"45ck","email":"ajax@aquinus.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/content-machine_0.2.2_1771109264993_0.7630266959427789"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-14T22:47:44.920Z","0.2.2":"2026-02-14T22:47:45.214Z","modified":"2026-02-14T22:47:45.474Z"},"maintainers":[{"name":"45ck","email":"ajax@aquinus.net"}],"description":"CLI-first automated short-form video generator for TikTok, Reels, and Shorts","homepage":"https://github.com/45ck/content-machine#readme","keywords":["video-generation","short-form","tiktok","reels","shorts","remotion","automation","content-creation","cli"],"repository":{"type":"git","url":"git+https://github.com/45ck/content-machine.git"},"bugs":{"url":"https://github.com/45ck/content-machine/issues"},"license":"MIT","readme":"# Content Machine\n\n[![CI](https://github.com/45ck/content-machine/actions/workflows/ci.yml/badge.svg)](https://github.com/45ck/content-machine/actions/workflows/ci.yml)\n![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)\n\nAutomated short-form video generation pipeline for TikTok, Reels, and Shorts.\n\n> **Status:** Early development. Not production-ready yet.\n\n![Content Machine pipeline](assets/demo/pipeline-preview.svg)\n\n## Demo videos\n\nGitHub READMEs can’t reliably inline-play `mp4`, so this repo uses small previews (GIF/SVG)\nand links to full videos hosted elsewhere (GitHub Releases / YouTube / Vimeo).\n\n- Demo hosting: https://github.com/45ck/content-machine/releases\n- Guide: [docs/guides/guide-demo-media-20260111.md](docs/guides/guide-demo-media-20260111.md)\n\n### Demo 1: Split-screen gameplay + content (brainrot template)\n\n![Split-screen gameplay + content demo](assets/demo/demo-1-split-screen.gif)\n\nShows:\n\n- Split-screen gameplay template with **Minecraft** (top) + **Subway Surfers** (bottom)\n- `cm import visuals` to bring your own clips\n- Gameplay slot selection (`--gameplay-style subway-surfers`)\n- `cm render --template brainrot-split-gameplay-top`\n\n### Demo 2: Subway Surfers-style gameplay with TikTok captions\n\n![Gameplay captions demo](assets/demo/demo-2-subway-captions.gif)\n\nShows:\n\n- Full-screen **Subway Surfers** gameplay with word-highlighted captions\n- `cm import visuals` + `cm render --template tiktok-captions`\n\n### Demo 3: Bring your own clips (no stock footage)\n\n![Import clips demo](assets/demo/demo-3-import-clips.gif)\n\nShows:\n\n- **Minecraft** clip imported via `cm import visuals`\n- `cm render --template tiktok-captions --caption-preset karaoke`\n\nNote: if you want _real_ gameplay (Subway Surfers / Minecraft parkour), you must supply your own\nclips with the appropriate rights in `~/.cm/assets/gameplay/<style>/`. This repo does not ship or\ndownload copyrighted gameplay footage by default. On Linux you can import clips with\n`scripts/download-gameplay.sh` (local files or URLs you have rights to).\n\n### Demo 4: Latest news listicle (TikTok captions + number badges)\n\n![Latest news listicle demo](assets/demo/demo-4-latest-news.gif)\n\nFull clip: `docs/demo/demo-4-latest-news.mp4`\n\nThis demo uses:\n\n- TikTok-style chunk captions (smaller default sizing)\n- Auto list-number badges (`#1`, `#2`, …) with fade/scale animation\n- List markers hidden in captions (so you don’t see `1:` in the text)\n\nReplicate the pipeline (exact commands):\n\n```bash\n# Node >= 20 recommended\nnvm use\n\n# (One-time) install deps + whisper for word-level timestamps\nnpm install\nnpm run cm -- setup whisper --model base\n\n# 1) Research latest headlines (Jan 2026 example query)\nnpm run cm -- --yes research --no-angles \\\n  -q \"Davos World Economic Forum Iraq US forces withdrawal North Korea official fired January 2026\" \\\n  -s tavily -t week -l 12 \\\n  -o output/research.stories.json\n\n# 2) Script (listicle)\nnpm run cm -- --yes script \\\n  --topic \"global news this week\" \\\n  --research output/research.stories.json \\\n  --duration 60 \\\n  -o output/script.stories.v2.json\n\n# 3) Audio + timestamps (audio-first + reconcile for cleaner captions)\nnpm run cm -- --yes audio \\\n  -i output/script.stories.v2.json \\\n  -o output/audio.stories.v2.wav \\\n  --timestamps output/timestamps.stories.v2.json \\\n  --sync-strategy audio-first --reconcile --require-whisper --whisper-model base \\\n  --tts-speed 1.2 \\\n  --no-music --no-sfx --no-ambience\n\n# 4) Visuals (Pexels)\nnpm run cm -- --yes visuals \\\n  -i output/timestamps.stories.v2.json \\\n  -o output/visuals.stories.v2.json \\\n  --provider pexels --orientation portrait\n\n# 5) Render (TikTok preset + chunk mode)\nnpm run cm -- --yes render \\\n  -i output/visuals.stories.v2.json \\\n  --audio output/audio.stories.v2.wav \\\n  --timestamps output/timestamps.stories.v2.json \\\n  --caption-preset tiktok --caption-mode chunk \\\n  --caption-offset-ms -80 \\\n  --hook none \\\n  -o output/global-news.stories.v2.tiktok-smaller.badges-back.mp4\n```\n\n## What is this?\n\nContent Machine is a CLI-first pipeline that transforms a topic into a short-form video in four stages:\n\n```\ntopic -> script.json -> audio.wav + timestamps.json -> visuals.json -> video.mp4\n```\n\n## Terminology\n\nThis repo has a few loaded words (template, workflow, archetype, preset, pack).\n\n- Canonical registry: `registry/ubiquitous-language.yaml`\n- Generated glossary: `docs/reference/GLOSSARY.md`\n- How it is enforced: `docs/reference/ubiquitous-language-system-20260210.md`\n\nRun the full pipeline with `cm generate` or run each stage independently.\n\n## Ubiquitous Language (Important)\n\nThese words mean specific things in this repo:\n\n- **Archetype**: script format (hook + structure + pacing rules). Used by `cm script` / `cm generate`.\n- **Template**: render template (Remotion composition + render defaults). Used by `cm render` / `cm generate`.\n- **Workflow**: pipeline orchestration preset (stage modes + defaults, optional exec hooks). Used by `cm generate`.\n\nFull glossary: `docs/reference/GLOSSARY.md`.\n\n**Key features:**\n\n- LLM script generation into scene-based `script.json`\n- Local TTS via kokoro-js with word-level timestamps from whisper.cpp\n- Visual matching to scenes with stock footage providers (Pexels/Pixabay)\n- Remotion rendering with word-highlighted captions\n- Import Remotion templates as **code templates** (`cm templates import ...`) with explicit opt-in (`--allow-template-code`)\n- CLI-first, stage-by-stage artifacts for iteration and CI\n- Custom asset imports and workflow definitions for marketing pipelines\n\n## Pipeline\n\n| Stage   | Command      | Input                                            | Output                         |\n| ------- | ------------ | ------------------------------------------------ | ------------------------------ |\n| script  | `cm script`  | topic string                                     | `script.json`                  |\n| audio   | `cm audio`   | `script.json`                                    | `audio.wav`, `timestamps.json` |\n| visuals | `cm visuals` | `timestamps.json`                                | `visuals.json`                 |\n| render  | `cm render`  | `visuals.json` + `audio.wav` + `timestamps.json` | `video.mp4`                    |\n\n`cm generate` runs the full pipeline in order.\n\n## Quick Start\n\n```bash\n# Clone\ngit clone https://github.com/45ck/content-machine.git\ncd content-machine\n\n# Prereqs\n# - Node.js >= 20 (recommended: use nvm + .nvmrc)\n# - (optional) ffmpeg (for making README demo GIFs)\n\n# Recommended Node setup (if you have nvm)\nnvm install\nnvm use\n\n# Install dependencies\nnpm install\n\n# Set up environment\ncp .env.example .env\n# Add your OPENAI_API_KEY\n\n# Note:\n# - In this repo: use `npm run cm -- <command>`\n# - If installed globally: use `cm <command>`\n\n# Run the full pipeline in dev mode\nnpm run cm -- generate \"Redis vs PostgreSQL for caching\" --archetype versus --output output/video.mp4 --keep-artifacts\n```\n\n## Recommended Video Pipeline (Default)\n\nFor best audio/caption sync, the default pipeline runs audio-first with Whisper timestamps\nand reconciles ASR output back to the script text.\n\n```bash\n# One-time Whisper setup (needed for audio-first)\nnpm run cm -- setup whisper --model base\n\n# Generate a short video with best-sync defaults\nnpm run cm -- generate \"Redis vs PostgreSQL for caching\" --archetype versus --output output/video.mp4 --keep-artifacts\n```\n\n## Research (Latest News → Script → Video)\n\n`cm research` gathers evidence across sources and writes `research.json`. You can then feed that\ninto `cm script` / `cm generate` to keep scripts grounded in the latest info.\n\n```bash\n# 1) Research (no API keys required: Hacker News + Reddit)\nnpm run cm -- research -q \"latest AI model news\" -s hackernews,reddit -t day -o research.json\n\n# 2) Generate a full video using that evidence\nnpm run cm -- generate \"latest AI model news\" --research research.json -a story --duration 35 -o output/news.mp4\n```\n\nAuto-research shortcut (runs Stage 0 automatically):\n\n```bash\n# Use `--research` with no value (or `--research true`).\n# Always uses hackernews,reddit; also adds web if BRAVE_SEARCH_API_KEY is set,\n# and adds tavily if TAVILY_API_KEY is set.\nnpm run cm -- generate \"latest AI model news\" --research -a story --duration 35 -o output/news.mp4\n```\n\n## Custom Assets and Workflows\n\nBring your own audio + clips and still use cm captions/rendering:\n\n```bash\n# 1) Generate timestamps from existing audio\ncm timestamps --audio assets/voiceover.wav --output output/timestamps.json\n\n# 2) Build visuals.json from local footage\ncm import visuals --timestamps output/timestamps.json --clips assets/clips --output output/visuals.json\n\n# 3) Render with your assets\ncm generate \"Launch teaser\" \\\n  --audio assets/voiceover.wav \\\n  --timestamps output/timestamps.json \\\n  --visuals output/visuals.json \\\n  --output output/video.mp4\n```\n\n## Import Remotion Templates (Code Templates)\n\nImport Remotion official/community templates (or any Remotion repo) into CM as a **code template**:\n\n```bash\ncm templates import https://www.remotion.dev/templates/tiktok --id remotion-tiktok\n\ncm render -i visuals.json --audio audio.wav --timestamps timestamps.json \\\n  --template remotion-tiktok --allow-template-code -o out/video.mp4\n```\n\nDocs:\n\n- `docs/guides/guide-remotion-template-import-20260210.md`\n- `docs/reference/cm-templates-reference-20260210.md`\n\nFor repeatable pipelines, define a workflow in `./.cm/workflows/<id>/workflow.json`:\n\n```bash\ncm workflows list\ncm generate \"Product recap\" --workflow acme-custom --workflow-allow-exec --output output/video.mp4\n```\n\n## Split-Screen Gameplay + Pexels (Brainrot Template)\n\nThis produces the same style as `output/demo-subway-pexels/video.mp4`: gameplay on one half,\nPexels B-roll on the other, CapCut-style captions, muted gameplay audio.\n\nPrereqs:\n\n- `.env` has `OPENAI_API_KEY` (keyword extraction) and `PEXELS_API_KEY` (stock footage).\n- Gameplay clips live in `~/.cm/assets/gameplay/<style>/` (or pass `--gameplay <path>`).\n\n```bash\n# 1) Prepare gameplay clips\nmkdir -p ~/.cm/assets/gameplay/subway-surfers\ncp /path/to/subway.mp4 ~/.cm/assets/gameplay/subway-surfers/\n\n# 2) Generate script + audio + timestamps\ncm script --topic \"Redis vs PostgreSQL for caching\" -o output/script.json\ncm audio --input output/script.json --output output/audio.wav --timestamps output/timestamps.json --tts-speed 1.2\n\n# 3) Match Pexels visuals + gameplay\ncm visuals --input output/timestamps.json --provider pexels --orientation portrait \\\n  --gameplay-style subway-surfers \\\n  --output output/demo-subway-pexels/visuals.json\n\n# 4) Render split-screen (gameplay on top, Pexels on bottom)\ncm render --template brainrot-split-gameplay-top --split-layout gameplay-top \\\n  --input output/demo-subway-pexels/visuals.json \\\n  --timestamps output/timestamps.json \\\n  --audio output/audio.wav \\\n  --output output/demo-subway-pexels/video.mp4 \\\n  --download-assets\n```\n\nLayout options:\n\n- Swap positions: `--split-layout gameplay-bottom`\n- Force full-screen: `--gameplay-position full` or `--content-position full`\n\nTroubleshooting:\n\n- If Remotion fails to decode a gameplay clip, transcode to H.264 baseline:\n  `ffmpeg -y -i input.mp4 -vf \"scale=1080:-2\" -c:v libx264 -profile:v baseline -level 3.1 -pix_fmt yuv420p -preset veryfast -crf 23 -an -movflags +faststart output.mp4`\n- For detailed logs: `--verbose` plus `REMOTION_LOG_LEVEL=verbose`\n\n## Vendored Dependencies\n\nThis repo vendors several open-source projects for video generation:\n\n```\nvendor/\n  remotion/              # React-based video composition\n  short-video-maker/     # Reference patterns for Pexels + Kokoro\n  open-deep-research/    # Deep research agent patterns\n  ...\n```\n\nSee [VENDORING.md](VENDORING.md) for details.\n\n## Configuration\n\n```bash\n# Required\nOPENAI_API_KEY=sk-...\n\n# Optional\nPEXELS_API_KEY=...         # For stock footage\nGEMINI_API_KEY=...         # For AI image generation (provider: nanobanana)\nGOOGLE_API_KEY=...         # Alias for GEMINI_API_KEY (either works)\nBRAVE_SEARCH_API_KEY=...   # For cm research --sources web\nTAVILY_API_KEY=...         # For cm research --sources tavily (and auto-research in cm generate)\nREDDIT_CLIENT_ID=...       # Optional (some Reddit features may use auth)\nREDDIT_CLIENT_SECRET=...   # Optional\n```\n\n### AI Images (Gemini)\n\nGenerate per-scene AI images as a first-class visuals provider (and animate them at render-time):\n\n```bash\ncm visuals --input timestamps.json --provider nanobanana --motion-strategy kenburns --output visuals.json\ncm render --input visuals.json --audio audio.wav --timestamps timestamps.json --output video.mp4\n```\n\n### Bring Your Own Visuals (Local)\n\nUse your own folder of clips/images as a visuals provider:\n\n```bash\n# Use local video clips (best-match by filename/folders)\ncm visuals --input timestamps.json --provider local --local-dir ./my-footage --output visuals.json\n\n# Use local images (requires a motion strategy at render-time)\ncm visuals --input timestamps.json --provider localimage --local-dir ./my-images --motion-strategy kenburns --output visuals.json\n```\n\nFor deterministic mapping (no fuzzy matching), provide a manifest mapping `sceneId -> assetPath`:\n\n```bash\ncm visuals --input timestamps.json --provider pexels --local-manifest ./visuals-manifest.json --output visuals.json\n```\n\n### Config Files\n\n- Project config (auto-discovered by walking up from `cwd`): `.content-machine.toml`, `content-machine.toml`, `.cmrc.json`\n- User config (optional): `~/.cm/config.toml`, `~/.cm/config.json`, `~/.cmrc.json`\n- Merge order: user first, then project (project wins)\n- Override: `CM_CONFIG=/abs/path/to/config.toml` or `cm --config /abs/path/to/config.toml ...`\n- Inspect: `cm config paths`, `cm config show`\n\n## Caption Fonts\n\nDefault captions use an Inter-first stack with Montserrat fallback. A small Inter font pack\nships in `assets/fonts/Inter` for consistent rendering.\n\nCLI overrides:\n\n```bash\ncm render --caption-font-family \"Inter\" \\\n  --caption-font-weight 700 \\\n  --caption-font-file \"assets/fonts/Inter/Inter-Bold.woff2\" \\\n  --input visuals.json --timestamps timestamps.json --audio audio.wav\n```\n\nConfig defaults (`.content-machine.toml`):\n\n```toml\n[captions]\nfont_family = \"Inter\"\nfont_weight = 700\nfont_file = \"assets/fonts/Inter/Inter-Bold.woff2\"\n```\n\nJSON config supports multiple fonts:\n\n```json\n{\n  \"captions\": {\n    \"fontFamily\": \"Inter\",\n    \"fontWeight\": 700,\n    \"fonts\": [\n      {\n        \"family\": \"Inter\",\n        \"src\": \"assets/fonts/Inter/Inter-Bold.woff2\",\n        \"weight\": 700\n      }\n    ]\n  }\n}\n```\n\n## Export-First Design\n\nContent Machine does **not** auto-publish to platforms. Instead, it generates a ZIP package:\n\n```\noutput/\n  2026-01-01-discord-bot-tutorial/\n    video.mp4\n    cover.jpg\n    metadata.json\n    upload-checklist.md    # Platform-specific instructions\n    platform-hints/\n      tiktok.md\n      reels.md\n      shorts.md\n```\n\n**Why?** TikTok/Instagram APIs require business verification and audit. Export-first means:\n\n- Works immediately (no API approvals needed)\n- Human reviews before publish\n- Can customize per-platform before upload\n\n## Project Structure\n\n```\nsrc/\n  cli/        # Commander.js entry points\n  script/     # Script generation pipeline\n  audio/      # TTS + ASR pipeline\n  visuals/    # Footage matching\n  render/     # Remotion integration\n  core/       # Shared infrastructure\n  prompts/    # Prompt templates\n  hooks/      # Hook selection helpers\n  package/    # Packaging outputs\n  publish/    # Publish/export helpers\n  research/   # Research command logic\n  score/      # Scoring pipeline\n  validate/   # Validation pipeline\n  types/      # Shared types\n  test/       # Test stubs/support\n  index.ts    # Package exports\n```\n\n## Roadmap\n\n- [ ] Core CLI pipeline (script/audio/visuals/render)\n- [ ] Remotion templates\n- [ ] Playwright capture scenarios\n- [ ] Review queue UI\n- [ ] Analytics dashboard\n- [ ] Trend MCP integration\n- [ ] Multi-platform scheduling\n\n## License\n\nMIT - See [LICENSE](LICENSE)\n\n## Contributing\n\nPRs welcome. Please read:\n\n- [CONTRIBUTING.md](CONTRIBUTING.md)\n- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)\n- [SECURITY.md](SECURITY.md)\n- [SUPPORT.md](SUPPORT.md)\n\n## Credits\n\nBuilt for [Vibecord](https://vibecord.dev) / [Vibeforge](https://vibeforge.dev).\n\nInspired by:\n\n- [Remotion](https://remotion.dev) - React video framework\n- [short-video-maker](https://github.com/gyuha/short-video-maker) - Reference patterns\n- [open-deep-research](https://github.com/langchain-ai/open_deep_research) - Research agent patterns\n","readmeFilename":"README.md","_rev":"1-e83c81dfc12614f584b3892deac75468"}