From 534e0bad8ae347324f7878303167e6db806cff66 Mon Sep 17 00:00:00 2001 From: Toshiyuki HIRANO Date: Tue, 3 Nov 2026 23:38:04 +0900 Subject: [PATCH] docs(architecture): design motion files for movies --- architecture.ja.md | 10 ++++++++++ architecture.md | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/architecture.ja.md b/architecture.ja.md index 3b29e46..114e422 100644 --- a/architecture.ja.md +++ b/architecture.ja.md @@ -707,6 +707,16 @@ UI には、**暗い**(既定。テーマができる前の見た目)と** - **pytools のグラフ(フェーズ 6l-ii)。** File →「Open Plot (pytools)...」で、`ProteinDF_pytools` が書く `pdf-plot/1` の YAML のファイル(同じ構造の JSON も、`ProteinDF_pytools` が YAML を書けるようになるまでの移行措置として、まだ読める。YAML の読み込みが JSON も読む。元素は常に文字列として読むので、`No` は元素のまま)(`pdf-plot-pop.py --json`: 原子ごとの Mulliken 電荷の差)を読み、下のペインに `PlotKind::Pytools` として出す(同時に 1 つ。別のファイルを開くと置き換える。データは利用者ごとに持ち、ワークスペースには保存しないので、復元したタブには「グラフが開いていない」と出る)。`core/src/pytools_plot.rs` は、先に `schema` を、次に `kind`(`scatter` だけ)を確かめ、リストにない原子を指す点がある JSON は拒否する。点の鍵は ProteinDF の原子番号(1 始まり、ProteinDF の入力の順)。`pdf-plot/1` は原子を番号だけで指す(chain・残基・原子名は `null`)ので、`core/src/pytools_atom_map.rs` が、位置で表示中の構造に結びつける。結びつけるのは、**原子の数と、全位置の元素が一致するときだけ**。合わなければ何も結ばず、理由をプロットの下に出す(表示中の構造は、計算した構造と違うことがある: 水素の追加、キャップ、ダミー原子)。同じ元素の原子の並びだけが違う 2 つの構造は、見分けられない。対応は、原子の数とアクティブなモデルを鍵に `Yui` がキャッシュする。`PytoolsAdapter`(`frontend/src/plot/pytools.rs`)が、クリックした点の原子番号を、結びついた原子の ID にし(Shift / Ctrl (Cmd) の扱いは 3D と同じ)、選ばれている原子の点を強調する。対応が拒否されているときは、クリックしても何も選ばず、選択もそのままにして(何もないところのクリックでも外さない)、理由をステータスバーに出す。誤った原子は選ばれない。 - **未対応。** 折れ線・棒グラフ、ズームとツールチップ、クリックで再生のフレームを動かすこと、非常に大きなデータのための格子の索引。データは毎フレーム複製するので、サンプルでは問題ないが、大きな構造ではキャッシュが要る。 +### 8.13 動きのファイル(予定) +カメラと描画表現の決まった動きを YAML のファイルに書き、いつも同じになる動画を作る。**まだ実装していない。これは、合意した設計である。** ファイルに書くのは動きだけで、描画表現は定義しない。描画表現はワークスペース(`AppState.representations`、6.2節)に残るので、1 つの動きのファイルを、別の構造にも使い回せる。 +- **形式。** YAML。`schema: yui-motion/1`、`fps`、`steps`。手順は上から順に実行する。 +- **手順。** `turn`(`axis`、度で書く `angle`、`seconds`。`x` / `y` / `z` は画面の軸、`[x, y, z]` は任意のベクトル)、`zoom`(`factor`、`seconds`)、`wait`(秒数)、`show_frame`(`from`、`to`、`seconds`。マルチモデル構造のモデル、XYZ の軌跡のフレーム)、`set`(次の項)。 +- **`set`。** ワークスペースの表現を `id` で指し、`visible` と `opacity` を変える。`seconds` があれば、不透明度を滑らかに変える(フェード)。見えるようになる表現は、フェードインする。`seconds` がなければ、すぐに変える。`set` は表現を作らない。最初の版で変えられるのは `visible` と `opacity` だけで、色と種類(`kind`)は、あとで足すかもしれない。 +- **実行前の検査。** 最初のフレームの前に、ファイル全体を読んで検査する。知らない手順、数値の誤り、ワークスペースにない `id` はエラーにするので、ファイルのせいで動画が途中で失敗することはない。 +- **カメラの計算。** 動きのコードの中では、カメラの向きを四元数で持つ。そのため、任意の軸まわりの回転に極はなく、仰角の制限もない(`orbit_camera` は ±86° に制限する)。保存する `CameraState` は、これまでどおり `eye` / `target` / `up` / `fov` で、古いファイルと同期の形式は変わらない。Spin、Rock、マウスのドラッグ(8.11節)も、動きを変えずに、同じ回転に載せ替える。 +- **使う場所。** File →「Export Animation」の動きに、Spin、Rock、Frames と並んで「Motion file」を足す(4.6節、動画のダイアログ)。同じファイルを画面で再生する(「Play Motion」)こともできる。実行が終わったとき、失敗したとき、取り消したとき、`set` が変えた表現は、実行前の状態に戻す。 +- **作業の順。** (1) カメラの回転を四元数に載せ替える(見た目は変えない)。(2) ファイルの読み込み、`turn` / `zoom` / `wait` / `show_frame`、書き出し。(3) `set`。 + ## 9. ライセンス・配布方針 - **ライセンス:** GPLv3。依存する `ProteinDF_bridge`(およびそのRust移植版 `proteindf-bridge`)もGPLv3であり、ライセンス上の矛盾はない。 diff --git a/architecture.md b/architecture.md index 066666d..bbdc413 100644 --- a/architecture.md +++ b/architecture.md @@ -709,6 +709,16 @@ A scatter plot whose points can be clicked to select atoms. The plot knows nothi - **pytools plots (Phase 6l-ii).** File → "Open Plot (pytools)..." reads a `pdf-plot/1` file in YAML (the same data model is still read as JSON, only as a transitional measure until `ProteinDF_pytools` writes YAML; it is read by the YAML reader, which accepts JSON; elements are always read as text, so `No` stays an element) that `ProteinDF_pytools` writes (`pdf-plot-pop.py --json`: the Mulliken charge difference per atom) and shows it as `PlotKind::Pytools` in the Bottom pane (one plot at a time; opening another replaces it; the data are kept per user and not saved in the workspace, so a restored tab says that no plot is open). `core/src/pytools_plot.rs` checks `schema` first and `kind` (only `scatter`) and rejects a file whose points name an atom that is not listed; the key of a point is the ProteinDF atom index (1-based, in the order of the ProteinDF input). Because `pdf-plot/1` names atoms only by that index (chain, residue and atom name are `null`), `core/src/pytools_atom_map.rs` links them to the displayed structure by position and only when **the atom count and the element at every position agree**; otherwise nothing is linked and the reason is shown under the plot (the displayed structure can differ from the calculated one: added hydrogens, caps, dummy atoms). It cannot tell apart two structures that differ only in the order of atoms of the same elements. The map is cached in `Yui` by atom count and active model. `PytoolsAdapter` (`frontend/src/plot/pytools.rs`) turns the atom index of a clicked point into the linked atom id (same Shift / Ctrl (Cmd) rules as the 3D view) and highlights the points of the selected atoms. When the map is refused, a click selects nothing, leaves the selection as it is (even a click on empty space), and shows the reason in the status bar, so no wrong atom is ever selected. - **Not yet.** Line and bar charts, zoom and tooltips, clicks that move the playback frame, and a grid index for very large data. The data are cloned on every frame, which is fine for the sample but will need a cache for large structures. +### 8.13 Motion Files (planned) +A scripted camera and representation motion, written in a YAML file, for movies that must come out the same every time. **Not implemented yet; this is the agreed design.** The file describes a motion only. It never defines representations: those stay in the workspace (`AppState.representations`, §6.2), so one motion file can be reused for other structures. +- **Format.** YAML with `schema: yui-motion/1`, `fps`, and `steps`. The steps run from top to bottom. +- **Steps.** `turn` (`axis`, `angle` in degrees, `seconds`; `x` / `y` / `z` are screen axes, `[x, y, z]` is any vector), `zoom` (`factor`, `seconds`), `wait` (seconds), `show_frame` (`from`, `to`, `seconds`; models of a multi-model structure and frames of an XYZ trajectory), and `set` (below). +- **`set`.** Names a representation of the workspace by its `id` and changes `visible` and `opacity`. With `seconds`, the opacity changes smoothly (a fade), and a representation that becomes visible fades in; without `seconds`, the change is immediate. `set` does not create representations. In this first version only `visible` and `opacity` can be changed; the color and the kind (`kind`) may be added later. +- **Checks before the run.** The whole file is read and checked before the first frame: an unknown step, a bad number, and an `id` that the workspace does not have are errors, so a movie never fails halfway because of the file. +- **Camera math.** The camera orientation is held as a quaternion inside the motion code, so a turn about any axis has no pole and no clamp on the elevation (`orbit_camera` clamps it to ±86°). The saved `CameraState` stays `eye` / `target` / `up` / `fov`, so old files and the synchronization format do not change. Spin, Rock and the mouse drag (§8.11) are moved onto the same rotation without changing how they move. +- **Where it is used.** File → Export Animation gets a "Motion file" kind of motion next to Spin, Rock and Frames (§4.6, the movie dialog), and the same file can be played on the screen ("Play Motion"). When a run ends, fails or is cancelled, the representations that `set` changed return to their state before the run. +- **Order of work.** (1) Move the camera rotation onto quaternions, with no visible change. (2) Read the file, `turn` / `zoom` / `wait` / `show_frame`, and the export. (3) `set`. + ## 9. License & Distribution Policy - **License:** GPLv3. The dependency `ProteinDF_bridge` (and its Rust port `proteindf-bridge`) is also GPLv3, so there is no licensing conflict.