boardweaver/motion)The platform bundles Motion — the motion package, version
12.43.0, formerly Framer Motion — and exposes its React surface as
boardweaver/motion. Like every bundled library it resolves to a single shared copy the frame
provides, so nothing is added to your bundle and your game is version-locked to that copy.
import { motion, AnimatePresence } from "boardweaver/motion";
Board games are animation-heavy and hand-rolled CSS transitions are where generated code is weakest. Two primitives do most of the work, and they map directly onto what a board game needs.
layoutId — a piece moving from A to BGive the same layoutId to an element in two places and Motion animates between them
automatically, however the tree is restructured. This is "a card moves from hand to table"
expressed in one prop — no measuring, no coordinates.
{hand.map((card) => (
<motion.div key={card.id} layoutId={card.id} onClick={() => play(card.id)}>
{card.name}
</motion.div>
))}
Render the same layoutId inside the table area next render and the card flies there. Wrap
groups that should animate together in <LayoutGroup>.
AnimatePresence — pieces entering and leavingReact removes an element the moment it leaves the tree, which is exactly wrong for a captured
piece or a played card. AnimatePresence keeps it mounted until its exit animation finishes.
This matters more than it looks: a broadcast can splice a piece out of the middle of the array,
so pieces disappear without warning.
<AnimatePresence>
{pieces.map((p) => (
<motion.div
key={p.pieceId}
initial={{ scale: 0 }}
animate={{ scale: 1 }}
exit={{ scale: 0, opacity: 0 }}
/>
))}
</AnimatePresence>
key must be stable and unique or exit animations will not run.
useLastChange() (see the match API section) reports which piece and space ids changed in the
last snapshot, whether it was your own move, and whether several actions were coalesced into one
update. Combine it with layoutId and you get opponent moves animating for free.
The platform cannot tell you what an action meant — "a capture happened" is not derivable from
a state diff. If you need that, have applyActions write a breadcrumb onto metaData and read
it in the client.
Some players get motion sick. This is not optional polish:
import { MotionConfig, useReducedMotion } from "boardweaver/motion";
// Whole-subtree: honours the player's OS setting.
<MotionConfig reducedMotion="user">…</MotionConfig>
// Or branch on it yourself.
const reduced = useReducedMotion();
<motion.div transition={{ duration: reduced ? 0 : 0.3 }} />
| Import | Use it for |
|---|---|
motion |
The animated elements: motion.div, motion.button, motion.svg, … |
AnimatePresence |
Exit animations for elements leaving the tree |
LayoutGroup |
Coordinating layout animations across siblings |
MotionConfig |
Subtree-wide defaults, including reducedMotion |
useReducedMotion |
Branching on the player's motion preference |
useAnimate |
Imperative sequences (animate(scope.current, …)) |
useMotionValue |
Animated state that does not re-render on every frame |
useTransform |
Deriving one motion value from another |
useSpring |
Spring-smoothing a motion value |
useMotionTemplate |
Composing motion values into a string (e.g. a CSS filter) |
useMotionValueEvent |
Subscribing to a motion value's changes |
useInView |
Whether an element is in the viewport |
usePresence / useIsPresent |
Custom exit choreography inside AnimatePresence |
useAnimationFrame |
A per-frame callback |
Types: MotionProps, MotionStyle, HTMLMotionProps, SVGMotionProps, Variants,
Transition, TargetAndTransition, VariantLabels, MotionValue,
AnimationPlaybackControls, AnimatePresenceProps, MotionConfigProps, UseInViewOptions.
Gesture props (whileHover, whileTap, whileDrag, drag) are props on motion.* elements,
not separate imports.
Anything not in the tables above is not part of the platform surface, even if
motion.dev documents it — Reorder, LazyMotion, m, useScroll and
Motion's internals are deliberately excluded. Use boardweaver/dnd for dragging things around;
it is the blessed drag surface and handles keyboard dragging, which Motion's drag does not.
import { motion } from "motion/react", use
import { motion } from "boardweaver/motion". Importing motion, motion/react or
framer-motion directly is a compile error — those specifiers do not exist inside a game.