Animation Overview
AraraJS’s execution model is supposed to be minimal, powerful and flexible. Some of it’s features include:
- 🐦️ Frame-based animation loop with precise timing control
- 🐦️ Composable animation callbacks for complex behaviors
- 🐦️ Smart state management with automatic cleanup
- 🐦️ Server-side rendering compatible
Bare Metal API Section titled Bare Metal API
The animation system is built around some basic building blocks:
- Animation Callbacks - Just a function that is called on each frame.
- Animation Controller - Manages the animation loop and timing.
These basic building blocks don’t output a signal for you, they just manage timing and possibly orchestration of your animations.
Body Animations Section titled Body Animations
To get an output signal in a more convenient way, you may want to create a Body
animation. Maybe you are not interested in how your signal change, which is the concept of velocity
, but keep in mind that both velocity
and acceleration
are present in the Body
object returned by the signal in case you need them in some point.
Maybe you won’t use them all, but the primitives come with them.
Composition and Other Primitives Section titled Composition and Other Primitives
Some common body animation primitives, like spring
and sine wave
, are available to you by the library. They come both in the form of just a callback, a BodyAnimationPass
, which is a callback that applies changes to the body on every frame, and they also come in more convenient createSpring
, createSine
, … variants.
const [sine] = createSineWave()
// is equivalent to
const [sine] = createBodyAnimation(() => [
sineWavePass()
])
import { cn } from '@lib/cn'
import { createElementSize } from '@solid-primitives/resize-observer'
import { createSignal } from 'solid-js'
import { createSineWave } from 'ararajs'
export function SineWaveDemo(props: {
class?: string
ballClass?: string
frequency?: () => number
}) {
const [body] = createSineWave(() => ({
amplitude: 90,
frequency: props.frequency?.() ?? 1,
}))
const [container, setContainer] = createSignal<HTMLDivElement>()
const containerSize = createElementSize(container)
const [ball, setBall] = createSignal<HTMLDivElement>()
const ballSize = createElementSize(ball)
const xOffset = () => {
return (
body.position +
-(ballSize.width ?? 0) / 2 +
(containerSize.width ?? 0) / 2
)
}
return (
<div
class={cn(
'w-full overflow-hidden rounded-lg p-8 shadow-inner',
props.class,
)}
ref={setContainer}
>
<div
class={cn(
'size-8 rounded-full bg-arara-text/70 shadow-xl',
props.ballClass,
)}
style={{
transform: `translate(${xOffset()}px`,
}}
ref={setBall}
/>
</div>
)
}
Using the BodyAnimationPass
will give you more flexibility because you can input multiple passes in a createBodyAnimation
and these passes are applied in order. It’s easy to combine multiple Sines and Springs with that, which gives you easings and periodic behaviours.