1仕組みと動作原理
「すべての行がレシートである」:作中のすべてのテキストは創作されたものではなく、ユーザー自身のClaude Codeセッション履歴から抽出された逐語的な引用であり、レンダリング前にユーザーが1行ずつ確認・承認する必要があります。
Every line on screen is a receipt. The user approves each one before anything renders.
「普通の一日」はモデルの想像ではなく統計から導出される:harvest.pyがセッション内のツール呼び出しからアクティビティを分類し(読込/編集/テスト/ビルド/実行/インストール/コミット/PR/デプロイ/取得/レンダリング/ウェブ閲覧/委譲)、各活動の出現率と中央値の位置を統計化し、「最もセッションが多かった週 + その週の中央値となる最初のメッセージ時刻」を基準としてその一日を定義します。
# the day: the weekday with the most sessions, and its usual start time (mornings preferred)
ユーザーの生の言葉はタイプごとにチャプター化される:CATSは正規表現を用いてメッセージをbuilding(承認/進行)、restart、knock(進捗確認)、notes(修正)、side-by-side(惜しい)、good-part(褒め言葉)、frames、watching、kept(記憶/次回)などのチャプター種別に分類し、それぞれに「引用可能な最大長」を設定します。
CATS = { # chapter type → pattern over the lowercased message (+ max length for short quotable lines)
素材の読み込み範囲は限定され、完全ローカルと宣言されている:~/.claude/projects/*/*.jsonl、その配下のmemory/*.md、および関連プロジェクトのCLAUDE.mdのみを読み込み、書き込み・変更・アップロードは一切行いません。
Reads (never writes, never uploads):
プライバシーゲートは口約束ではなく実行可能な構造バリデーションである:new-film.mjsはstory.js生成前に各フィールドを正規表現で走査し、クレデンシャル形式(sk-/ghp_/github_pat_/xox?-/AKIA/BEGIN秘密鍵)、メールアドレス、ファイルパスに合致した場合はエラーを出し、URLの場合は警告を発します。また、story.approvedがtrueでない場合、全行を事前にユーザーへ提示するよう促します。
if (SECRET.some(r => r.test(t))) errs.push(`${at}.${k}: looks like a credential; remove it`);
タイムラインはarchetypes.jsonに**完全に固定**されている:各チャプターには小節数(bars)と複数のイベント発生秒数が設定されており、すべて96 BPMのグリッド上に配置されます。映像(scenes.js)と劇伴(score.py)の双方がこの単一テーブルから時間を参照するため、チャプター順を入れ替えてもタイミングが狂いません。
Single source of truth for the film clock. scenes.js draws every event at these times and scripts/score.py composes on them, so picture and music cannot drift.
映像はフレーム単位で描画される(DOM/CSSアニメーションではない):kitは非表示のp5/WEBGL canvas上に各フレームを描画し、表示用の#outに合成します。「boil」=約8枚/秒、3フレームごとに1枚切り替え、いかなる静止も3フレームを超えない仕様であり、これらはqc.pyがレンダリング済みのMP4から直接測定・検証します。
/* the kit paints in a hidden p5/WEBGL canvas and composites each drawing into #out */
劇伴は映像と同一ソースから完全ローカルで合成される:score.pyは同一のstory.json + archetypes.jsonを読み込み、章ごとに2小節を作曲します(96 BPM、Dメジャー、テーマはキー入力音のclaude = D E F# A B A)。加算合成ストリングス/Karplus-Strong撥弦/シンセリバーブを用いてローカルでレンダリングおよびマスタリングされ、ネットワーク接続や認証情報は一切不要です。
No network, no credentials. Needs numpy, scipy, ffmpeg.
2コア機能
3外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| cli | HyperFrames CLI(钉死 0.8.70,经 npx 从 npm 取;check 与 render) |
| cli | ffmpeg(配乐母带、QC 解码与响度量测、渲染链路) |
| package | p5 2.3.2 (LGPL-2.1) / p5.brush 2.2.1 (MIT) / puppeteer 25.9.0(含其钉死的 Chrome for Testing),由 lockfile 钉住 |
| package | Python3 + numpy + scipy(配乐合成与母带);harvest.py 只用标准库 |
| network | Google Fonts:合成页在预览/渲染时加载手写字体 Gochi Hand(SIL OFL) |
| network | 素材来源(唯一):用户本机的 Claude Code 转录、memory 文件与相关项目的 CLAUDE.md;不上传 |
4推奨統制措置と判定根拠
- scripts/: ローカルスクリプトまたはコマンドの実行: python3 scripts/harvest.py --out <film>/receipts.json(ローカルの書き起こしのみを読み込み、--root のデフォルトは ~/.c
- 网络端点: 外部ネットワークアクセスの宣言: registry.npmjs.org:setup時のnpm ciで固定バージョンのp5/p5.brush/puppeteerをインストール、および毎回のnpx --ye実行
- 本地工作目录: ファイル読み書きと成果物出力: filmディレクトリ内:receipts.json、story.json、story.js、index.html(data-durationの書き換え)、mus
5二重目の独立検証
- [ok] 脚本是否读凭证(黄/橙分界的关键) — 全目录 grep process.env / os.environ 零命中;harvest.py 走 argparse 参数(--root/--tz/--project),score.py/qc.py 无环境变量入口。new-film.mjs 的 SECRET 常量是用于**拒绝**凭证形状的正则,不是读取。因此橙档第一条不成立。
- [ok] 『Nothing is uploaded』声明是否真的成立 — harvest.py(读转录)import 仅 argparse/collections/datetime/glob/json/os/re/statistics,无任何网络模块;score.py 只 subprocess 调 ffmpeg;shoot.mjs 只 page.goto('file://…');qc.py 只跑 ffmpeg 解码。唯一出网行为是 setup 的 npm ci、每次 npx 取 hyperframes 与页面加载 Google Fonts。
- [ok] Use 门槛(至少 10 个本地会话、跨 5 个活跃日)是否真在代码里 — harvest.py:256 'enough': len(sessions) >= 10 and len(days) >= 5,并在运行摘要里打印 'enough material: {out["enough"]}';与 SKILL.md 的 Use 条件一致,且 SKILL.md 要求 enough 为 false 时停下。
- [ok] 隐私闸(凭证/邮箱/路径/URL)是否真有拦截面 — new-film.mjs 的 validate() 对每章每个字符串字段:SECRET 命中 → errs('looks like a credential; remove it');EMAIL 命中 → errs;PATH 命中 → errs;URL 命中 → warns。errs 非空即 exit 1,故是硬拦截。
- [discrepancy] 『故事必须经用户批准』是否被强制 — SKILL.md 的 Rules 写 'Approval before render.',但代码层面 story.approved 未置 true 时只产生一条 warn('story.approved is not true: show the user every on-screen line …'),并不阻断 --sync 或渲染。也就是说这是一道人工程序纪律,不是技术门禁;SKILL.md 的措辞(`story.approved` is set only by the user's yes)容易被读成强制。该出入对 pin commit 有效。
- [discrepancy] 『8 到 13 章』是否被校验 — SKILL.md Workflow 第 3 步写 '8 to 13 chapters.',但 new-film.mjs 的 validate() 只校验:非空、首章必须是 intro、末章必须是 tag、kept 必须紧邻 tag 之前、各章型必需字段;没有章数上下限检查。故 8–13 是写作纪律而非校验规则。
- [ok] 单一时间轴声明是否成立(画面与配乐同源) — archetypes.json 的 about 明写 scenes.js 与 scripts/score.py『both read it』;score.py 文档行也声明读 story.json + archetypes.json('the same table scenes.js draws from')。两处一致,未见第二处时钟。
- [ok] 没有本地转录时的行为 — harvest.py:137 'if not sessions: raise SystemExit(f\'no sessions under {a.root}: nothing to harvest\')',且没有任何兜底造数路径;与 SKILL.md『this skill never invents receipts』一致。
6結論
94c054dd0a6d242e…