Skill v1.0.1
currentAutomated scan100/100+2 new
name: flutter_scene-kit version: 8 description: Build interactive 3D gameplay, character controllers, camera rigs, dynamic day/night cycles, water surfaces, audio, pooling, and debug overlays in flutter_scene. Use when creating game mechanics, camera controls, NPC behaviors, atmospheric environments, or diagnostic HUDs.
Gameplay, camera, and atmosphere kit in flutter_scene
Flutter Scene provides high-level gameplay components and ergonomic building blocks in package:flutter_scene/kit.dart so games and interactive experiences do not need to re-implement standard mechanics from scratch.
When choosing components, consider existing engine alternatives:
- For physics-driven character navigation with collider capsules, wall sliding, and autostep, use
KinematicCharacterControllerfrompackage:flutter_scene/physics.dart. - For interactive mouse/touch orbit cameras with inertia, use
OrbitCameraControllerorFollowCameraController. - For framing a standalone
PerspectiveCamera, usePerspectiveCamera.framing. UseBoundsFramingwhen computing a transform for aNodeCameramounted in the scene graph. - When driving custom camera-relative movement or ground panning (WASD strafing, RTS/strategy camera drag), read
camera.horizontalRightandcamera.horizontalForward(orcamera.rightandnode.right). Never writeforward.cross(up), which points screen-left influtter_scene's left-handed (+Zforward) view space and horizontally invertsA/Dand drag controls.
Imports
import 'package:flutter_scene/scene.dart';import 'package:flutter_scene/kit.dart';import 'package:vector_math/vector_math.dart' as vm;
Camera rigs and smoothing
SpringArmComponent
SpringArmComponent attaches to a target character node and mounts a camera node at the arm's socket. It casts rays against the scene hierarchy to prevent geometry clipping, smoothly pulling the camera inward when colliding with walls.
Note on offsets: targetOffset is applied in world space from the character node's origin, and socketOffset acts in the camera socket's local plane along X (right) and Y (up).
Leave the mounted camera's near plane at its default. Every pass rasterizes with a near plane fitted to visible content each frame, so a chase or follow camera gets the depth precision of a much larger near without clipping the character when the arm pulls in. Raising near by hand clips the character at close range and gains nothing; the fit falls back to the authored value only when the camera sits inside an item's bounds (a sky sphere), so draw skies with scene.skybox.
final characterNode = Node();final cameraNode = Node();final cameraArm = SpringArmComponent(targetLength: 5.0,targetOffset: vm.Vector3(0, 1.6, 0), // Eye heightsocketOffset: vm.Vector3(0.5, 0, 0), // Over-the-shoulderenablePositionLag: true,positionLagSpeed: 8.0,cameraNode: cameraNode,);characterNode.addComponent(cameraArm);scene.root.add(characterNode);scene.root.add(cameraNode);
CameraShake
CameraShake implements a trauma-decay model driven by deterministic simplex noise for organic multi-axis camera shake (explosions, footsteps, hits).
final shake = CameraShake(decayRate: 1.2, frequency: 25.0);// Add trauma on hitshake.addTrauma(0.6);// Inside game loopfinal offset = shake.update(deltaSeconds);cameraNode.localTransform = baseTransform * offset.toMatrix4();
Character movement and steering
ThirdPersonControllerComponent
ThirdPersonControllerComponent handles kinematic movement, sprint multipliers, turn smoothing, ground snapping with raycasts, slope sliding, coyote time, and buffered jumps. Input expects +Y as forward in 3D.
final playerNode = Node();final controller = ThirdPersonControllerComponent(walkSpeed: 4.5,runMultiplier: 1.8,jumpVelocity: 7.0,groundPlaneHeight: 0.0, // Optional fallback floor);playerNode.addComponent(controller);// Pass rotatesToMovement: false to move the node without turning it; read// controller.yaw to drive a child mesh or animation from the heading instead.// When using VirtualJoystick (where up is -Y in screen space), invert Y:// controller.setMoveInput(vm.Vector2(joystickDir.x, -joystickDir.y), isRunning: isSprinting);if (jumpPressed) controller.jump();
Autonomous Steering Behaviors
Steering provides math helpers for NPC navigation, flocking, and crowd dynamics.
// Seek targetfinal seekForce = Steering.seek(npcPos, npcVel, targetPos, maxSpeed: 4.0);// Arrive smoothlyfinal arriveForce = Steering.arrive(npcPos, npcVel, targetPos, slowingRadius: 3.0);// Flocking separationfinal sepForce = Steering.separation(npcPos, npcVel, neighborPositions, desiredDistance: 1.5);
Dynamic environments and atmosphere
DayNightCycleComponent
DayNightCycleComponent moves the sun along a realistic solar arc given latitude and time of day, evaluating sun colors, intensities, and ambient lighting transitions.
final sunLight = DirectionalLight();final sunNode = Node()..addComponent(DirectionalLightComponent(sunLight));scene.root.add(sunNode);final skyCycle = DayNightCycleComponent(timeOfDay: 14.5, // 2:30 PMtimeSpeed: 0.1, // Progress 0.1 hours per secondlatitude: 34.0,sunLightNode: sunNode,);scene.root.addComponent(skyCycle);
WaterSurfaceComponent
WaterSurfaceComponent evaluates multi-harmonic Gerstner trochoidal waves for water surfaces and floating buoyancy queries.
final water = WaterSurfaceComponent();final surface = water.evaluateAt(vm.Vector2(playerPos.x, playerPos.z));final waterHeight = surface.displacement.y;final waterNormal = surface.normal;
Immediate-mode debug visualization
DebugDraw provides static immediate-mode line, ray, box, sphere, axis, and physics collider drawing utilities for physics debugging and AI visualizers.
DebugDraw.line(startPos, endPos, color: vm.Vector4(1, 0, 0, 1));DebugDraw.box(aabb, color: vm.Vector4(0, 1, 0, 1));DebugDraw.sphere(center, 1.0, color: vm.Vector4(0, 0, 1, 1));DebugDraw.axes(node.globalTransform, size: 2.0);// Every collider under a node, posed the way the simulation sees it.// Triggers draw in triggerColor. DebugDraw.shape draws a single posed Shape.DebugDraw.colliders(scene.root);// Render debug lines: one updatable geometry, rebuilt in place each frame.final debugGeometry = DebugDraw.createGeometry();debugNode.mesh = Mesh(debugGeometry, UnlitMaterial());// Per frame, after the DebugDraw calls:DebugDraw.flushInto(debugGeometry);
DebugDraw.flushMesh() builds a new geometry per call; it suits a one-off capture, not a per-frame loop.