solid-drift 0.2.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +735 -10
- package/dist/animate.d.ts +2 -2
- package/dist/animate.js +2 -2
- package/dist/cartoon.d.ts +190 -0
- package/dist/cartoon.js +334 -0
- package/dist/color.d.ts +53 -0
- package/dist/color.js +391 -0
- package/dist/directive.d.ts +5 -5
- package/dist/directive.js +15 -7
- package/dist/easing.d.ts +22 -1
- package/dist/easing.js +49 -1
- package/dist/flip.d.ts +44 -0
- package/dist/flip.js +108 -0
- package/dist/horizontal.d.ts +107 -0
- package/dist/horizontal.js +208 -0
- package/dist/index.d.ts +16 -3
- package/dist/index.js +15 -3
- package/dist/inview.d.ts +4 -4
- package/dist/inview.js +5 -5
- package/dist/motion.d.ts +327 -0
- package/dist/motion.js +729 -0
- package/dist/physics.d.ts +146 -0
- package/dist/physics.js +352 -0
- package/dist/pointer.d.ts +76 -0
- package/dist/pointer.js +123 -0
- package/dist/reduced-motion.d.ts +3 -3
- package/dist/reduced-motion.js +5 -4
- package/dist/scroll.d.ts +3 -3
- package/dist/scroll.js +5 -5
- package/dist/scrollfx.d.ts +156 -0
- package/dist/scrollfx.js +148 -0
- package/dist/scrub.d.ts +51 -0
- package/dist/scrub.js +67 -0
- package/dist/spring.d.ts +39 -4
- package/dist/spring.js +26 -7
- package/dist/stagger.d.ts +4 -4
- package/dist/stagger.js +4 -4
- package/dist/timeline.d.ts +45 -0
- package/dist/timeline.js +93 -0
- package/dist/trail.d.ts +27 -0
- package/dist/trail.js +75 -0
- package/dist/tween.d.ts +3 -3
- package/dist/tween.js +3 -3
- package/dist/typography.d.ts +241 -0
- package/dist/typography.js +812 -0
- package/dist/velocity.d.ts +44 -0
- package/dist/velocity.js +88 -0
- package/package.json +1 -1
package/dist/motion.d.ts
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Motion-graphics family: showreel and launch-film primitives.
|
|
3
|
+
*
|
|
4
|
+
* These are the building blocks of code-driven motion design: kinetic
|
|
5
|
+
* typography, scene orchestration, camera moves, time-based color
|
|
6
|
+
* shifts, match-cut transitions, and a beat clock for cutting on the
|
|
7
|
+
* music. Each primitive is small and composable; a showreel is a
|
|
8
|
+
* `createScenePlayer` driving a few of these together, not one mega-API.
|
|
9
|
+
*
|
|
10
|
+
* All primitives are signal-native, SSR-safe, dependency-free, and
|
|
11
|
+
* define sensible static behavior under `prefers-reduced-motion`.
|
|
12
|
+
*/
|
|
13
|
+
import { type Accessor } from "solid-js";
|
|
14
|
+
import { type ColorFormat, type ColorStop } from "./color.js";
|
|
15
|
+
import { type Easing, type EasingName } from "./easing.js";
|
|
16
|
+
type MaybeElement = () => Element | null | undefined;
|
|
17
|
+
export interface KineticTypeFrom {
|
|
18
|
+
/** Vertical offset in px where each unit starts. Default 28. */
|
|
19
|
+
y?: number;
|
|
20
|
+
/** Blur in px where each unit starts. Default 10. */
|
|
21
|
+
blur?: number;
|
|
22
|
+
/** Scale where each unit starts. Default 0.85. */
|
|
23
|
+
scale?: number;
|
|
24
|
+
/** Opacity where each unit starts. Default 0. */
|
|
25
|
+
opacity?: number;
|
|
26
|
+
/** Rotation in degrees where each unit starts. Default 0. */
|
|
27
|
+
rotate?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface KineticTypeOptions {
|
|
30
|
+
/** Split into "chars" or "words". Default "chars". */
|
|
31
|
+
unit?: "chars" | "words";
|
|
32
|
+
/** Milliseconds each unit takes to arrive. Default 550. */
|
|
33
|
+
duration?: number;
|
|
34
|
+
/** Milliseconds between unit starts. Default 45. */
|
|
35
|
+
stagger?: number;
|
|
36
|
+
/** Starting transform/opacity/blur for each unit. */
|
|
37
|
+
from?: KineticTypeFrom;
|
|
38
|
+
/** Easing for each unit's arrival. Default "easeOutExpo". */
|
|
39
|
+
easing?: Easing | EasingName;
|
|
40
|
+
}
|
|
41
|
+
export type KineticTypeStatus = "idle" | "running" | "done";
|
|
42
|
+
export interface KineticTypeControls {
|
|
43
|
+
/** Play the reveal. Resolves when the last unit arrives. */
|
|
44
|
+
play: () => Promise<void>;
|
|
45
|
+
/** Stop mid-reveal. The play() promise resolves. */
|
|
46
|
+
stop: () => void;
|
|
47
|
+
/** Stop and play again from the first unit. */
|
|
48
|
+
replay: () => Promise<void>;
|
|
49
|
+
/** Reactive status: "idle" | "running" | "done". */
|
|
50
|
+
status: Accessor<KineticTypeStatus>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Kinetic typography: each character (or word) flies in with position,
|
|
54
|
+
* blur, scale, and opacity, staggered for that showreel title feel.
|
|
55
|
+
*
|
|
56
|
+
* One master clock drives every unit, so a headline with 40 characters
|
|
57
|
+
* costs a single rAF task, not 40 timers. Units animate through the
|
|
58
|
+
* same `from` state with per-unit easing.
|
|
59
|
+
*
|
|
60
|
+
* SSR-safe: no-op on the server. Under reduced motion every unit jumps
|
|
61
|
+
* to its final state when `play()` runs, so the text is fully readable.
|
|
62
|
+
*
|
|
63
|
+
* ```tsx
|
|
64
|
+
* let title!: HTMLHeadingElement
|
|
65
|
+
* const kinetic = createKineticType(() => title, {
|
|
66
|
+
* unit: "chars",
|
|
67
|
+
* stagger: 35,
|
|
68
|
+
* from: { y: 40, blur: 12, scale: 0.8 },
|
|
69
|
+
* easing: "easeOutExpo",
|
|
70
|
+
* })
|
|
71
|
+
* onMount(() => kinetic.play())
|
|
72
|
+
* <h1 ref={title}>Showreel</h1>
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function createKineticType(ref: MaybeElement, options?: KineticTypeOptions): KineticTypeControls;
|
|
76
|
+
/** One scene in a showreel: a duration plus enter/exit hooks. */
|
|
77
|
+
export interface MotionScene {
|
|
78
|
+
/** How long the scene stays active, in milliseconds. */
|
|
79
|
+
duration: number;
|
|
80
|
+
/** Called when the scene becomes active. */
|
|
81
|
+
onEnter?: (index: number) => void;
|
|
82
|
+
/** Called when the scene ends. */
|
|
83
|
+
onExit?: (index: number) => void;
|
|
84
|
+
}
|
|
85
|
+
export type ScenePlayerStatus = "idle" | "running" | "paused" | "done";
|
|
86
|
+
export interface ScenePlayerControls {
|
|
87
|
+
/** Current scene index, or -1 before the first play(). */
|
|
88
|
+
scene: Accessor<number>;
|
|
89
|
+
/** Reactive status: "idle" | "running" | "paused" | "done". */
|
|
90
|
+
status: Accessor<ScenePlayerStatus>;
|
|
91
|
+
/** Play from the current scene. Resolves after the last scene. */
|
|
92
|
+
play: () => Promise<void>;
|
|
93
|
+
/** Freeze the clock; play() resumes where it left off. */
|
|
94
|
+
pause: () => void;
|
|
95
|
+
/** Halt and reset to before the first scene. */
|
|
96
|
+
stop: () => void;
|
|
97
|
+
/** Stop and play again from the first scene. */
|
|
98
|
+
replay: () => Promise<void>;
|
|
99
|
+
/** Jump to the next scene now. */
|
|
100
|
+
next: () => void;
|
|
101
|
+
/** Jump to the previous scene now. */
|
|
102
|
+
prev: () => void;
|
|
103
|
+
/** Jump to a scene now. */
|
|
104
|
+
goTo: (index: number) => void;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Scene orchestrator for showreels and launch films: an ordered list of
|
|
108
|
+
* scenes, each with a duration and enter/exit hooks. Think of it as the
|
|
109
|
+
* paused-master-timeline pattern from motion-design tools, expressed as
|
|
110
|
+
* signals: `scene()` tells your view which scene is live, and the hooks
|
|
111
|
+
* trigger each scene's choreography (a `createKineticType`, a camera
|
|
112
|
+
* move, a color shift).
|
|
113
|
+
*
|
|
114
|
+
* SSR-safe: scenes never advance on the server. Under reduced motion
|
|
115
|
+
* `play()` jumps straight to the last scene (the clean final frame)
|
|
116
|
+
* instead of stepping through.
|
|
117
|
+
*
|
|
118
|
+
* ```ts
|
|
119
|
+
* const player = createScenePlayer([
|
|
120
|
+
* { duration: 1200, onEnter: () => hookTitle.play() },
|
|
121
|
+
* { duration: 2000, onEnter: () => cameraZoom.play() },
|
|
122
|
+
* { duration: 1500, onEnter: () => showLogo() }, // final frame
|
|
123
|
+
* ])
|
|
124
|
+
* player.scene() // 0, 1, 2 as the reel plays
|
|
125
|
+
* await player.play()
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function createScenePlayer(scenes: MotionScene[]): ScenePlayerControls;
|
|
129
|
+
/** One camera keyframe: pan (x/y in px) and zoom (scale) at a progress. */
|
|
130
|
+
export interface CameraKeyframe {
|
|
131
|
+
/** Progress position, 0 to 1. */
|
|
132
|
+
at: number;
|
|
133
|
+
/** Horizontal pan in px. Default 0. */
|
|
134
|
+
x?: number;
|
|
135
|
+
/** Vertical pan in px. Default 0. */
|
|
136
|
+
y?: number;
|
|
137
|
+
/** Zoom factor. Default 1. */
|
|
138
|
+
scale?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Easing for the segment that ends at this keyframe, following the
|
|
141
|
+
* CSS keyframe convention. Default "linear".
|
|
142
|
+
*/
|
|
143
|
+
easing?: Easing | EasingName;
|
|
144
|
+
}
|
|
145
|
+
export interface CameraOptions {
|
|
146
|
+
/** 0-to-1 progress signal driving the camera. */
|
|
147
|
+
progress: Accessor<number>;
|
|
148
|
+
/** Fallback easing for segments without their own. Default "linear". */
|
|
149
|
+
easing?: Easing | EasingName;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Camera moves for a motion-design stage: pan and zoom driven by a
|
|
153
|
+
* 0-to-1 progress signal, returned as a compositor-friendly transform
|
|
154
|
+
* string (`translate3d(...) scale(...)`).
|
|
155
|
+
*
|
|
156
|
+
* Drive `progress` with anything: a `createScenePlayer` scene's own
|
|
157
|
+
* clock, an `animate()` tween, or scroll. Keyframes sort themselves by
|
|
158
|
+
* `at`; progress outside the range clamps to the end poses.
|
|
159
|
+
*
|
|
160
|
+
* Pure computation, no listeners, no rAF: SSR-safe by construction.
|
|
161
|
+
* Under reduced motion it holds the final keyframe's pose.
|
|
162
|
+
*
|
|
163
|
+
* ```tsx
|
|
164
|
+
* const [p, setP] = createSignal(0)
|
|
165
|
+
* // Slow dolly-in across the scene.
|
|
166
|
+
* const cam = createCamera({
|
|
167
|
+
* progress: p,
|
|
168
|
+
* keyframes... // via options below
|
|
169
|
+
* })
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function createCamera(keyframes: CameraKeyframe[], options: CameraOptions): Accessor<string>;
|
|
173
|
+
export interface ColorShiftOptions {
|
|
174
|
+
/** Milliseconds to travel across all stops. Default 1200. */
|
|
175
|
+
duration?: number;
|
|
176
|
+
/** Delay before starting, in milliseconds. Default 0. */
|
|
177
|
+
delay?: number;
|
|
178
|
+
/** Fallback easing for stop segments without their own. Default "linear". */
|
|
179
|
+
easing?: Easing | EasingName;
|
|
180
|
+
/** Output format. Default "hex". */
|
|
181
|
+
format?: ColorFormat;
|
|
182
|
+
}
|
|
183
|
+
export type ColorShiftStatus = "idle" | "running" | "done";
|
|
184
|
+
export interface ColorShiftControls {
|
|
185
|
+
/** The interpolated color as a string signal. */
|
|
186
|
+
color: Accessor<string>;
|
|
187
|
+
/** Play the shift. Resolves at the final stop. */
|
|
188
|
+
play: () => Promise<void>;
|
|
189
|
+
/** Stop mid-shift. The play() promise resolves. */
|
|
190
|
+
stop: () => void;
|
|
191
|
+
/** Stop and play again from the first stop. */
|
|
192
|
+
replay: () => Promise<void>;
|
|
193
|
+
/** Reactive status: "idle" | "running" | "done". */
|
|
194
|
+
status: Accessor<ColorShiftStatus>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Time-based color interpolation across stops: the sibling of
|
|
198
|
+
* `createScrollColor` for motion graphics, where color shifts run on a
|
|
199
|
+
* clock instead of scroll. Colors interpolate in linear light, so
|
|
200
|
+
* midpoints stay vivid, and alpha channels interpolate too.
|
|
201
|
+
*
|
|
202
|
+
* Under reduced motion `play()` jumps straight to the final stop's
|
|
203
|
+
* color. SSR-safe: `color()` returns the final stop's color.
|
|
204
|
+
*
|
|
205
|
+
* ```ts
|
|
206
|
+
* const shift = createColorShift(
|
|
207
|
+
* [
|
|
208
|
+
* { at: 0, color: "#0a1220" },
|
|
209
|
+
* { at: 0.5, color: "#2f8fdd" },
|
|
210
|
+
* { at: 1, color: "#d9a441", easing: "easeInOutQuad" },
|
|
211
|
+
* ],
|
|
212
|
+
* { duration: 2000 },
|
|
213
|
+
* )
|
|
214
|
+
* shift.color() // "#0a1220" ... "#d9a441" as it plays
|
|
215
|
+
* await shift.play()
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export declare function createColorShift(stops: ColorStop[], options?: ColorShiftOptions): ColorShiftControls;
|
|
219
|
+
/** How one scene hands off to the next. */
|
|
220
|
+
export type TransitionType = "cut" | "fade" | "slide" | "wipe";
|
|
221
|
+
/** Direction for "slide" and "wipe". */
|
|
222
|
+
export type TransitionDirection = "left" | "right" | "up" | "down";
|
|
223
|
+
export interface TransitionOptions {
|
|
224
|
+
/** Transition style. Default "fade". */
|
|
225
|
+
type?: TransitionType;
|
|
226
|
+
/** Direction for "slide" and "wipe". Default "left". */
|
|
227
|
+
direction?: TransitionDirection;
|
|
228
|
+
/** Duration in milliseconds. Default 500. */
|
|
229
|
+
duration?: number;
|
|
230
|
+
/** Easing. Default "easeInOutCubic". */
|
|
231
|
+
easing?: Easing | EasingName;
|
|
232
|
+
}
|
|
233
|
+
/** Compositor-friendly style for one side of a transition. */
|
|
234
|
+
export interface TransitionLayerStyle {
|
|
235
|
+
opacity: string;
|
|
236
|
+
transform: string;
|
|
237
|
+
clipPath: string;
|
|
238
|
+
}
|
|
239
|
+
export type TransitionStatus = "idle" | "running" | "done";
|
|
240
|
+
export interface TransitionControls {
|
|
241
|
+
/** 0-to-1 progress of the handoff. */
|
|
242
|
+
progress: Accessor<number>;
|
|
243
|
+
/** Style for the outgoing scene's layer. */
|
|
244
|
+
outgoing: Accessor<TransitionLayerStyle>;
|
|
245
|
+
/** Style for the incoming scene's layer. */
|
|
246
|
+
incoming: Accessor<TransitionLayerStyle>;
|
|
247
|
+
/** Play the handoff. Resolves when the incoming scene owns the frame. */
|
|
248
|
+
play: () => Promise<void>;
|
|
249
|
+
/** Stop mid-handoff. The play() promise resolves. */
|
|
250
|
+
stop: () => void;
|
|
251
|
+
/** Stop and play the handoff again. */
|
|
252
|
+
replay: () => Promise<void>;
|
|
253
|
+
/** Reactive status: "idle" | "running" | "done". */
|
|
254
|
+
status: Accessor<TransitionStatus>;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Match-cut style scene handoffs: `outgoing()` and `incoming()` return
|
|
258
|
+
* style objects for the two scene layers, driven by one 0-to-1 progress.
|
|
259
|
+
*
|
|
260
|
+
* - "cut": instant swap, no animation.
|
|
261
|
+
* - "fade": crossfade.
|
|
262
|
+
* - "slide": the outgoing scene exits one way while the incoming scene
|
|
263
|
+
* enters from the opposite side.
|
|
264
|
+
* - "wipe": the incoming scene reveals over the outgoing one with a
|
|
265
|
+
* clip-path wipe.
|
|
266
|
+
*
|
|
267
|
+
* Everything animates on opacity, transform, or clip-path, so handoffs
|
|
268
|
+
* stay on the compositor. Under reduced motion every type degrades to a
|
|
269
|
+
* cut: the swap happens instantly.
|
|
270
|
+
*
|
|
271
|
+
* ```tsx
|
|
272
|
+
* const cut = createTransition({ type: "wipe", direction: "left", duration: 600 })
|
|
273
|
+
* const go = async () => {
|
|
274
|
+
* showSceneB()
|
|
275
|
+
* await cut.play()
|
|
276
|
+
* }
|
|
277
|
+
* <div style={cut.outgoing()}>{sceneA}</div>
|
|
278
|
+
* <div style={cut.incoming()}>{sceneB}</div>
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export declare function createTransition(options?: TransitionOptions): TransitionControls;
|
|
282
|
+
export interface BeatOptions {
|
|
283
|
+
/** Beats per minute. Default 120. */
|
|
284
|
+
bpm?: number;
|
|
285
|
+
/** Beats per bar. Default 4. */
|
|
286
|
+
beatsPerBar?: number;
|
|
287
|
+
}
|
|
288
|
+
export type BeatStatus = "idle" | "running";
|
|
289
|
+
export interface BeatControls {
|
|
290
|
+
/** Whole beats elapsed since start(). */
|
|
291
|
+
beat: Accessor<number>;
|
|
292
|
+
/** Whole bars elapsed since start(). */
|
|
293
|
+
bar: Accessor<number>;
|
|
294
|
+
/** Fractional position within the current beat, 0 to 1. */
|
|
295
|
+
phase: Accessor<number>;
|
|
296
|
+
/**
|
|
297
|
+
* Register a callback fired on every beat with the beat index.
|
|
298
|
+
* Returns an unsubscribe function.
|
|
299
|
+
*/
|
|
300
|
+
onBeat: (cb: (beat: number) => void) => () => void;
|
|
301
|
+
/** Start the clock. No-op if already running. */
|
|
302
|
+
start: () => void;
|
|
303
|
+
/** Stop the clock. */
|
|
304
|
+
stop: () => void;
|
|
305
|
+
/** Reactive status: "idle" | "running". */
|
|
306
|
+
status: Accessor<BeatStatus>;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* A beat clock for cutting on the music: at 120 BPM it ticks twice a
|
|
310
|
+
* second, and `onBeat` fires your scene cuts, kinetic type replays, or
|
|
311
|
+
* color shifts in time. `phase()` gives the fractional position inside
|
|
312
|
+
* the current beat for syncing continuous motion to the rhythm.
|
|
313
|
+
*
|
|
314
|
+
* Beats are timing, not motion, so the clock keeps ticking under
|
|
315
|
+
* reduced motion (your callbacks decide what that means visually).
|
|
316
|
+
* SSR-safe: `start()` is a no-op without requestAnimationFrame.
|
|
317
|
+
*
|
|
318
|
+
* ```ts
|
|
319
|
+
* const beat = createBeat({ bpm: 128 })
|
|
320
|
+
* const off = beat.onBeat((b) => {
|
|
321
|
+
* if (b % 8 === 0) player.next() // cut scenes every 2 bars
|
|
322
|
+
* })
|
|
323
|
+
* beat.start()
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
export declare function createBeat(options?: BeatOptions): BeatControls;
|
|
327
|
+
export {};
|