A dependency-free MoonBit motion toolkit for media timelines, easing curves, cubic Bezier inversion, and scalar keyframes.
moon add Zlj6566/moonbit-easings///|
import {
"Zlj6566/moonbit-easings" @easings,
}let curve = try! @easings.Bezier::new(0.25, 0.1, 0.25, 1.0)
let tween = try! @easings.Tween::new(
0.0,
320.0,
1.0,
curve=@easings.Curve::bezier(curve),
)
let sample = tween.sample_motion(0.5)
println(sample.value().to_string())
println(sample.velocity().to_string())# 展示 Tween、关键帧、颜色渐变和序列组合
moon run cmd/demo
# 运行可复现的 Native 工作负载并打印校验和
moon run --target native --release cmd/benchEasing / Bezier
│
├── Tween / Keyframe / ScalarTrack
│ │
│ ├── Timeline / Bundle / StateMachine
│ └── Clip / Sequence / Transport / Markers
│
├── Point / Color / Transform Tracks
├── Spline / Path / RetimeMap
└── Sampling / Signal / Diagnosticsmoon build --target native --release cmd/bench
moon run --target native --release cmd/benchmoon fmt --check
moon info --target all
git diff --exit-code
moon check --fmt --deny-warn --target all
moon build --target all
moon test --deny-warn --target allpub(all) suberror MotionError {
InvalidBezierX(Double, Double)
InvalidSampleCount(Int)
InvalidTime(Double)
InvalidDuration(Double)
InvalidDelay(Double)
InvalidRepeatCount(Int)
EmptyTrack
NonIncreasingKeyframe(Double, Double)
InvalidFrameRate(Double)
InvalidPointCount(Int)
InvalidTension(Double)
InvalidSegmentCount(Int)
InvalidThreshold(Double)
InvalidMarkerName
InvalidChannelName
InvalidRetimeSegment
InvalidStateName
}pub(all) struct AdaptiveSampleResult {
points : Array[AdaptiveSamplePoint]
accepted_segments : Int
rejected_segments : Int
maximum_error : Double
} derive(Debug)pub struct AdaptiveSamplingConfig {
tolerance : Double
max_depth : Int
max_samples : Int
} derive(Debug)fn AdaptiveSamplingConfig::new(tolerance : Double, max_depth? : Int, max_samples? : Int) -> AdaptiveSamplingConfig raise MotionErrorfn Bezier::new(x1 : Double, y1 : Double, x2 : Double, y2 : Double, sample_count? : Int) -> Bezier raise MotionErrorfn ClipSequence::markers_between(self : ClipSequence, start : Double, end : Double) -> Array[MarkerHit]fn ClipSequence::sample_many(self : ClipSequence, count : Int) -> Array[SamplePoint] raise MotionErrorfn ClipSequenceBuilder::add(self : ClipSequenceBuilder, item : ClipSequenceItem) -> ClipSequenceBuilderfn ClipSequenceBuilder::add_at(self : ClipSequenceBuilder, clip : MotionClip, start : Double, weight? : Double) -> ClipSequenceBuilder raise MotionErrorfn ColorGradient::new(stops : Array[GradientStop], premultiplied? : Bool) -> ColorGradient raise MotionErrorfn CubicPath2D::sample_by_distance(self : CubicPath2D, distance : Double, segments? : Int) -> Point2pub(all) struct CurveAnalysisPoint {
time : Double
value : Double
velocity : Double
acceleration : Double
normalized_value : Double
} derive(Debug)pub(all) struct CurveReport {
samples : Int
minimum : Double
maximum : Double
endpoint_error : Double
monotonic : Bool
peak_velocity : Double
peak_acceleration : Double
} derive(Debug)pub(all) enum EasingId {
Linear
QuadIn
QuadOut
QuadInOut
CubicIn
CubicOut
CubicInOut
QuartIn
QuartOut
QuartInOut
QuintIn
QuintOut
QuintInOut
SineIn
SineOut
SineInOut
ExpoIn
ExpoOut
ExpoInOut
CircIn
CircOut
CircInOut
BackIn
BackOut
BackInOut
ElasticIn
ElasticOut
ElasticInOut
BounceIn
BounceOut
BounceInOut
} derive(Eq, Debug)fn MarkerTimeline::at(self : MarkerTimeline, time : Double, tolerance? : Double) -> Array[MotionMarker]pub struct MotionClip {
name : String
track : ScalarTrack
markers : MarkerTimeline
loop_mode : ClipLoopMode
} derive(Debug)pub(all) struct MotionSample {
time : Double
value : Double
velocity : Double
acceleration : Double
} derive(Debug)fn MotionSignal::new(values : Array[Double], start : Double, step : Double) -> MotionSignal raise MotionErrorfn MotionSignal::sample_many(self : MotionSignal, count : Int) -> Array[SamplePoint] raise MotionErrorfn MotionSignal::zip_map(self : MotionSignal, other : MotionSignal, func : (Double, Double) -> Double) -> MotionSignalpub struct MotionStateMachine {
states : Array[MotionStateNode]
transitions : Array[MotionStateTransition]
current : String
transition_from : String
transition_to : String
transition_start : Double
transition_duration : Double
transition_curve : Curve
has_transition : Bool
} derive(Debug)fn MotionStateMachine::add_state(self : MotionStateMachine, state : MotionStateNode) -> Unit raise MotionErrorfn MotionStateMachine::add_transition(self : MotionStateMachine, transition : MotionStateTransition) -> Unit raise MotionErrorfn MotionStateMachine::new(states : Array[MotionStateNode], transitions? : Array[MotionStateTransition], initial? : String) -> MotionStateMachine raise MotionErrorfn MotionStateMachine::transition_to(self : MotionStateMachine, target : String, now : Double, duration? : Double, curve? : Curve) -> Unit raise MotionErrorpub struct MotionTransport {
position : Double
speed : Double
status : TransportStatus
direction : PlaybackDirection
range : TransportRange
markers : MarkerTimeline
} derive(Debug)fn MotionTransport::advance(self : MotionTransport, delta_seconds : Double) -> Array[MarkerHit] raise MotionErrorfn MotionTransport::seek_and_collect(self : MotionTransport, position : Double) -> Array[MarkerHit] raise MotionErrorpub struct Path2D {
segments : Array[PathSegment2D]
lengths : Array[Double]
total_length : Double
} derive(Debug)fn Path2D::append(self : Path2D, segment : PathSegment2D, samples_per_curve? : Int) -> Path2D raise MotionErrorfn Path2D::new(segments : Array[PathSegment2D], samples_per_curve? : Int) -> Path2D raise MotionErrorfn PathBuilder2D::cubic_to(self : PathBuilder2D, control_start : Point2, control_end : Point2, end : Point2) -> Unitfn Point2Track::sample_many(self : Point2Track, count : Int, mode? : Extrapolation) -> Array[Point2] raise MotionErrorfn Point3Track::sample_many(self : Point3Track, count : Int, mode? : Extrapolation) -> Array[Point3] raise MotionErrorpub struct RetimeMap {
segments : Array[RetimeSegment]
input_start : Double
input_end : Double
output_start : Double
output_end : Double
} derive(Debug)fn RetimeMapBuilder::add(self : RetimeMapBuilder, segment : RetimeSegment) -> RetimeMapBuilder raise MotionErrorfn RgbaTrack::new(frames : Array[RgbaKeyframe], premultiplied? : Bool) -> RgbaTrack raise MotionErrorfn RgbaTrack::sample_many(self : RgbaTrack, count : Int, mode? : Extrapolation) -> Array[Rgba] raise MotionErrorpub struct SamplingConfig {
start : Double
end : Double
frame_rate : Double
include_end : Bool
} derive(Debug)fn SamplingConfig::new(start : Double, end : Double, frame_rate : Double, include_end? : Bool) -> SamplingConfig raise MotionErrorpub struct ScalarChannel {
name : String
track : ScalarTrack
enabled : Bool
weight : Double
offset : Double
} derive(Debug)fn ScalarChannel::with_offset(self : ScalarChannel, offset : Double) -> ScalarChannel raise MotionErrorfn ScalarChannel::with_weight(self : ScalarChannel, weight : Double) -> ScalarChannel raise MotionErrorfn ScalarTrack::map_values(self : ScalarTrack, mapper : (Double) -> Double) -> ScalarTrack raise MotionErrorfn ScalarTrack::sample_motion(self : ScalarTrack, time : Double, mode? : Extrapolation) -> MotionSamplefn ScalarTrack::sample_values(self : ScalarTrack, times : Array[Double], mode? : Extrapolation) -> Array[Double]fn ScalarTrack::trim(self : ScalarTrack, start : Double, end : Double) -> ScalarTrack raise MotionErrorpub struct ScalarTrackBundle {
channels : Array[ScalarChannel]
start_time : Double
end_time : Double
} derive(Debug)fn ScalarTrackBundle::sample(self : ScalarTrackBundle, time : Double, mode? : Extrapolation) -> BundleSamplefn ScalarTrackBundle::sample_many(self : ScalarTrackBundle, count : Int, mode? : Extrapolation) -> Array[BundleSample] raise MotionErrorfn ScalarTrackBundle::set_enabled(self : ScalarTrackBundle, name : String, enabled : Bool) -> ScalarTrackBundle raise MotionErrorfn ScalarTrackBundle::set_weight(self : ScalarTrackBundle, name : String, weight : Double) -> ScalarTrackBundle raise MotionErrorfn ScalarTrackBundle::with_channel(self : ScalarTrackBundle, channel : ScalarChannel) -> ScalarTrackBundle raise MotionErrorfn ScalarTrackBundle::without(self : ScalarTrackBundle, name : String) -> ScalarTrackBundle raise MotionErrorfn ScalarTrackBundleBuilder::add(self : ScalarTrackBundleBuilder, channel : ScalarChannel) -> ScalarTrackBundleBuilder raise MotionErrorfn ScalarTrackBundleBuilder::build(self : ScalarTrackBundleBuilder) -> ScalarTrackBundle raise MotionErrorpub(all) struct SequenceSample {
time : Double
value : Double
index : Int
progress : Double
state : SequenceState
} derive(Debug)fn Spline2D::new(points : Array[Point2], tension? : Double, closed? : Bool) -> Spline2D raise MotionErrorfn Spline2D::project(self : Spline2D, target : Point2, samples_per_segment? : Int) -> SplineProjectionfn Spline3D::new(points : Array[Point3], tension? : Double, closed? : Bool) -> Spline3D raise MotionErrorpub struct SpringSpec {
stiffness : Double
damping : Double
mass : Double
initial_velocity : Double
} derive(Debug)fn SpringSpec::is_settled(self : SpringSpec, start : Double, end : Double, time : Double, tolerance? : Double) -> Boolfn SpringSpec::sample(self : SpringSpec, start : Double, end : Double, time : Double) -> MotionSamplefn SpringSpec::sample_many(self : SpringSpec, start : Double, end : Double, duration : Double, count : Int) -> Array[MotionSample] raise MotionErrorfn SpringSpec::velocity_at(self : SpringSpec, start : Double, end : Double, time : Double) -> Doublefn TimeWarp::new(curve : Curve, start : Double, end : Double, speed? : Double) -> TimeWarp raise MotionErrorfn Timeline::sample_window(self : Timeline, config : SamplingConfig, mode? : Extrapolation) -> Array[Array[TimelineValue]]pub struct TrackSlot {
name : String
track : ScalarTrack
offset : Double
enabled : Bool
} derive(Debug)pub struct TransformTrack {
frames : Array[TransformKeyframe]
shortest_rotation : Bool
} derive(Debug)fn TransformTrack::new(frames : Array[TransformKeyframe], shortest_rotation? : Bool) -> TransformTrack raise MotionErrorfn TransformTrack::sample(self : TransformTrack, time : Double, mode? : Extrapolation) -> Transform2Dfn TransformTrack::sample_many(self : TransformTrack, count : Int, mode? : Extrapolation) -> Array[Transform2D] raise MotionErrorpub struct Tween {
from : Double
to : Double
duration : Double
delay : Double
repeat_count : Int
mode : Extrapolation
curve : Curve
} derive(Debug)fn Tween::new(from : Double, to : Double, duration : Double, delay? : Double, repeat_count? : Int, mode? : Extrapolation, curve? : Curve) -> Tween raise MotionErrorpub(all) struct TweenSample {
time : Double
value : Double
progress : Double
cycle : Int
state : TweenState
} derive(Debug)fn TweenSequence::sample_many(self : TweenSequence, count : Int) -> Array[SequenceSample] raise MotionErrorfn adaptive_sample(func : (Double) -> Double, start : Double, end : Double, config : AdaptiveSamplingConfig) -> AdaptiveSampleResult raise MotionErrorfn adaptive_sample_tween(tween : Tween, start : Double, end : Double, config : AdaptiveSamplingConfig) -> AdaptiveSampleResult raise MotionErrorfn back_in(t : Double, overshoot? : Double) -> Doublefn blend(first : (Double) -> Double, second : (Double) -> Double, amount~ : Double) -> ((Double) -> Double)fn blend_bundles(first : ScalarTrackBundle, second : ScalarTrackBundle, amount : Double) -> ScalarTrackBundle raise MotionErrorfn bounce_out(t : Double) -> Doublefn catmull_rom(previous : Double, start : Double, end : Double, next : Double, t : Double, tension? : Double) -> Doublefn compose(outer : (Double) -> Double, inner : (Double) -> Double) -> ((Double) -> Double)fn compose_retime(first : RetimeMap, second : RetimeMap, samples_per_segment? : Int) -> RetimeMap raise MotionErrorfn critically_damped_step(current : Double, target : Double, velocity : Double, response : Double, delta_time : Double) -> (Double, Double)fn cubic_in_out(t : Double) -> Doublefn cubic_path2d(start : Point2, control_start : Point2, control_end : Point2, end : Point2) -> CubicPath2Dfn curve_lookup(func : (Double) -> Double, start : Double, end : Double, count : Int) -> Array[SamplePoint] raise MotionErrorfn derivative_of(func : (Double) -> Double, t : Double, step? : Double) -> Doublefn elastic_in(t : Double, amplitude? : Double, period? : Double) -> Doublefn hermite(start : Double, end : Double, tangent_start : Double, tangent_end : Double, t : Double) -> Doublefn integrate_curve(func : (Double) -> Double, samples : Int) -> Doublefn interpolate_angle(start : Double, end : Double, t : Double) -> Doublefn interpolate_scalar(start : Double, end : Double, t : Double) -> Doublefn interpolate_transform(start : Transform2D, end : Transform2D, t : Double, shortest_rotation? : Bool) -> Transform2Dfn local_maxima(samples : Array[SamplePoint], prominence : Double) -> Array[SamplePoint] raise MotionErrorfn map_curve_range(samples : Array[SamplePoint], output_min : Double, output_max : Double) -> Array[SamplePoint]fn marker_sequence(names : Array[String], start : Double, interval : Double) -> MarkerTimeline raise MotionErrorfn mirror(ease : (Double) -> Double) -> ((Double) -> Double)fn motion_clip(name : String, track : ScalarTrack, markers? : MarkerTimeline, loop_mode? : ClipLoopMode) -> MotionClip raise MotionErrorfn motion_profile(func : (Double) -> Double, samples : Int) -> Array[MotionSample] raise MotionErrorfn motion_transition(from : String, to : String, duration : Double, curve? : Curve) -> MotionStateTransition raise MotionErrorfn path_cubic(start : Point2, control_start : Point2, control_end : Point2, end : Point2) -> PathSegment2Dfn point2_keyframe(time : Double, value~ : Point2, curve? : Curve) -> Point2Keyframe raise MotionErrorfn point3_keyframe(time : Double, value~ : Point3, curve? : Curve) -> Point3Keyframe raise MotionErrorfn polynomial_in(t : Double, exponent~ : Double) -> Doublefn quad_in_out(t : Double) -> Doublefn quart_in_out(t : Double) -> Doublefn quint_in_out(t : Double) -> Doublefn remap_value(value : Double, source_min : Double, source_max : Double, target_min : Double, target_max : Double) -> Doublefn resample_adaptive(result : AdaptiveSampleResult, count : Int) -> Array[SamplePoint] raise MotionErrorfn retime_linear(input_start : Double, input_end : Double, output_start : Double, output_end : Double) -> RetimeMap raise MotionErrorfn retime_segment(input_start : Double, input_end : Double, output_start : Double, output_end : Double, curve? : Curve) -> RetimeSegment raise MotionErrorfn sample_function(func : (Double) -> Double, start : Double, end : Double, count : Int) -> Array[SamplePoint] raise MotionErrorfn sample_track(track : ScalarTrack, config : SamplingConfig, mode? : Extrapolation) -> Array[SamplePoint]fn scalar_channel(name : String, track : ScalarTrack, enabled? : Bool, weight? : Double, offset? : Double) -> ScalarChannel raise MotionErrorfn sequence_item(clip : MotionClip, start : Double, weight? : Double) -> ClipSequenceItem raise MotionErrorfn simplify_samples(samples : Array[SamplePoint], tolerance : Double) -> Array[SamplePoint] raise MotionErrorfn smooth_damp(current : Double, target : Double, velocity : Double, smooth_time : Double, delta_time : Double) -> (Double, Double)fn soft_limit(value : Double, minimum : Double, maximum : Double, softness : Double) -> Doublefn spring_spec(stiffness : Double, damping : Double, mass? : Double, initial_velocity? : Double) -> SpringSpec raise MotionErrorfn threshold_crossings(samples : Array[SamplePoint], threshold : Double) -> Array[Double] raise MotionErrorfn transform2d(position~ : Point2, scale~ : Point2, rotation~ : Double, skew? : Double) -> Transform2Dfn transform_keyframe(time : Double, value~ : Transform2D, curve? : Curve) -> TransformKeyframe raise MotionErrorfn transport_frames(range : TransportRange, frame_rate : Double, markers? : MarkerTimeline) -> Array[TransportFrame] raise MotionErrorA dependency-free MoonBit motion toolkit for media timelines, easing curves, cubic Bezier inversion, and scalar keyframes.