Skip to content

✨ Phase γ:AJ export への汎用 render hook 追加と export バグ 3 件の修正 - #3

Merged
EllaCoat merged 13 commits into
mainfrom
feat/pg-render-hooks
Aug 5, 2026
Merged

✨ Phase γ:AJ export への汎用 render hook 追加と export バグ 3 件の修正#3
EllaCoat merged 13 commits into
mainfrom
feat/pg-render-hooks

Conversation

@EllaCoat

@EllaCoat EllaCoat commented Aug 5, 2026

Copy link
Copy Markdown
Owner

概要

外部 plugin が AJ の datapack export に自分の計算結果を載せられるよう、汎用の pose pipeline hook を追加する。AJ 側は registry と dispatch だけを提供し、物理等の固有ロジックは持たない。あわせて、作業中に見つけた export 経路のバグ 3 件を修正する。

hook が 1 つも登録されていないときの出力は従来と完全に同一であることを最優先の条件とし、hook 導入前の実装が出した値と突き合わせて確認している。

主な変更点

追加した hook API

window.AnimatedJava.renderHooks として公開する (= register(id, hooks) / unregister(id) / version)。

callback は onBeginRendering / onBeginAnimation / onPose / onEndAnimation / onEndRendering の 5 つ。begin と pose は登録順、end は逆順に呼ぶ。

契約 内容
発火点 updatePreview が keyframe pose を scene に確定させた直後
同期のみ Promise を返しても await しない
pose の受け渡し matrix は返さず、scene の node pose を直接書き換える。書き換えたら updateMatrixWorld を自分で呼ぶ
冪等性 onPose は同じ frameIndex で 1 frame につき複数回呼ばれる (= IK のための二度呼び / pre-post の side sample とその巻き戻し / null_object ごとの再評価)。回数は blueprint 構成で変わるため、hook 側は回数を数えず frameIndex の変化だけを見る
例外 RenderHookError で hook id と phase を付けて export エラーへ surface する

修正した export バグ

対象 内容
getFrame の 1 tick 前 keyframe 参照 time - 0.05 を格子へ再スナップしておらず、0〜3 秒の 61 frame 中 20 frameMap がヒットしない。pre-post interpolation の指定が出力から落ちていた
keyframe の衝突回避 ずらした時刻が格子から外れていた (= 0.1 + 0.050.15000000000000002 になり、frame ループ側の時刻から引けない)
hashAnimations pos / rot / scale しか mix していなかった。compiler は matrix 全体を使う (= 純正経路は 16 要素をそのまま、TSB 経路は SVD 分解) ため、shear や right rotation だけが変わると 出力は変わったのに hash が一致し、on_load の reload-skip が誤判定する

例外時の状態復旧

renderProjectAnimations は bone interpolation フラグ / scene の 180 度回転 / 選択中 animation を変更するが、復元が保護されておらず、例外で抜けると壊れた状態が残っていた。次の 3 点を入れた。

  • 復元を保護区間へ移し、各段を独立させた (= 1 つの失敗が残りの復元を巻き添えにしない)
  • 元の例外を cleanup の例外で上書きしない
  • hook の begin 系が途中で失敗した場合、成功済みの hook へ逆順で end callback を送ってから rethrow する

動作確認

bun run test = 94 passed / 1 todo (= 本 PR の新規 61 件)。bun install --frozen-lockfile は差分なし、tsc --noEmit の error 件数は変更前と同数、prettier も pass。

検証の中心は src/tests/animationRenderExport.test.ts。Blockbench 無しで production の renderProjectAnimations を実走させ、次を確認する。

  • hook 未登録時の出力が hook 導入前の実装が出した値と完全に一致する
  • hook 登録で node_transforms と hash が変わり、生成される mcfunction が byte 単位で変わる。変化が「1 回分だけ」であることも見る (= 冪等でない hook を入れると落ちる)
  • unregister で元の出力へ完全復帰する
  • hook が throw したとき export がエラーになり、フラグと scene の回転が復旧する
  • shear だけを加える変換が hash に乗る (= 修正前の hash では検出できなかったことも並べて示す)

注意

この PR は export 出力を変える。いずれもバグ修正による正しい変化だが、既存 blueprint の datapack は再生成が必要になる。

  1. pre-post interpolation が正しく載る (= 約 1/3 の frame で落ちていた)
  2. 衝突回避でずらされた keyframe の時刻が格子に載る
  3. animation_hash の式が変わるため、次回 export 時に 1 回だけ全 cell が reload される

未対応

  • 実機での確認。CLI 検証が保証するのは「hook 経路で export の値が機械的に変わること」まで。物理値の妥当性は対象外
  • keyframe を持つ経路の回帰確認。検証用 fixture が keyframe を持たない構成のため、pre-post / step / null_object の経路は導入前との一致を確認できていない。上記の出力変更 1 と 2 がまさにその経路にあたる
  • keyframe 正規化ループの構造的な問題animator.keyframes は channel 連結の getter (= rotation / position / scale が順に並ぶ) だが、正規化ループはこれを 1 本の時系列として扱っている。channel をまたいだ衝突の誤検出、3 つ以上が同じ格子点へ丸まる場合の重複、ずらした結果が animation.length を超える取りこぼしが残る。正しい修正には channel 単位への作り替えと実機検証が要るため本 PR では扱わない。現状の挙動は「既知の未解決欠陥」としてテストで固定してある

@EllaCoat
EllaCoat merged commit ac96056 into main Aug 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant