簿記学習用の章ページに「ボタンを押すと仕訳帳に転記され、残高試算表でアニメーションが走る」インタラクティブブロックを純HTML+CSS+JS(IIFE)で組み込んだ。設計は10分で固まったが、実装中に3回つまずき、最後はChrome DevToolsでスクショを撮るまでバグに気づかなかった。
やったこと
cash-3-topics.html というキャッシュ章のページに、仕訳エンジンを埋め込む。要件はこうだ。
- ユーザーが「仕訳をプッシュ」ボタンを押すと、仕訳帳テーブルに行が追加される
- 同時に残高試算表の該当勘定の数字が増減し、差分がアニメーションで光る
- 期間切替(前期/当期)はExcelシート風のタブで切り替える
- 前期は記帳済み・閲覧専用、当期だけ操作可能
Vue化はまだなので、まずは1ファイルで完結する純HTMLで動かす方針にした。
レイアウトの分割
借方・貸方を縦に並べる愚直な見せ方だと、BS/PLの構造が伝わらない。CSS Gridで4象限に切った。
.tb-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
gap: 8px;
}
/* 借方=資産・費用 / 貸方=負債・純資産・収益 */
純資産には繰越利益剰余金(期首)と当期純利益を別行で出し、子要素として2文字インデント。当期純利益は費用区分の末尾にも添えてPLをバランスさせた。これだけで「PLの利益が純資産に積み上がる」感覚が視覚的に伝わるようになった。
帳簿側は黒の角張ったカードで囲み、ヘッダーを黒背景+白文字にした。入力側カードと帳簿側カードの間に「帳簿に反映 ▼」というフロー矢印を1本入れたら、操作の因果がひと目で読めるようになった。
マトリックス形式で出して怒られた
最初、受取時と支払時を縦横の2x2マトリックスで並べて見せたら、ユーザーから「完全に独立した仕訳を縦に並べる形式に直して」と一発で却下された。
確かに、マトリックスは「同じ取引の表裏」を示すには良いが、独立した2つの取引には不向きだった。受取時と支払時で勘定が変わる構造を縮約しすぎていた。例題タブで「① 不一致発覚 / ② 原因判明」をタブ切替にして縦長を圧縮し、各タブの中では仕訳をシンプルに縦並びにした。
リセットボタンも「リセット」のままだと押しづらいという指摘があり、「↺ 一括取消」と動詞ラベルに変えて右上に逃がした。
漫画風の差分吹き出し
仕訳プッシュ後、何がいくら動いたかを可視化したかった。試算表右上のFYタブ行に「現金が +2,000 増加 / 売掛金が −2,000 減少」をマゼンタ薄背景(10% alpha)の吹き出しで出すようにした。
最初は仕訳行の真上に出していたが、「大事な部分が見えなくなる」と指摘されて即座に右上固定に変えた。これも独りよがりな配置だった。
取消後の挙動も悩んだ。新しい吹き出しを作ると「取り消したのに何か出る」状態で混乱を招く。残ったままにして、次のプッシュで上書きされる方針に落ち着けた。
simplifyスキルで踏んだTDZ
ロジックがふくらんできたので simplify スキルで畳み込んだ。
- preposted展開を
applyEntryに統合 switchFYJournalとswitchFYTbをswitchFYに統合- アニメーション重複防止に
activeRafsとpendingTimersを導入
ここで applyEntry の宣言順序が崩れて、初期化時にTDZ(Temporal Dead Zone)エラーが出るバグを仕込んだ。エディタで開いてもエラーは出ず、ビルドも通る。「直したつもり」で次のタスクに進みかけた。
ユーザーから「Chrome DevToolsで撮ってみて」と言われ、初めてコンソールに赤いエラーが出ているのを見た。スクショなしで「ファイル更新済み=正常」と判断したのが完全にミスだった。
教訓: ファイル更新だけで「動いた」と言わない
シンプル化のリファクタは、見た目のロジックは正しくても実行順序を壊す。今回もコードを読み返した時点では「変数を上に集めて宣言した」つもりが、関数式の代入が後ろに残っていて、初回呼び出しで参照不能になっていた。
教訓は3つに集約された。
- ファイルを保存しただけで「動いた」と言わない
- インタラクティブ要素を触ったら必ずブラウザでスクショを撮る
- simplify後は特に、初期化パスを通す動作確認が必須
ナレーション化と縦切り検証
cash-3-topics-narration.vue を別途作り、3名話者(ずんだもん他)でVOICEVOX音声を58行生成した。NarrationViewer.vue に line-change emit を追加し、Cash3TopicsExample.vue / Cash3TopicsNarrationViewer.vue を新規作成して、ナレーションの行送りに合わせてインタラクティブ要素のステートが切り替わる作りにした。
縦切り検証で「あるナレーション行に来たら、対応する仕訳が自動でプッシュされる」というイベント同期がきれいに動いた瞬間は、思わずもう一度再生ボタンを押した。
計画書は Codex GPT-5.5 で3ラウンドレビューしてもらい、致命的な指摘13個を全部潰してからOKをもらった。指摘の質が高くて、自分で見直すより速い。
共通化: SVG拡大とモーダル
マウスオーバーでSVGが拡大、クリックでモーダル拡大、ESCで閉じる。この3つは他の章でも使うので _layout.css/_layout.js に共通化した。各章ページは <svg> を置くだけで自動的に拡大UIが効く。
Nuxt/Vue化への移行計画
HTMLだけで全章を展開するのは破綻する。1ファイルが2000行を超え、章をまたいだステート共有もできない。Nuxt/Vue化と並行で進める方針を立てた。
移行計画はM0でTypeScript章メタデータと分類を入れ、仕訳の借方/貸方/金額はTSにせず、章ごとの例題タイトル一覧をマークダウンに残すハイブリッドにした。仕訳データを完全TS化すると編集コストが跳ね上がるためだ。
この計画書も Codex で複数回レビューに回し、5つの致命指摘(ルーティング方針統一、完了条件明確化、マイルストーンの縦切り順)を反映してから本実装に入る。
明日やること
- M0着手: 章メタデータのTypeScript型を切る
- 例題タイトル一覧のマークダウン雛形を1章ぶん作る
- cash-3-topics.html のTDZ修正をユニットテスト相当の手動チェックリスト化
- simplify後の動作確認手順を
.claude/rules/にメモする