Live values
A value that changes as the page is used, a pointer's place or a slider's, goes straight into an element's style. Where Motion needs a motion value, Wardic takes a signal: the element follows it, and nothing re-renders.
const [x, setX] = createSignal(0)
<w.div style={{ x }} />The create* primitives make values from values, each an accessor that style takes too. Here, two springs follow the pointer's place:
import { createSpring, w } from "@wardic/solid/unstable/v2"
import { createSignal } from "solid-js"
/** A dot that follows the pointer: the pointer sets two signals, and two springs follow them. */
export default function Follow() {
const [x, setX] = createSignal(0)
const [y, setY] = createSignal(0)
const springX = createSpring(x, { stiffness: 300, damping: 20 })
const springY = createSpring(y, { stiffness: 300, damping: 20 })
const follow = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {
const box = event.currentTarget.getBoundingClientRect()
setX(event.clientX - box.left - 20)
setY(event.clientY - box.top - 20)
}
return (
<div class="sample-field" onPointerMove={follow}>
<w.div class="sample-dot" style={{ x: springX, y: springY }} />
</div>
)
}import { createSpring, w } from "@wardic/solid"
import { createSignal } from "solid-js"
/** A dot that follows the pointer: the pointer sets two signals, and two springs follow them. */
export default function Follow() {
const [x, setX] = createSignal(0)
const [y, setY] = createSignal(0)
const springX = createSpring(x, { stiffness: 300, damping: 20 })
const springY = createSpring(y, { stiffness: 300, damping: 20 })
const follow = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {
const box = event.currentTarget.getBoundingClientRect()
setX(event.clientX - box.left - 20)
setY(event.clientY - box.top - 20)
}
return (
<div class="sample-field" onPointerMove={follow}>
<w.div class="sample-dot" style={{ x: springX, y: springY }} />
</div>
)
}import { motion, useMotionValue, useSpring } from "motion/react"
import type { PointerEvent } from "react"
/** A dot that follows the pointer: the pointer sets two motion values, and two springs follow them. */
export default function Follow() {
const x = useMotionValue(0)
const y = useMotionValue(0)
const springX = useSpring(x, { stiffness: 300, damping: 20 })
const springY = useSpring(y, { stiffness: 300, damping: 20 })
const follow = (event: PointerEvent<HTMLDivElement>) => {
const box = event.currentTarget.getBoundingClientRect()
x.set(event.clientX - box.left - 20)
y.set(event.clientY - box.top - 20)
}
return (
<div className="sample-field" onPointerMove={follow}>
<motion.div className="sample-dot" style={{ x: springX, y: springY }} />
</div>
)
}From one value to another
createSpring(source, options)followssourceon a spring,stiffness,dampingandmass, or avisualDurationandbounce. A change mid-way keeps its speed.jump(value)puts it somewhere at once.createFollowValue(source, transition)follows on any transition: a tween, a spring or an inertia.createTransform(source, input, output)maps ranges: a source atinput[i]givesoutput[i], and blends between them, numbers, units and colours alike.createTransform(source, fn)maps through a function.createVelocity(source)is how fastsourceis changing, in its units a second. A velocity is a value too, socreateVelocity(createVelocity(x))is its acceleration.
const opacity = createTransform(x, [-150, 0, 150], [0, 1, 0])
const background = createTransform(x, [-150, 150], ["#bf616a", "#a3be8c"])From time
createTime()is the milliseconds since it was made, for something that turns forever:createTransform(createTime(), (ms) => (ms / 1000) * 90)is 90° a second.createAnimationFrame((time, delta) => …)calls you every frame, for drawing that isn't an element's style.
Where an element is
A value you give is never written to: it's what the element follows. What Wardic draws, mid-animation, comes from the element's ward, as an accessor of the value it's drawn at, to drive another value from a drag, say:
- On Solid 2,
card.read("x"), fromconst card = w.ward({ drag: "x" })given aswardRef={card}. - On Solid 1,
card.value("x"), fromconst card = w.createWard({ drag: "x" })spread onto the element.
const card = w.ward({ drag: "x" })
const opacity = createTransform(card.read("x"), [-150, 0, 150], [0, 1, 0])
<w.div wardRef={card} style={{ opacity }} />Where they live
Make them in a component's body, where you'd make a signal: each one lives as long as its owner. On the server, each is its source's value at that moment. Scroll values are live values too.