What does Archival Film (档案影像) do?
Code-rendered story films built from real archival material. Every frame is computed (WebGL in headless Chrome, Python where it fits), so results are reproducible, captions are exact and every source is licence-checked. The user directs taste; references/style-canon.md holds everything they have asked for — read it first, it overrides your defaults.
Defaults (change only if the user asks)
Chinese, vertical 1080×1920, about 3 minutes + credits after the main cut. Narration on (Edge neural voice, deep male documentary tone, 1.2× — the user's range 1.1–1.25×) reading the captions. Music: one stock library track for the whole film, credits included. Delivery = MP4 + designed cover + Douyin and Xiaohongshu copy. Memory: all render/capture/model processes together use at most a quarter of RAM (8 GB → 2 GB). Slower is fine.
Setup (once per machine, then once per film)
sh scripts/setup.sh→~/.cache/archival-film/: a Python 3.11 venv ($AF/py: numpy, pillow, onnxruntime, edge-tts), the depth model, the typewriter recording, node packages for WebGL. It lives outside project folders, so cleaning a project never breaks the tools. Fonts:PROJECT=~/.cache/archival-film/assets sh scripts/fetch_fonts.sh classic.sh scripts/new_project.sh <dir>→ project folder withplates/ depth/ music/ sfx/ footage/ out/ prev/ web/, linked fonts/typewriter/node_modules, the web kit and afilm.pytemplate. Run scripts asPROJECT=<dir> FILM=film $AF/py <skill>/scripts/<script>.py ….
Quick test mode
When the user asks for a short trial ("随便做个10s试试", a sample, a test of the skill), skip the four checkpoints, keep everything else (real material, facts, narration, sound, the look), and say in the delivery which choices you made on their behalf. A worked 10 s example is templates/film_collage_example.py (+ templates/cuts_example.json).
Workflow — with the user's four checkpoints
- Brief — topic, length, any constraints. For a remake, list everything earlier versions used and avoid it all (
references/narrative.md§ Remakes). - Facts and material — sourced fact list; find and download material with licences (
references/sourcing.md,scripts/cands.py,scripts/fetch_commons.py); footage and restoration if useful (references/enhancement.md); depth maps (scripts/depth.py); contact sheets with grid ticks. - Script — design it like a marketer for a stranger (
references/narrative.md): premise with a contradiction in the first 3 s, an open question paid off at the end, anchors for unknown names/places, a viewer stand-in, escalation every 20–30 s, captions written to be read aloud within the speech budget (references/narration.md). → Checkpoint 1: script. Show the full caption text, the hook, the open question and the planned title/cover promise. Wait for approval before any picture work. - Music, palette, look, voice — propose 2–3 looks from
references/style-menu.mdfitted to the subject, a bold simple palette (1–2 strong colours per era + black + paper; show it on a real rough still, not only as swatches), one stock library track for the whole film, found online (Kevin MacLeod / FMA / CC0 —references/audio.md; classical only if the user wants period music; never a change of song between sections — "全局用一个bgm") with a mood/drive that fits (measure withscripts/beats.py; brisk for business/tech), and voice auditions (scripts/narrate.py --audition). → Checkpoint 2: music + palette (+ look and voice). - Timing — fit the one track with
Kit.music_bed()(→scripts/music_edit.py); generate narration (scripts/narrate.py), fix every overrun it reports, sync typing to the voice (apply_narration); place cuts and hits on the music's onsets. - Pictures — by default a collage animation (剪报画), read
references/collage.md: cut the material into pieces withscripts/cutout.py(scissor-cut figures, torn clippings, real headlines, map regions), animate the pieces — never the camera — asCOLLAGEin film.py (keyframes, print looks photo/halftone/spot/fill/ink/color, tear, grow, jolt, wobble), export withscripts/export_web.py, render withweb/collage.js. One spot colour with meaning, never a uniform sepia. Add other techniques where they fit (references/style-menu.mdpalette; shatter and dot assembly inweb/example_opening.js, Python print looks inreferences/looks.md). The continuous-cameraweb/journey.jswas rejected as a default (references/webgl.md). Colourization only as a B&W→colour effect, credited. Write it withscripts/collage_kit.py(captions from the voice, pieces landing on beats, stacking by arrival). Or make the film from the modern effect modules (web/fx.js,references/fx.md): dot morph, wirephoto, darkroom, kinetic type, investigation board, footage montage + woodcut rotoscope, ink fluid, pixel sort, point cloud, character portrait, plusholdand SVG guide marks. First write the shot list — per line: the one subject to see, where, the cue word (Kit.W), how the effect leads the eye there, and why this effect means the line; no meaning → ahold. The effect peaks on the cue word and resolves into a clean subject ("特效要有明确的视觉引导,而不是堆砌素材"). Write it withscripts/fx_plan.py→Kit.fx_cuts(), check every frame withscripts/fx_sheet.py(isseethe first thing you see?) before rendering. Offer it at checkpoint 2 next to the collage for modern / business / tech subjects. → Checkpoint 3: stills / sample. Send a contact sheet of key stills and a 10–20 s sample with sound — or the whole film as a rough cut (scripts/rough.py, ~150 MB) when memory is tight or the user wants to see it all. - Sound — every effect is a real recording found online with
scripts/fetch_sfx.py(Commons, Internet Archive 78s and field recordings, Freesound with a key; licence recorded, auto-trimmed intosfx/bank.json). Dense design:Kit.sfx_events()puts a paper slap/slam/rip on every landing and tear (Kit.fx_sfx_events()does the same for effect films: whoosh, radiofax, pour/slosh, projector, glitch, wind, keys); add ambience beds per section and diegetic sounds; period voices from PD records (references/audio.md,scripts/sfx_build.py). → Checkpoint 4: sound list. Send the list of effects and period voices with times and sources before the final render. - Render and mix —
scripts/run_chunks.py(memory budget, broken chunks re-run), concat, thenscripts/mixdown.py --voice …(voice-ducked, −14 LUFS / −1 dBTP). - Deliver — verify (
references/verification.md), then send the MP4, the cover and the platform copy (references/platform-copy.md); a 720p preview under 30 MB if the user follows from a phone.
What matters most to this user (short form; reasons in style-canon.md)
- Real archival material only; code effects act on it. No modelled objects, no self-drawn emblems.
- A clear story for a stranger; small people vs. the big event shown by facts, never preached; no AI slogans; big typographic words come from the sources.
- Animator's thinking: the pieces move, not the camera (fly-throughs were "烂完了"); cut material like a newspaper collage; no zoom-then-cut; no full-frame colour flashes as transitions.
- Strong colour emphasis with meaning — never one uniform sepia/yellow over everything; use the effects for real.
- Every shot has one subject the effect leads the eye to, on the word that names it — effects as the verb of the line, never for their own sake or to pile up material; plain holds between them. SVG only for guide marks, never to draw pictures.
- Rich, impressive effects — but not fussy, refined ornament ("太精致" was rejected). Avant-garde over decorative.
- One generic stock background track for the whole film (CC BY / CC0, found online) whose mood fits — classical felt "怪"; narration 1.1–1.25×; no "ding"; typewriter per typed character, no bell; dense real sound.
- Captions complete and held until the next line; palette bold and simple; later pieces on top.
- Captions on solid slabs, readable on a phone; one strong theme colour; credits after the main cut.
- Remakes share nothing with earlier versions (
scripts/overlap_check.py).
Files
scripts/— picture:render_print.py anim.py futur.py captions.py cjkwrap.py base.py cfg.py; material:cands.py fetch_commons.py fetch_ia.py depth.py cutout.py fetch_fonts.sh; collage / effect films:collage_kit.py fx_plan.py fx_sheet.py rough.py; audio:fetch_sfx.py beats.py onsets.py music_edit.py narrate.py sfx_build.py mixdown.py; WebGL bridge:export_web.py; render:run_chunks.py; checks:contact.py grid.py overlap_check.py; environment:setup.sh new_project.sh.web/—index.html(loads?scene=NAME),fx.js+fx/*.js(modern effect modules,fx/hold.jsplain picture,fx/guide.jsSVG guide marks),collage.js(the default cut-out animation scene, driven by out/timeline.json),captions.js(shared caption slabs),journey.js(continuous-camera scene, rejected as default),example_opening.js(older hand-built scene: shatter, dot field — reuse its effects, not its cuts/flashes),capture.mjs(deterministic capture),package.json.templates/film_template.py— the film module format (shots, captions, print spec, sound events, credits);templates/film_collage_example.py+cuts_example.json— a complete 10 s collage film (San Francisco 1906);templates/film_journey_example.py— the older journey version of it.references/— style-canon, narrative, narration, style-menu, collage, looks, webgl, audio, sourcing, enhancement, platform-copy, verification, known-gaps (open items for the next patch rounds).