Expand description
§Open GPUI Motion
open-gpui-motion contains renderer-neutral motion primitives for Open GPUI components and domain
crates. It is a deterministic Rust foundation for layout-like UI motion; it is not a DOM animation
runtime.
§What This Crate Owns
- Motion preferences, duration tokens, easing tokens, and immediate reduced-motion semantics.
- Timeline and spring scalar sampling from explicit elapsed time.
- Policy-resolved execution plans for committed layout, continuity, affordance previews, and input-coupled paths.
- Scalar controllers, retargeting, cancellation, explicit finish, terminal pruning, and adapter-owned frame demand.
MotionProgressExecutionfor policy-resolved normalized 0..1 adapter progress runs.MotionSequencefor composing many keyed scalar tracks with absolute starts, append, with-previous, after-previous, and staggered insertion while preserving renderer-neutral sampling.MotionClockSamplefor mapping adapterInstantvalues into deterministic controllerDurationsamples with non-monotonic elapsed time clamped.MotionFrameDemand::combineandMotionFrameDemand::combine_allfor aggregating many motion sources into one adapter frame request.MotionFrameHostfor keeping adapter-owned frame request decisions consistent without depending on a GPUI window, browser scheduler, or renderer.- Neutral logical-pixel geometry plus projection, reveal, and clip helpers for final-size content.
Adapters keep authority over rendering, input, focus, accessibility, and frame scheduling. A Splitter, docking host, canvas, or application decides when to request a GPUI frame and how to map a motion sample into painted elements.
§First-Party Proof Scope
The v0.2.0 stable proof is intentionally small:
Splitterconsumes scalar controller samples for programmatic panel layout transitions.VirtualizedListconsumes scalar controller samples for an active-descendant indicator that moves paint-only chrome by stable row key.- Docking consumes neutral motion geometry and projection helpers for presentation and affordance evidence.
These consumers prove deterministic clocks, normalized progress runs, retargeting, reduced-motion
final state, cancellation, terminal pruning, sequence composition, and MotionFrameDemand
aggregation. They do not prove row enter/exit animation, public presence, keyframes,
repeat/reverse/speed controls, full shared-layout orchestration, WAAPI, or a global scheduler.
§Where To See It
Run the component gallery to inspect Splitter and VirtualizedList motion in a normal checkout:
cargo run -p open-gpui-ui-foundation-galleryRun the docking example to inspect layout and affordance motion through the docking host:
cargo run -p open-gpui-docking-nativeBoth examples keep frame scheduling in their GPUI adapters. open-gpui-motion only publishes
deterministic samples and frame demand.
§Boundaries
This crate deliberately does not provide React hooks, CSS parsing, DOM measurement, WAAPI behavior,
browser-native acceleration, global animation loops, drag-and-drop policy, asset animation, or full
shared-layout orchestration. MotionProgressExecution only owns a local 0..1 run lifecycle, and
MotionSequence only owns deterministic keyed timing and sampling; neither mutates properties or
schedules frames. Presence, keyframes, repeat/reverse/speed controls, public value subscriptions,
and high-level builders are deferred until a first-party Open GPUI adapter proves the shape.
open-gpui-motion must stay below open-gpui-ui-core, open-gpui-ui-components,
open-gpui-docking, open-gpui-platform, open-gpui-web, and renderer crates. Use conversion
helpers in adapter crates to map MotionRect to renderer-specific geometry.
§Example
use open_gpui_motion::{
MotionDuration, MotionEasing, MotionExecutionPlan, MotionFrameHost, MotionModel,
MotionPolicyContext, MotionPolicyInput, MotionPreference, MotionScalarExecution, MotionSpec,
};
use std::time::Duration;
let spec = MotionSpec::new(
MotionPreference::Animated,
MotionDuration::Custom(Duration::from_millis(180)),
MotionEasing::EaseOutStrong,
);
let plan = MotionExecutionPlan::resolve(
MotionPolicyInput::new(MotionPolicyContext::CommittedLayout, MotionModel::timeline(spec))
.with_spatial_motion(true)
.with_reduced_motion_final_state(true),
);
let execution = MotionScalarExecution::start(plan, 0.0, 1.0, 0.0, Duration::ZERO);
let mut frame_host = MotionFrameHost::new();
let sample = frame_host.sample_elapsed(Duration::from_millis(90), |clock| {
let sample = execution.sample_clock(clock);
(sample.value(), sample.frame_demand())
});
if sample.should_request_frame() {
// Ask the owning adapter to request a GPUI frame.
}Reduced motion uses the same APIs and publishes the final semantic state immediately:
use open_gpui_motion::{MotionPreference, MotionSpec};
let spec = MotionSpec::committed_layout(MotionPreference::Reduced);
assert!(spec.is_immediate());Lifecycle ordering is intentionally small: start or retarget creates active sampled state, each
sample returns a frame demand, cancel freezes the sampled value and goes idle without reaching the
semantic final state, finish publishes the target value as completed, reduced motion publishes
the final state immediately, and adapters may prune terminal tracks after observing idle demand.
§Testing
For focused changes in this crate, run:
cargo check -p open-gpui-motion --tests --locked
cargo nextest run -p open-gpui-motion --no-fail-fast
cargo test -p open-gpui-motion --docWhen changing geometry or policy used by first-party adapters, also run the focused Splitter and
docking gates documented in docs/verification.md.
Renderer-neutral motion primitives for Open GPUI.
This crate owns deterministic motion specifications, sampling, policy, projection helpers, and frame-demand contracts without depending on GPUI windows, component state, docking state, or platform renderers.
Re-exports§
pub use controller::MotionClockSample;pub use controller::MotionExecutionPlan;pub use controller::MotionExecutionState;pub use controller::MotionFrameDemand;pub use controller::MotionFrameReason;pub use controller::MotionProgressExecution;pub use controller::MotionProgressSample;pub use controller::MotionScalarController;pub use controller::MotionScalarControllerSample;pub use controller::MotionScalarExecution;pub use controller::MotionScalarExecutionSample;pub use controller::MotionScalarTrack;pub use controller::MotionScalarTrackSample;pub use frame_host::MotionFrameHost;pub use frame_host::MotionFrameHostSample;pub use frame_host::MotionFrameHostUpdate;pub use geometry::MotionEdges;pub use geometry::MotionPoint;pub use geometry::MotionPx;pub use geometry::MotionRect;pub use geometry::MotionSize;pub use geometry::motion_edges;pub use geometry::motion_point;pub use geometry::motion_px;pub use geometry::motion_rect;pub use geometry::motion_size;pub use motion::MotionDuration;pub use motion::MotionEasing;pub use motion::MotionPreference;pub use motion::MotionSpec;pub use policy::MOTION_POLICY_MAX_UI_DURATION;pub use policy::MotionPolicyContext;pub use policy::MotionPolicyInput;pub use policy::MotionPolicyIssue;pub use policy::MotionPolicyReport;pub use policy::MotionPreviewTargetPolicy;pub use policy::validate_motion_policy;pub use projection::MotionProjection;pub use projection::MotionProjectionClip;pub use runtime::MotionEdge;pub use runtime::MotionRetargetItem;pub use runtime::MotionRetargetSet;pub use runtime::MotionRunState;pub use runtime::MotionSnapshot;pub use runtime::MotionTimeline;pub use runtime::MotionTimelineSample;pub use runtime::lerp_rect;pub use runtime::motion_source_rect;pub use runtime::preferred_motion_edge;pub use runtime::retarget_motion_snapshots;pub use runtime::reveal_rect_from_edge;pub use sequence::MotionSequence;pub use sequence::MotionSequenceSample;pub use sequence::MotionSequenceStep;pub use sequence::MotionSequenceStepSample;pub use sequence::MotionSequenceStepState;pub use spring::MotionModel;pub use spring::MotionPreset;pub use spring::MotionScalarSample;pub use spring::MotionSpring;pub use spring::MotionSpringPhysics;pub use spring::MotionSpringPreset;pub use spring::MotionSpringSpec;
Modules§
- controller
- Renderer-neutral motion controller contracts.
- frame_
host - Adapter-owned frame request helpers.
- geometry
- Renderer-neutral geometry values for UI component state.
- motion
- Renderer-neutral motion descriptors.
- policy
- Renderer-neutral motion policy validation.
- projection
- Renderer-neutral layout projection primitives.
- runtime
- Renderer-neutral runtime helpers for deterministic UI motion.
- sequence
- Renderer-neutral sequence plans for composing many motion tracks.
- spring
- Renderer-neutral spring sampling for layout-like UI motion.