### Game Scene Setup with Physics in TypeScript Source: https://context7.com/usirin/snowtail/llms.txt Scene component that initializes Canvas with camera position, applies gravity physics, adds ambient and directional lighting, and renders the Player component. Provides complete 3D environment setup for the physics-based player controller. ```typescript function GameScene() { return ( {/* Ground plane */} ``` -------------------------------- ### Player Component with State Machine Setup in TypeScript Source: https://context7.com/usirin/snowtail/llms.txt Main player component that initializes physics body, wraps physics vectors, configures input key mapping, and establishes state machine with four states (Idle, Walking, Jumping, Falling). Implements camera follow functionality using useFrame hook and manages state transitions based on movement and jump context. ```typescript function Player() { const { managers: { input } } = useGame(); // Setup physics const [ref, api] = useBox(() => ({ args: [1, 3, 1], mass: 50, position: [0, 5, 0], fixedRotation: true, type: "Dynamic", })); // Wrap physics vectors const player: PlayerAPI = { position: useWorkerVector(api.position), velocity: useWorkerVector(api.velocity), rotation: useWorkerVector(api.rotation), }; // Setup input mapping useEffect(() => { input.addKeyMap("a", "MoveLeft"); input.addKeyMap("d", "MoveRight"); input.addKeyMap(" ", "Jump"); }, [input]); // State machine with behaviors const [currentState] = useStateMachine({ initialState: "Idle", context: { moving: false, jumping: false }, states: { Idle: { behaviors: [ new Move(player, 0, input), new TriggerJump(input), ], update: (api) => { if (api.context.moving) api.transition("Walking"); if (api.context.jumping) api.transition("Jumping"); }, }, Walking: { behaviors: [ new Move(player, 5, input), new TriggerJump(input), ], update: (api) => { if (!api.context.moving) api.transition("Idle"); if (api.context.jumping) api.transition("Jumping"); }, }, Jumping: { behaviors: [ new ExecuteJump(player, 8), new Move(player, 3, input), ], }, Falling: { behaviors: [new Move(player, 3, input)], update: (api) => { const [, vy] = player.velocity.get(); // Check if landed (velocity near zero) if (Math.abs(vy) < 0.1) { api.transition(api.context.moving ? "Walking" : "Idle"); } }, }, }, }); // Camera follow useFrame((state) => { const [x] = player.position.get(); state.camera.position.x = x; }); console.log("Current player state:", currentState); return ( ); } ``` -------------------------------- ### PubSub: Type-Safe Event Publishing and Subscription (TypeScript) Source: https://context7.com/usirin/snowtail/llms.txt Implements a global event system for decoupled communication using type-safe event definitions. Supports asynchronous event handlers and automatic handler snapshotting. Requires the 'pkg/pubsub' package. Handles event publishing, subscription, and checking for active subscriptions. ```typescript import { createPubSub, PubSubEvent } from "pkg/pubsub"; // Define typed events interface PlayerDiedEvent extends PubSubEvent<"player-died", { position: [number, number, number]; cause: string; }> {} interface ScoreUpdatedEvent extends PubSubEvent<"score-updated", { score: number; combo: number; }> {} // Create pub-sub instance (typically done in Game component) const pubsub = createPubSub(); // Subscribe to events const unsubscribe = pubsub.subscribe( "player-died", async (data) => { console.log(`Player died at [${data.position}] due to: ${data.cause}`); await saveGameState(); await showDeathScreen(); } ); // Publish events from anywhere async function killPlayer(position, cause) { const success = await pubsub.publish("player-died", { position, cause, }); if (success) { console.log("Death handlers executed"); } else { console.log("No subscribers for player-died event"); } } // Multiple subscribers work simultaneously pubsub.subscribe("score-updated", (data) => { updateUI(data.score); }); pubsub.subscribe("score-updated", (data) => { if (data.combo > 5) { console.log("Amazing combo!"); } }); // Check if event has subscribers if (pubsub.hasSubscriptions("score-updated") > 0) { await pubsub.publish("score-updated", { score: 1000, combo: 7, }); } // Clean up subscription unsubscribe(); // Expected output: All subscribers receive events, async handlers execute // in parallel, unsubscribe prevents future event delivery ``` -------------------------------- ### usePubsubEvent: React Hook for Event Subscriptions (TypeScript) Source: https://context7.com/usirin/snowtail/llms.txt A React hook that simplifies subscribing to PubSub events within functional components. It automatically handles subscription and cleanup on component unmount, ensuring efficient event integration. Requires 'pkg/pubsub/use-pubsub-event' and 'pkg/pubsub'. ```typescript import { usePubsubEvent } from "pkg/pubsub/use-pubsub-event"; import { PubSubEvent } from "pkg/pubsub"; import { useState } from "react"; interface CoinCollectedEvent extends PubSubEvent<"coin-collected", { coinId: string; value: number; }> {} function ScoreDisplay() { const [score, setScore] = useState(0); const [lastCoinId, setLastCoinId] = useState(""); usePubsubEvent( "coin-collected", (data) => { console.log(`Collected coin ${data.coinId} worth ${data.value}`); setScore(prevScore => prevScore + data.value); setLastCoinId(data.coinId); return data; // Return value passed to next handler }, [setScore, setLastCoinId] // Dependencies ); return (

Score: {score}

Last collected: {lastCoinId}

); } // In another component, publish the event function Coin({ id, value }) { const { publish } = useGame(); const handleCollision = async () => { await publish("coin-collected", { coinId: id, value: value, }); }; return ...; } // Expected output: Score updates automatically when coins are collected, // subscription automatically cleaned up when component unmounts ``` -------------------------------- ### SceneManager - Multi-Scene Game Navigation with State Persistence Source: https://context7.com/usirin/snowtail/llms.txt React component system that manages multiple game scenes with level support, state persistence per scene, and lifecycle callbacks. Enables scene transitions with automatic cleanup and provides hooks for accessing current scene state, changing levels, and resetting scenes. ```typescript import { SceneManager, Scene } from "snowtail/engine"; import { useSceneManager } from "snowtail/engine/use-scene-manager"; function GameRoot() { return ( ); } function MenuScene() { const { setScene } = useSceneManager(); const startGame = () => { setScene("gameplay:1"); }; return ( ); } function GameplayScene() { const { currentLevel, setLevel, setSceneState, getSceneState, resetScene } = useSceneManager(); useEffect(() => { setSceneState("enemiesDefeated", 0); setSceneState("startTime", Date.now()); return () => { console.log("Exiting gameplay scene"); }; }, []); const completeLevel = () => { const defeated = getSceneState("enemiesDefeated"); console.log(`Level ${currentLevel} completed! Enemies: ${defeated}`); if (currentLevel < 3) { setLevel(currentLevel + 1); } else { setScene("gameover"); } }; const restartLevel = () => { resetScene(); }; return ( Level {currentLevel} Next Level Restart ); } ``` -------------------------------- ### Access Global Game State and Event System with useGame Source: https://context7.com/usirin/snowtail/llms.txt The useGame hook returns the global game context containing pause state, pub-sub event system, and manager references. This provides access to all core game systems from any component within the Game provider tree. Use subscribe() to listen for game events and publish() to trigger events across the application. ```typescript import { useGame } from "snowtail/engine/use-game"; import { useEffect } from "react"; function GameUI() { const { paused, setPaused, publish, subscribe, managers } = useGame(); const { input } = managers; useEffect(() => { // Subscribe to game events const unsubscribe = subscribe("player-died", (data) => { console.log("Player died at position:", data.position); setPaused(true); }); return unsubscribe; }, [subscribe, setPaused]); const handleReset = async () => { setPaused(false); await publish("game-reset", { timestamp: Date.now() }); }; return (

Game Status: {paused ? "Paused" : "Running"}

); } // Expected output: UI that displays game status and can trigger game events ``` -------------------------------- ### PlayerAPI and PlayerContext Interfaces in TypeScript Source: https://context7.com/usirin/snowtail/llms.txt Type definitions for player physics API and state context. PlayerAPI wraps position, velocity, and rotation vectors from physics engine, while PlayerContext tracks movement and jumping state flags for state machine transitions. ```typescript interface PlayerAPI { position: ReturnType; velocity: ReturnType; rotation: ReturnType; } interface PlayerContext { moving: boolean; jumping: boolean; } ``` -------------------------------- ### Map Keyboard Input to Actions with useInputManager Source: https://context7.com/usirin/snowtail/llms.txt The useInputManager hook creates an input manager that maps keyboard keys to named actions with support for continuous press detection and single-frame "just pressed" events. Key state is automatically cleaned up every frame, enabling efficient input handling for game mechanics like movement and jumping. ```typescript import { useInputManager } from "snowtail/engine/use-input-manager"; import { useEffect } from "react"; import { useFrame } from "react-three-fiber"; function PlayerController() { const inputManager = useInputManager(); useEffect(() => { // Map physical keys to action names inputManager.addKeyMap("w", "MoveForward"); inputManager.addKeyMap("a", "MoveLeft"); inputManager.addKeyMap("d", "MoveRight"); inputManager.addKeyMap(" ", "Jump"); }, [inputManager]); useFrame((state, delta) => { const moveLeft = inputManager.getKey("MoveLeft"); const jump = inputManager.getKey("Jump"); // Continuous movement while key held if (moveLeft.pressed) { console.log("Moving left at speed:", delta * 5); } // One-time action on key press if (jump.justPressed) { console.log("Jump triggered!"); } }); return null; } // Expected output: Console logs showing movement every frame when 'a' is held, // and "Jump triggered!" only once per spacebar press ``` -------------------------------- ### Character Movement and Jumping with XState in React Source: https://context7.com/usirin/snowtail/llms.txt This snippet demonstrates how to integrate XState machines for character movement and jumping within a React application using the @xstate/react hook. It manages jump duration and movement persistence, logging state changes to the console. Dependencies include @xstate/react, snowtail/machines, and three. ```typescript import { useMachine } from "@xstate/react"; import { createJumpingMachine } from "snowtail/machines/jumping"; import { createMovingMachine } from "snowtail/machines/moving"; import { Vector3 } from "three"; import { useFrame } from "@react-three/fiber"; function CharacterWithXState() { // Jump state machine (1000ms jump duration) const [jumpState, sendJump] = useMachine(createJumpingMachine(1000)); // Movement state machine const [moveState, sendMove] = useMachine( createMovingMachine(new Vector3(5, 0, 0)) ); useFrame((state, delta) => { // Check jump state if (jumpState.matches("on")) { console.log("Currently jumping"); console.log("Jump duration:", jumpState.context.duration); } // Check movement state if (moveState.matches("on")) { const velocity = moveState.context.velocity; console.log("Moving with velocity:", velocity); } }); const handleJump = () => { if (jumpState.matches("off")) { sendJump({ type: "JUMP" }); } }; const handleMove = () => { sendMove({ type: "MOVE", velocity: new Vector3(10, 0, 0) }); }; const handleStop = () => { sendMove({ type: "STOP" }); }; return ( Jump Button Move Button Stop Button ); } // Expected output: State machines that manage timing and transitions, // jump automatically completes after duration, movement persists until stopped ``` -------------------------------- ### Move Behavior Implementation in TypeScript Source: https://context7.com/usirin/snowtail/llms.txt Reusable state behavior class that handles player movement based on input key states. Updates player position and rotation based on left/right input, with configurable speed parameter. Integrates with input manager to check key press states and updates movement context flag. ```typescript class Move implements StateBehavior { constructor( private player: PlayerAPI, private speed: number, private inputManager: any ) {} update(api, delta) { const moveLeft = this.inputManager.getKey("MoveLeft"); const moveRight = this.inputManager.getKey("MoveRight"); if (moveLeft.pressed && !moveRight.pressed) { const [x, y, z] = this.player.position.get(); this.player.position.set(x - delta * this.speed, y, z); this.player.rotation.set(0, -Math.PI / 2, 0); api.context.moving = true; } else if (moveRight.pressed && !moveLeft.pressed) { const [x, y, z] = this.player.position.get(); this.player.position.set(x + delta * this.speed, y, z); this.player.rotation.set(0, Math.PI / 2, 0); api.context.moving = true; } else { api.context.moving = false; } } } ``` -------------------------------- ### useStateMachine: React State Management with Behaviors Source: https://context7.com/usirin/snowtail/llms.txt The useStateMachine hook enables behavior-driven state management in React, integrating with React Three Fiber's render loop. It supports multiple behaviors per state, context sharing, and automatic lifecycle management via callbacks like onBeforeEnter, onEnter, update, and onExit. Essential for complex character or object states. ```typescript import { useStateMachine, StateBehavior } from "snowtail/engine/use-state-machine"; import { useFrame } from "react-three-fiber"; interface CharacterContext { health: number; speed: number; grounded: boolean; } class GroundCheck implements StateBehavior { update(api, delta, context) { // Check if character is on ground (simplified) const isGrounded = context.camera.position.y < 1; api.context.grounded = isGrounded; } } class IdleBehavior implements StateBehavior { onEnter(api) { console.log("Character entered idle state"); api.context.speed = 0; } update(api, delta) { if (!api.context.grounded) { api.transition("Falling"); } } onExit(api) { console.log("Character exiting idle state"); } } function Character() { const [currentState, api] = useStateMachine({ initialState: "Idle", context: { health: 100, speed: 0, grounded: true, }, states: { Idle: { behaviors: [new GroundCheck(), new IdleBehavior()], update: (api, delta) => { // State-specific update logic if (api.context.health <= 0) { api.transition("Dead"); } }, }, Walking: { behaviors: [new GroundCheck()], update: (api, delta) => { api.context.speed = 5; }, }, Falling: { behaviors: [new GroundCheck()], update: (api, delta) => { if (api.context.grounded) { api.transition("Idle"); } }, }, Dead: { behaviors: [], }, }, }); return Current State: {currentState}; } // Expected output: State transitions logged to console, context.speed // updated based on state, automatic ground checking every frame ``` -------------------------------- ### useAnimationMixer - State Machine Animation Control in Three.js React Source: https://context7.com/usirin/snowtail/llms.txt Custom React hook that manages Three.js animations using a state machine pattern. Automatically caches animation clips, handles mixer updates every frame, and provides action references for direct animation control. Supports smooth blending between animations with fade transitions and configurable loop behaviors. ```typescript import { useAnimationMixer } from "pkg/use-animation-mixer"; import { useGLTF } from "@react-three/drei"; import { useEffect } from "react"; import { LoopRepeat } from "three"; function AnimatedCharacter() { const gltf = useGLTF("/models/character.glb"); const { mixer, actions } = useAnimationMixer(gltf, (mixer, clips) => { const idleClip = clips.find(c => c.name === "Idle"); const walkClip = clips.find(c => c.name === "Walk"); const jumpClip = clips.find(c => c.name === "Jump"); return { initial: "Idle", states: { Idle: { action: mixer.clipAction(idleClip), onEnter: () => console.log("Playing idle animation"), }, Walk: { action: mixer.clipAction(walkClip), }, Jump: { action: mixer.clipAction(jumpClip), }, }, }; }); useEffect(() => { actions.Idle.setLoop(LoopRepeat, Infinity); actions.Idle.play(); actions.Walk.setLoop(LoopRepeat, Infinity); actions.Walk.setEffectiveTimeScale(1.2); actions.Jump.setLoop(LoopOnce, 1); actions.Jump.clampWhenFinished = true; }, [actions]); const switchToWalk = () => { actions.Idle.fadeOut(0.2); actions.Walk.reset().fadeIn(0.2).play(); }; return ; } ``` -------------------------------- ### Jump Execution Behavior in TypeScript Source: https://context7.com/usirin/snowtail/llms.txt State behavior for executing jump physics and managing jump-to-fall transitions. Uses onEnter lifecycle hook to apply vertical velocity impulse, then monitors falling state by checking for negative velocity to trigger transition to Falling state. ```typescript class ExecuteJump implements StateBehavior { constructor(private player: PlayerAPI, private jumpForce: number) {} onEnter(api) { const [vx, vy, vz] = this.player.velocity.get(); this.player.velocity.set(vx, this.jumpForce, vz); console.log("Jump executed with force:", this.jumpForce); } update(api, delta) { const [, vy] = this.player.velocity.get(); // Transition to falling when velocity becomes negative if (vy < 0) { api.transition("Falling"); } } } ``` -------------------------------- ### useWorkerVector: Synchronous Physics Data for Cannon.js Source: https://context7.com/usirin/snowtail/llms.txt The useWorkerVector hook provides synchronous access to Cannon.js physics worker data, which is typically asynchronous. This is crucial for reading physics values within the same frame they are updated, enabling real-time interaction and responsiveness in React Three Fiber applications. It wraps Cannon.js API objects. ```typescript import { useBox } from "@react-three/cannon"; import { useWorkerVector } from "snowtail/engine/use-worker-vector"; import { useFrame } from "react-three-fiber"; function PhysicsCharacter() { const [ref, api] = useBox(() => ({ args: [1, 2, 1], mass: 50, position: [0, 5, 0], })); // Wrap physics vectors for synchronous access const position = useWorkerVector(api.position, [0, 5, 0]); const velocity = useWorkerVector(api.velocity, [0, 0, 0]); const rotation = useWorkerVector(api.rotation, [0, 0, 0]); useFrame((state, delta) => { // Synchronously read current physics values const [x, y, z] = position.get(); const [vx, vy, vz] = velocity.get(); // Apply movement based on current state if (y > 0.5 && Math.abs(vy) < 0.1) { // Character is grounded, allow jump velocity.set(vx, 3, vz); } // Move camera to follow character state.camera.position.x = x; console.log(`Position: [${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}]`); }); return ( ); } // Expected output: Console logs showing real-time position updates, // character physics box that responds to gravity and can jump when grounded ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.