A local-first pipeline that fetches the daily Lichess puzzle, normalizes it, renders board frames, and builds a silent MP4 — all on disk, no upload.
This repository implements only Milestone 1: local file generation. A run
produces, under artifacts/YYYY-MM-DD/:
puzzle.json— raw puzzle JSON from Lichessmetadata.json— deterministic run metadataframes/frame_00000.png(and more) — rendered scene framesvideo.mp4— silent video assembled from the frames
- Python 3.11+
- FFmpeg on
PATH(or setffmpeg.binaryinconfig/app.json) - Python deps:
requests,chess(python-chess),Pillow,cairosvg
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]python -m src.main smoke-test
python -m src.main run --skip-upload
# regenerate everything, ignoring step markers:
python -m src.main run --skip-upload --force--skip-upload is the standard Milestone 1 run mode.
The fetch step normally calls https://lichess.org/api/puzzle/daily. For
offline or reproducible runs, point it at a local fixture:
LICHESS_PUZZLE_FIXTURE=tests/fixtures/daily_puzzle_sample.json \
python -m src.main run --skip-upload --force- fetch (
src/fetch_puzzle.py) — GET daily puzzle JSON; error on non-200; persist raw JSON. - normalize (
src/puzzle_model.py) — extractid,rating,themes,solution,fen; derive side to move; handlegame.perfas string or object. FEN resolution preferspuzzle.fen, thenraw.fen, thengame.fen. - render (
src/render_board.py) — render intro, think-time, solution, and outro scenes; board viachess.svg.board()+cairosvg, fit with no clipping, vertically centered below the header. - video (
src/build_video.py) — assemble a silent MP4 with FFmpeg using configured width/height/fps/codec/pixel format. - metadata (
src/metadata.py) — write deterministic run metadata.
State markers (src/state_manager.py) under artifacts/YYYY-MM-DD/.state/
provide rerun safety; --force clears them.
See config/app.json. Milestone 1 baseline: 1920×1080, 30 fps, board_size 740, coordinates on.
pytest -qLocal generation only. YouTube API, OAuth, token generation, and upload automation are intentionally out of scope for Milestone 1 and are not implemented or documented here.