# Gameplay packages

# Gameplay packages

Each package is a set of components and services that a game, or a level manifest, attaches by name.

## Characters (`character`)

`spawnCharacter` makes an entity with `CharacterMovement`: a capsule moving against static geometry, with walk, run, crouch, jump, steps, slopes and acceleration. Its parameters follow Unreal's Character Movement Component, in metres and seconds (`CharacterParams`).

`PlayerController` turns input actions into movement and camera: it reads the action names you give it (`PlayerActions`) and ignores the ones you leave out. `CameraRig` is first or third person, switchable at run time.

## Animation (`animation`)

An `Animator` plays an animation graph (`GraphDef`) on an entity: state machines, blend spaces driven by speed or direction, layers, `Montage`s for one-shot actions, and notifies at named times in a clip. `locomotionGraph` is a ready-made walk / run / jump graph. `retargetGroup` moves a clip from one skeleton to another, and `buildPuppet` makes a stand-in skinned character, so a game runs before its real models exist. A state can also play **random motion** (`{ random: { entries } }`, Unreal's Random Player): it picks an entry by weight, loops it a random number of times at a random rate, then cross-fades to the next pick; the pick is seeded, so it replays the same in a test or a replicated game, and the Unreal exporter's `animbp.mjs` turns Random Player nodes into it.

The graph does not use Babylon's animation clock: poses are requested and applied each fixed step, so animation is deterministic with the rest of the world.

## AI (`ai`)

`NavService` builds or loads a NavMesh (recast-navigation, WebAssembly, loaded once by `initNavigation`) and answers path and point queries. `NavAgent` moves an entity over it in the crowd. Small ready behaviours: `Roam` (walk to random points near home), `Follow`, `Attention` (stop and face the player who comes near). `BehaviorTree` is there for more.

## Interaction (`interaction`)

`Interactor` on the player picks the usable thing in front of it each step and shows its prompt; `Interactable` is the base. On top: `Door`, `LevelDoor`, `Lever` (flips and toggles the doors it points at), `Pickup` and `Inventory`. `installInteraction(world)` registers them so manifests can name them.

## Zones (`zones`)

`ZoneService` keeps named zones on a grid and knows who is in which one (a member is in exactly one zone at a time). It emits enter and exit events. `zoneHash` gives the name a backend sees, so zone names in a game's data can stay private.

## Transformation (`transform`)

`Transformer` swaps what an entity looks like and how it animates (mesh, skeleton, graph, movement values), keeping position and AI state, with an `Effect` around the swap: `particleBurst`, `scalePulse`, or `combine` of several. `ZoneTransform` does it on entering a zone. `ProximityTransform` does it from a **record shared between clients**: every client with a player in range posts "form" each tick, every client reads the record and shows the form while it is fresh, so all players see the same state (an NPC teacher stands up for whoever is near). Where the record lives is a `RecordStore`: `MemoryRecordStore` in-process, or `PresenceRecordStore` of `net` on the presence server.

## Combat (`combat`)

`Fighter` and `Duel` run a melee fight by rules that the clips set: the player and `FighterAI` give the same commands, weapon sweeps meet hit capsules, blocks, parries, stamina, health and reactions decide the rest. See Melee combat (skill `ferret-combat`).

## Media (`media`)

`AudioService` has a master gain and four buses (music, sfx, ambient, voice); `AmbientZones` maps zones to ambient sounds. `VideoScreen` plays HLS or MP4 on a plane in the world; `HtmlScreen` draws a web page onto a plane as a texture. Every media component implements the same `MediaPlayer` interface. `SceneRecorder` records the scene to a video file (MP4 where the browser writes it, else WebM) with the sound the player hears once the audio is unlocked.

`captureFrames` captures the scene frame by frame on simulated time rather than the wall clock: before each frame the world moves exactly 1/fps seconds and the engine's frame time reads 1/fps, so nothing is dropped however slowly a frame is drawn, physics and animation stay in step, and a turntable loop closes exactly. Frames can be drawn at up to four times the size and scaled down (`supersample`), and come out as one WebM file (encoded in the browser with WebCodecs: VP9, else VP8; `writeWebm` is the container writer) or as PNG pictures one by one. `beforeFrame(i, t)` moves a camera along. The inspector command `capture` does the same from the console or an agent.

```ts
const clip = await captureFrames(game.engine, game.scene, game.world, {
  seconds: 5, fps: 30, width: 1920, height: 1080, supersample: 2,
  beforeFrame: (i, t) => { camera.alpha = start + (2 * Math.PI * t) / 5; },   // one turn in five seconds
});
// clip.blob: video/webm, clip.frames === 150
```

## View (`view`)

`SectionView` is a section (cutaway) view: meshes, or every mesh under a model's root, are cut by one to six planes in their materials on the GPU, and the cut faces are filled with a flat hatched colour, so a closed solid reads as cut through. Mode `all` cuts away only what lies beyond every plane (one plane is a half section, two planes take out a quarter); mode `any` cuts away what lies beyond any plane (a slice, a box). Planes can be given in a node's frame and move with it; `exclude` keeps chosen parts whole; `active` switches the cut on and off. The cut materials are copies, so a material shared with uncut meshes is untouched, and `dispose()` gives every mesh its own material back. Shadows and picking still see whole meshes. The gearbox of the showcase sample uses it for its cutaway.

```ts
const cut = new SectionView(scene, {
  targets: [housingNode],
  planes: [{ point: [0, 0, 0], normal: [0, 1, 0] }, { point: [0, 0, 0], normal: [0, 0, -1] }],   // the upper front quarter
  mode: 'all', frame: modelRoot,
});
cut.active = false;   // whole again
```
