Local-first CLI that turns a folder of images into a short story video. Follow the interactive prompts in your terminal and it renders video.mp4 locally with Remotion.
Current architecture in one line: Tabby -> StoryBrief -> Ocelot (Creative Director) -> Kitten/Cub -> Remotion.
Duration rule: final video length is driven by musicIntent.durationMs in creative-plan.json (not a fixed 30s).
- Node.js >= 20
- A Chromium-based browser (Chrome / Edge / Arc / Brave)
fluidsynthcommand available inPATH(for MIDI -> WAV synthesis)- A SoundFont (
.sf2) file; project default recommendation isSGM-V2.01
Standard SoundFont for this project: SGM-V2.01.sf2.
Install fluidsynth:
- macOS (Homebrew):
brew install fluid-synth - Ubuntu/Debia
9BF2
n:
sudo apt install fluidsynth - Windows (Chocolatey):
choco install fluidsynth(or install manually and add it toPATH)
Download SGM-V2.01.sf2 (example path):
mkdir -p "$HOME/.local/share/soundfonts"
curl -L "https://archive.org/download/SGM-V2.01/SGM-V2.01.sf2" -o "$HOME/.local/share/soundfonts/SGM-V2.01.sf2"Set environment variable:
export LIHUACAT_SOUNDFONT_PATH="$HOME/.local/share/soundfonts/SGM-V2.01.sf2"Persist it (zsh):
echo 'export LIHUACAT_SOUNDFONT_PATH="$HOME/.local/share/soundfonts/SGM-V2.01.sf2"' >> ~/.zshrc
source ~/.zshrcWindows PowerShell (example):
setx LIHUACAT_SOUNDFONT_PATH "C:\soundfonts\SGM-V2.01.sf2"Quick check:
fluidsynth --version- Use
pnpmfor repository development (pnpm install,pnpm test,pnpm run build). npm/yarninstall is blocked bypreinstallto keep lockfile and dependency resolution consistent.
- Install it globally (package:
@chiimagnus/lihuacat, command:lihuacat):
npm i -g @chiimagnus/lihuacat
# or
pnpm add -g @chiimagnus/lihuacat- Run it:
lihuacat- You’ll be guided through a few prompts (arrow keys + Enter), usually including:
- Source image directory (if you didn’t pass
--input) - Tabby chat: select 2–4 suggested options (or “free input”), then confirm / revise
Use flags to prefill prompts and skip steps:
--input <dir>: image directory (must be a single directory path)--browser-executable <path>: explicit browser executable path--model <name>: override Codex model name--model-reasoning-effort <minimal|low|medium|high|xhigh>: override reasoning effort
Defaults (when not provided):
- model:
gpt-5.1-codex-mini - reasoning effort:
medium
- Only scans the first level of
--input(non-recursive) - Only supports
jpg/jpeg/png - Maximum 20 images
- If the directory contains
webp/heic/heif/gif/bmp/tiff/avif, it errors as “unsupported format”
By default, outputs to: <inputDir>/lihuacat-output/<runId>/
Common artifacts:
video.mp4story-brief.jsoncreative-plan.jsonvisual-script.jsonreview-log.jsonmusic-json.jsonmusic.midmusic.wavrender-script.jsontabby-conversation.jsonlrun.log(anderror.logon failures)ocelot-input.json,ocelot-output.json,ocelot-prompt.log(debug)ocelot-revision-{N}.json(when creative review rounds occur)stages/round-{N}-kitten-visual-script.json,stages/round-{N}-cub-midi-json.json,stages/round-{N}-ocelot-review.json(per-round intermediate artifacts)
- Ocelot creative review loop has a max of 3 rounds; if still not approved, it records a warning and continues render with the latest version.
- Cub failure degrades to no-music render and records fallback reason in
review-log.json. - If SoundFont/
fluidsynthis missing, workflow degrades to no-music render and records warning inrun.log. - Other FluidSynth synthesis failures still exit the run with an error;
music.midis kept for debugging/retry.
If auto-detection fails, specify a browser executable path:
lihuacat --input /ABS/PATH/TO/PHOTOS --browser-executable "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"Source directory does not exist ...:--inputmust be a directory (not multiple file paths)Unsupported image format ...: unsupported images exist in the directory- Browser launch failed: install Chrome/Edge/Arc/Brave, or set
--browser-executable - StoryBrief / RenderScript generation failed: check Codex auth/model options, then inspect
error.log