2026 04 20_configurability_sweep_phase2_plan - mark-ik/graphshell GitHub Wiki
status: Active owner: iced-migration track created: 2026-04-20 supersedes: β related:
- ../2026-04-14_iced_host_migration_execution_plan.md
- ../2026-04-20_navigation_policy_plan.md (archived)
- ../2026-04-20_node_style_configurability_sweep_plan.md (archived)
Follow-on to the navigation-policy and node-style sweeps. Same pattern (portable struct + per-view override + per-graph default + host-neutral resolver), applied to two new surfaces: physics release behavior, and shell chrome theming.
The navigation-policy sweep proved the three-slot resolver pattern:
resolve_X(view_id) returns view override ? per-graph default ?
preset fallback. Carrying that through iced M3.5 means the iced host
can reuse the same resolver calls without re-deriving from egui state.
Two surfaces carried hardcoded constants that would have forced the iced host to replicate opinionated defaults:
-
SimulateMotionProfileβ release-impulse tuning for dragβfling was inlined atgraph/scene_runtime.rs:236with an app-local duplicate struct. - Shell chrome colors β status dots, workbench panel background,
and the high-contrast selection-highlight trio were
Color32::from_rgbliterals scattered across four files.
Both are user-visible defaults that a hosting embedder (iced, future wgpu-native) will want to override without patching the shell.
-
crates/graph-canvas/src/scene_physics.rsβSimulateMotionProfilegainedSerialize + Deserialize + Default.Defaultderives fromSimulateBehaviorPreset::default()so serialized forms round-trip. -
app/graph_views.rsβGraphViewStategainedsimulate_motion_override: Option<SimulateMotionProfile>with#[serde(default)]. Addedresolve_simulate_motion_profile(view_id),set_graph_view_simulate_motion_override,set_simulate_motion_defaultonGraphBrowserApp. -
domain/mod.rsβDomainState.simulate_motion_default: Option<β¦>added; both constructor sites updated. -
graph/scene_runtime.rs:236β call site swapped from inlined struct toapp.resolve_simulate_motion_profile(view_id). -
render/canvas_bridge.rsβ three tests:resolve_simulate_motion_profile_falls_back_to_presetresolve_simulate_motion_profile_prefers_view_overrideresolve_simulate_motion_profile_falls_back_to_per_graph_default
-
app::graph_views::SimulateBehaviorPresetandgraph_canvas::scene_physics::SimulateBehaviorPresetare still duplicated.resolve_simulate_motion_profiledoes a manual match to bridge them. Dedup deferred β touches more surface than this sweep warranted.
Six new tokens added to ThemeTokenSet in
shell/desktop/runtime/registries/theme.rs, wired across all four
theme variants (default / light / dark / high_contrast):
-
status_warning,status_neutralβ paired with existingstatus_successfor the three-state sync-status dot. -
workbench_panel_backgroundβ the(20, 20, 25)chrome-fill that recurred at four frame call sites. -
selection_highlight_background/selection_highlight_text/selection_highlight_strokeβ the high-contrast-theme trio previously inlined in eguiVisuals.
-
shell/desktop/ui/workbench_host.rsβgraph_scope_sync_statusnow resolvesstatus_neutral/status_warning/status_successfrom theme tokens. -
shell/desktop/ui/gui_frame/post_render_phase.rsβ bothSidePanel::right("workbench_area")andCentralPanel::default()frames now pullworkbench_panel_backgroundfrom the active theme. -
shell/desktop/workbench/tile_render_pass.rs:1391βrun_tile_render_passCentralPanelframe swapped. -
shell/desktop/ui/toolbar/toolbar_ui.rsβrender_fullscreen_origin_stripderives its translucent fill fromworkbench_panel_background+ alpha 220, instead of the literal. -
shell/desktop/ui/gui.rsβapply_runtime_theme_visualshigh-contrast branch now reads the three selection-highlight tokens instead of inliningfrom_rgb(255, 230, 0)/WHITE/BLACK.
All four theme variants resolve to values that preserve visual parity with the prior hardcoded defaults (default theme uses the same rgb triples that were inlined).
- Minimap palette β
shell/desktop/ui/overview_plane.rshas ~12Color32::WHITE/ literal-rgb sites clustered around the overview rendering. They share one visual semantic (minimap foreground) and belong in a dedicatedminimap_*token pass. - Divider stroke tokens β 8 sites in
gui_frame/*and the workspace swatch useStroke::newwith ad-hoc grays. Group intodivider_stroke_primary/_subtlein a follow-on. -
NodeStylecolor-picker UI β the node-style sweep landed the policy surface but didn't wire an eguicolor_edit_button_rgbacontrol for end users. Follow-on UX-layer task.
Both lifts feed directly into the M3.5 carve-out in
../2026-04-14_iced_host_migration_execution_plan.md. When the iced
host renders the workbench frame or simulates release impulse, it
calls the same resolver methods on GraphBrowserApp β no bespoke
defaults to re-derive. That closes the two outstanding items noted
in the M3 completion log.
-
SimulateMotionProfileportable withDefault + Serialize + Deserialize -
resolve_simulate_motion_profileonGraphBrowserAppwith view-override + per-graph-default + preset-fallback semantics - Three unit tests covering each resolver path
- Six new theme tokens wired in all four theme variants
- Five shell call sites swapped off
Color32::from_rgbliterals -
cargo check -p graphshellclean (warnings unchanged) -
cargo test -p graph-canvas --libgreen (224 pass) - Canvas-bridge resolver suite green (25 pass)
- Broader
graphshell --libdefault-features suite (2158 pass / 3 ignored)
- SimulateMotionProfile portability + resolver landed with tests.
- Theme palette tokens added; five call sites swapped.
- Deferred sweeps logged in Β§2.
- Iced M3.5 alignment noted in Β§3.