Animation - Kinematic Snake Simulation
A kinematic simulation of a snake moving on a 2D plane.
Animation - Kinematic Snake Simulation
Description
This is a simple simulation of a snake moving on a 2D plane.
How it Works
Core Data Structure
The snake is represented as an array of nodes, where each node contains:
x
: X-coordinate in 2D spacey
: Y-coordinate in 2D space Nodes are rendered using SVG<circle>
elements and connected with<line>
elements.
Kinematic Motion System
The movement algorithm follows these steps each frame:
Head Guidance: The leading node receives movement input
Cascade Propagation: Subsequent nodes follow their predecessors by:
- Calculating direction vectors between consecutive nodes
- Maintaining fixed inter-node distances
Position Update: Each node’s coordinates are recalculated using:
node[i].position = node[i-1].position + direction_vector * node_distance
Pathfinding Mechanism
An invisible waypoint (referred to as “bait”) drives the navigation:
- Waypoint Behavior:
- Moves in zig-zag patterns within viewport boundaries
- Triggers random repositioning upon boundary collision
- Head Movement:
- Head node moves towards the current waypoint with a small distance delta each frame
Motion Optimization
Two key constraints ensure natural movement:
- Body Flexion Limit:
- Prevents unrealistic bending angles between nodes
- Head Turning Rate Limit:
- Constrains instantaneous directional changes
Proximity-based relaxation (when head is close to the waypoint):
- Temporarily disables constraints to facilitate target acquisition
- Gradual constraint restoration after waypoint capture
This animation system implements the kinematic principles demonstrated in this video, specifically modeling:
- Vertebrate spinal movement through cascading node propagation
- Dynamic constraint relaxation during target acquisition
- Motion stabilization using flexion angle limits
Svelte Animation Architecture
The implementation demonstrates reactive animation control:
// store.ts
export const state = {
isAnimationRunning: false, // Master animation toggle
// ... other state properties
};
// animation logic.ts
let animationFrameId: number | null = null;
export function manageAnimationLoop() {
$effect(() => {
if (!state.isAnimationRunning) {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
return;
}
const frameHandler = () => {
updatePositions(); // Core kinematic calculations
animationFrameId = requestAnimationFrame(frameHandler);
};
animationFrameId = requestAnimationFrame(frameHandler);
return () => {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
};
});
}
// view.svelte
onMount(() => {
state.isAnimationRunning = true;
});
manageAnimationLoop();
onDestroy(() => {
state.isAnimationRunning = false;
});
Key implementation notes:
- Lifecycle Management:
onMount()
activates animationonDestroy()
ensures resource cleanup
- Reactive Control:
- The
$effect
block automatically manages animation state changes
- The
- Frame Budgeting:
- Uses browser-native
requestAnimationFrame
for optimal rendering
- Uses browser-native