Skip to content

Commit c17a57a

Browse files
zachcpclaude
andauthored
feat(ferritin-bevy): interactive protein viewer with orbit camera, cartoon, and color fixes (#161)
* feat(ferritin-bevy): migrate Structure from AtomCollection to Model Add `load_model` to ferritin-core (CIF-backed, returns the new Arc<AtomicHierarchy>-based Model from ferritin-4tl). Update ferritin-bevy's Structure to hold Model instead of AtomCollection, replacing all AtomCollection API calls with their Model equivalents (residues_aminoacid, atoms, hierarchy.bonds SoA, coord()). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ferritin-bevy): absorb ferritin-structure-mesh, port StructurePlugin to Model Move StructurePlugin/StructureSettings/LoadProteinEvent into ferritin-bevy (updated to load_model), port ToRerun conversions behind rerun feature, update all 4 bevy examples to import from ferritin-bevy, and delete the now-redundant ferritin-structure-mesh crate from the workspace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ferritin-bevy): use load_model in StructurePlugin, drop AtomCollection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ferritin-examples): add interactive protein viewer with bevy_feathers UI Adds bevy_interactive_viewer example that lets the user switch between all five RenderOptions (Wireframe, Cartoon, BallAndStick, Solid, Putty) and four ColorScheme presets via a feathers-themed bottom control panel. Updated from the worktree prototype to use the ferritin-bevy APIs introduced in this branch (load_model, Model instead of AtomCollection). - Add bevy_feathers = "0.19.0" dependency - New example: crates/ferritin-examples/examples/bevy/interactive_viewer.rs - FeathersPlugins + dark theme for panel background theming - ViewerState resource drives mesh rebuild via resource_changed condition - ButtonAction component on each button drives state mutations - Standard Bevy Interaction system for hover/press feedback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add fix bevy example * chore(beads): close 4 bevy_interactive_viewer issues Close ferritin-0iy, ferritin-pvg, ferritin-hn9, ferritin-jbs — all implemented in the preceding commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 511793e commit c17a57a

27 files changed

Lines changed: 537 additions & 1340 deletions

File tree

.beads/interactions.jsonl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,9 @@
7373
{"id":"int-525992e0ab84cb661e5c4edec13ab0d0","kind":"field_change","created_at":"2026-06-28T22:20:10.292716Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-pya","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
7474
{"id":"int-9fae29a206e20cef13219abad3ad80dd","kind":"field_change","created_at":"2026-06-28T22:20:10.880608Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-1ti","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
7575
{"id":"int-3872aafcd715ed80bb645d4fa090c323","kind":"field_change","created_at":"2026-06-28T22:20:11.462779Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-lgr","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
76+
{"id":"int-1e9f87c42f380859cd05a5de0951ab07","kind":"field_change","created_at":"2026-06-28T23:11:05.476258Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-d8w","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
77+
{"id":"int-c3562b01287d93334f13aaf3f826dc5c","kind":"field_change","created_at":"2026-06-28T23:51:59.678168Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-myf","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Closed"}}
78+
{"id":"int-e3a2d07cb3f7060cb416fd15f3799477","kind":"field_change","created_at":"2026-06-29T11:44:59.611308Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-0iy","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Added Structure::centroid(); rebuild_protein() now applies Transform::from_translation(-centroid) on mesh spawn."}}
79+
{"id":"int-2d686c6a90c0dc2c2b0b90f6113830a6","kind":"field_change","created_at":"2026-06-29T11:45:00.208583Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-pvg","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Bevy 0.19 auto-enables VERTEX_COLORS shader when mesh has ATTRIBUTE_COLOR. Confirmed vertex colors already set in mesh; build+tests pass."}}
80+
{"id":"int-2c133f49a4748c2f22624fb9adfa3755","kind":"field_change","created_at":"2026-06-29T11:45:00.799531Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-hn9","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Rewrote render_cartoon() to use generate_cartoon_mesh() with per-curve-point SS assignment. Added vertex colors (salmon/periwinkle/green) to cartoon mesh. Removed broken generate_alpha_helix_mesh / generate_beta_sheet_mesh."}}
81+
{"id":"int-628cc6166189d5ab997b6c8c15c5fe66","kind":"field_change","created_at":"2026-06-29T11:45:01.383696Z","actor":"Zachary Charlop-Powers","issue_id":"ferritin-jbs","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Added OrbitCamera component + orbit_camera system to interactive_viewer.rs. Left-drag=orbit, right-drag=pan, scroll=zoom."}}

Cargo.lock

Lines changed: 7 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ members = [
88
# "crates/ferritin-molviewspec",
99
"crates/ferritin-plms",
1010
# "crates/ferritin-pymol",
11-
"crates/ferritin-structure-mesh",
1211
"crates/ferritin-test-data",
1312
# "crates/ferritin-wasm-examples/ligandmpnn",
1413
# "crates/ferritin-wasm-examples/ligandmpnn-wasm",

crates/ferritin-bevy/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ authors.workspace = true
66
license.workspace = true
77
description.workspace = true
88

9+
[features]
10+
rerun = ["dep:rerun"]
11+
912
[dependencies]
1013
anyhow.workspace = true
1114
bevy = { workspace = true, default-features = true }
1215
bon.workspace = true
1316
ferritin-core = { path = "../ferritin-core" }
17+
itertools.workspace = true
18+
rerun = { workspace = true, optional = true }
1419

1520
[dev-dependencies]
1621
ferritin-test-data = { path = "../ferritin-test-data" }
File renamed without changes.

crates/ferritin-bevy/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
//! Bevy-based protein structure rendering for ferritin.
22
33
pub mod colors;
4+
pub mod plugin;
45
pub mod structure;
56

67
pub use colors::ColorScheme;
8+
pub use plugin::{LoadProteinEvent, StructurePlugin, StructureSettings};
79
pub use structure::{RenderOptions, Structure};
10+
11+
#[cfg(feature = "rerun")]
12+
pub mod conversions;
13+
#[cfg(feature = "rerun")]
14+
pub use conversions::ToRerun;

crates/ferritin-structure-mesh/src/plugin.rs renamed to crates/ferritin-bevy/src/plugin.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//!
55
use super::{ColorScheme, RenderOptions, Structure};
66
use bevy::prelude::*;
7-
use ferritin_core::{AtomCollection, load_structure};
7+
use ferritin_core::load_model;
88
use std::path::Path;
99
use std::path::PathBuf;
1010

@@ -74,15 +74,10 @@ fn load_initial_proteins(
7474
continue;
7575
}
7676

77-
// Todo: revisit this portion about the right default visuals later on
78-
// by default lets only keep the amino acids.
79-
let mut ac: AtomCollection = load_structure(file_path).unwrap();
80-
81-
// add the bonds back in as they are removed during the collection process above.
82-
ac.connect_via_residue_names();
77+
let model = load_model(file_path).unwrap();
8378

8479
let structure = Structure::builder()
85-
.pdb(ac)
80+
.pdb(model)
8681
.rendertype(settings.render_type.clone())
8782
.color_scheme(settings.color_scheme.clone())
8883
.material(settings.material.clone())

0 commit comments

Comments
 (0)