Files
tilt/SPORTS_FRAMEWORK.md
T
ryanfitzpatrickio dd819e991d Add main menu, 3v3 with goalies, and dead-puck faceoffs.
Players pick 1-on-1 shootout or 3-on-3 scrimmage; 3v3 gets nets,
goalies, scoring, OOB whistles to the nearest faceoff circle, and
one-way board re-entry for skaters who leave the ice.
2026-08-03 10:28:11 -05:00

607 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sports Framework — Expansion Plan
What you already have is not a hockey demo with spare parts. It is a **character +
physics + intent** stack that happens to be wired as ice hockey. The goal of this
document is to name the seams honestly, list what still has to become *sport-agnostic*,
and outline what would remain as **sport packs** so the same building blocks can
ship football, basketball, soccer, fighting, racing-on-foot, and contact sports
without forking the engine.
This is complementary to [ROADMAP.md](ROADMAP.md) (hockey product depth) and
[README.md](README.md) (current architecture). Here the question is:
> What would it take for *this package* to be the framework under *any* sport game?
---
## 1. The thesis
A general sports framework is not “one locomotion model that does everything.”
It is a **small set of contracts** plus **pluggable sport modules**:
| Layer | Owns | Sport-specific? |
|-------|------|-----------------|
| **Body stack** | skeleton, mesh, skinning, body style, ragdoll, proxy | mostly shared |
| **Equipment stack** | gear builders, sockets, coverage, colliders | shared builders; sport kits |
| **Motion stack** | pose buffer, crossfade, IK, override layers, clips later | shared runtime; sport poses |
| **Locomotion** | intent → velocity → footing | **one model per surface/gait family** |
| **Impact** | did hit / what kind / severity / handoff limp↔driven | shared core; sport rules |
| **Object play** | ball/puck possession, tool use, goals | sport packs |
| **AI** | roles, intent writers, formation | shared brain shell; sport tactics |
| **Arena** | bounds, surfaces, markings, static colliders | sport packs |
| **Rules / match** | clock, score, phases, sanctions | sport packs |
| **Studio / harness** | shot sheets, drills, capture, regression | shared tooling; sport catalogs |
Hockey already forces the hard problems (anisotropic friction, limb-level contact,
tool-in-hand IK, pure sim in `shared/`). That is why a framework *can* fall out of
this — but only if hockey stops being the type system.
---
## 2. What you already have (framework seeds)
These are reusable with little or no redesign.
### 2.1 Character body pipeline
- **23-bone A-pose skeleton** (`skeleton.js`) with regions, bone radii, segment graph
- **Procedural lofted body** (`body.js`) + **distance-field skinning** (`skinning.js`)
- **Body style morphs** mass / muscle / fat (`bodyStyle.js`) — already sport-neutral
- **Materials / team tints** (`materials.js`) — team identity, not hockey identity
### 2.2 Equipment geometry kit
- **`gearMesh.js`**: `loft`, `carvedShell`, `tube` — sport-agnostic mesh grammar
- **Socket + skinned cloth pattern** (hard shells on bones, cloth skinned with `aPart`/`aT`)
- **`hideCoveredBody`** coverage masks so kit replaces flesh
Hockey gear (`skaterGear`, `goalieGear`, `stick`) is content *on top of* that grammar.
### 2.3 Animation runtime
- **Pose buffer + state crossfade + override layers** (`skateAnimator.js`)
- **Two-bone analytic IK** (legs; goalie legs; stick grip reach partially)
- **Override layers that multiply spine** while replacing arms (stickwork) — correct
pattern for “keep locomoting while acting”
- **Animator does not own movement** — sim/proxy own position (critical for all sports)
### 2.4 Physics character loop
- **Proxy capsule for standing presence** + **kinematic ragdoll for pose/hits**
- **Limp handoff** with root re-expression so get-up does not double-apply slide
- **Limb-pair hit classification** from posed capsules (`hits.js`) — the right
separation of *did hit* vs *what hit*
- **Collision layers / tags** (`bridge.js`) — extensible KIND system
### 2.5 Intent seam
- **`applyIntent`** clamped entry (`skaterSim.js`) — controller, AI, and netcode all
write the same shape
- **Camera-relative stick** (`input.js`) — gamepad/keyboard already abstracted
### 2.6 Pure sim island
- **`shared/`** free of three.js, headless-testable, server-ready
- **Headless test culture** (pose, AI, physics, hits) + **capture / img2mesh** tools
### 2.7 Studio / reference loop (seed)
- **Character studio** (`character.html` + `img2mesh`) with pose presets, fixed views,
shot sheets, optional live drill (puck machine)
- Pattern: *author → capture sheet → drop refs → re-capture → diff by eye (or later pixel)*
---
## 3. What is still hockey-shaped (must peel off)
These block “any sport” until they become interfaces + plugins.
| Hardcoded today | Why it blocks generality |
|-----------------|---------------------------|
| `shared/skaterSim.js` is *the* locomotion | Running, plant-and-cut, swim, bike, skate all need different footing models |
| `shared/rink.js` is the arena | Rect + corner radius is not a pitch, court, ring, or track |
| `shared/ai.js` puck roles + rink half | Roles are puck/carrier/chaser; no ball/goal/zone abstraction |
| `possession.js` + stick blade | Magnetism dial is excellent, but assume blade + cylinder puck |
| `stick.js` grip-space tool | Need generic **held tool / ball socket / two-hand implement** |
| `hits.js` CAN_DELIVER / ice thresholds | Sport contact rules differ (tackle vs check vs foul vs strike) |
| `goalie` as special entity type | “Keeper” should be a role/locomotion profile, not only a hockey class |
| `match.js` / `shootout.js` | Match loop is sport session; not a generic phase machine |
| `input.js` Skill Stick / hockey stop | Sport action maps differ; need bindable action sets |
| Pose catalogs only skate / stick / goalie | Need gait families + sport action libraries |
| Physics world assumes ice plane + boards | Surfaces (friction, bounce), goals, posts, glass, hoops, cages |
| Package name / scripts assume hockey MVP | Cosmetics; real issue is import graph coupling |
---
## 4. Target architecture
```
packages/ (or src/ layered)
core/ math, rng, time, determinism helpers
body/ skeleton, body loft, skinning, bodyStyle, ragdoll, proxy
gear/ loft/shell/tube builders, socket attach, coverage
anim/ pose buffer, blend, IK solvers, layer stack, clip hooks
locomotion/ interface + models: skate, run, plant, crouch-shuffle, …
impact/ contact resolution, limb pairs, severity curves, handoff
object/ free bodies, attachment/magnetism, tools, projectiles
arena/ surfaces, bounds, static colliders, markings API
brain/ intent writer, roles, blackboard, formation helpers
match/ phase machine, clock, score, events (sport-agnostic shell)
input/ device → action set → intent
render/ materials, camera presets, arena mesh helpers
studio/ pose/view catalogs, capture API, ref sheets, drills
harness/ headless scenarios, golden metrics, capture regression
sports/
hockey/ rink, skate loco, stick, puck, check rules, shootout, AI
(future packs)
football/
basketball/
soccer/
fighting/ (Ludus-adjacent — already half-solved)
```
**Rule:** a sport pack may depend on the framework. The framework must not import a sport pack.
Hockey becomes the first pack that proves the contracts. Ludus fighting is the second
pack if contact + minigame reuse is the priority (see ROADMAP fighting note).
---
## 5. Contracts to extract (the real work)
### 5.1 Locomotion model (`ILocomotion`)
**Have:** carve/glide blade model + intent fields (`ix, iz, sprint, brake`).
**Need:**
```
createState(spawn, profile) → state
applyIntent(state, msg) // clamped, never trusts client
step(state, dt, env) // env: surface, contacts, clamps
readout(state) → { speed, gaitPhase, bank, plantL, plantR, … }
```
**Locomotion families to support eventually:**
| Family | Examples | Key physics |
|--------|----------|-------------|
| **Blade / edge** | ice hockey, figure, speed skate | anisotropic friction, carve |
| **Run plant** | soccer, basketball, football | foot plant, cut friction, acceleration |
| **Crouch / shuffle** | goalies, catchers, linemen | lateral step without full gait |
| **Contact-limited** | rugby ruck, board pin | reduced mobility under constraint |
| **Aerial / jump** | basketball, volleyball, headers | ballistic + land recovery |
| **Vehicle-assisted** | cycling, wheelchair, luge | separate later; not v1 |
**Left to build:**
- Shared `env` (surface µ, max slope, out-of-bounds clamp hooks)
- Foot plant bookkeeping for run gaits (world-planted feet vs mover-local skate feet)
- Profile data (top speed, accel, turn radius by sport / position / fatigue)
- Unit tests per model mirroring `test/skaterSim.mjs`
### 5.2 Footing & IK policy
**Have:** mover-local foot targets for skating; world-height leg IK for goalie pads.
**Need:**
- **`IFootPolicy`**: glide | plant | pivot | kick | slide
- World-space plant IK for walk/run (Ludus-style), without regressing skate glide
- Arm IK generic: **two-hand implement**, **one-hand hold**, **catch**, **block**
- Spine/look-at IK for tracking ball / opponent (broadcast + AI readability)
- Hand-to-object solve that reports *reach error* (you already see this on stick grip)
**Left to build:**
- Unified IK module (two-bone + simple FABRIK/pole vectors), shared by sports
- Constraint priorities (feet > implement > look) so layers dont fight
- Authoring helpers: target sockets in mover-local vs world
### 5.3 Pose / animation system generalization
**Have:** states + stick override layers + goalie stance set.
**Need:**
- **Locomotion graph** (idle, walk, run, sprint, cut, stop, jump, land, fall, getup)
- **Action layers** (shoot, pass, tackle, catch, block, celebrate) with blend masks
- **Clip adapter** interface early — procedural remains default; mocap/clips plug in
without rewriting sports (ROADMAP already names motion matching as the ceiling)
- Shared **get-up / knockdown / stagger** presentation states (physics-driven entry)
**Left to build:**
- Pose catalog format (JSON or pure JS) keyed by sport + role
- Layer stack API (replace vs multiply vs additive per bone set)
- Phase drivers from locomotion readout (gait phase, effort, bank)
- Optional motion-match slot (even if empty) so content pipeline isnt a rewrite later
### 5.4 Equipment framework
**Have:** builders + hockey kits + stick as special tool.
**Need:**
```
EquipmentDef {
id, sockets[], skinnedParts[], rigidParts[],
colliders[], coverage[], massAdd, tags[]
}
ToolDef extends Equipment // stick, bat, racket, gloves-as-weapons
WearableDef extends Equipment // helmet, pads, jersey, cleats
```
**Left to build:**
- Data-driven attach (bone name + local TRS + optional skin weights)
- Size from physique (you already scale gear off `physique` — generalize)
- Collider generation from mesh bounds or authored capsules
- Damage/armor hooks by `REGION` (skeleton already has regions “from GDD”)
- Asset path: procedural first, imported glTF meshes later behind same sockets
- **Reference-driven iteration**: shot sheet per equipment part (front/side/3q/detail)
### 5.5 Player assembly (`createAthlete`)
**Have:** `createSkater`, `createGoalie` — two assembly paths.
**Need:** one factory:
```
createAthlete({
seed, bodyStyle, team,
locomotion: 'skate' | 'run' | …,
role: 'skater' | 'keeper' | 'striker' | …,
loadout: EquipmentDef[],
animProfile,
impactProfile,
})
```
Roles swap locomotion, gear, AI profile, and action map — not hard forks of the character.
### 5.6 Impact / contact sports core
**Have:** proxy collision + limb pair + severity tiers + limp handoff + get-up fix.
**Need:**
- **Impact profiles** (thresholds, limbShare, bonuses, legal deliverers) per sport
- Legal / illegal contact classification as *rules callback*, not hardcoded hockey
- Multi-body pile stability (proxy equilibrium already soft under pressure)
- Grapple / pin / clinch states (football tackle finish, wrestling, board battle)
- Strike profiles for combat sports (Ludus) reusing limb pairs + reaction curve
- Surface hits (wall, boards, post) feeding same severity pipeline
- Injury / fatigue hooks off region + severity (data only; presentation later)
**Left to build:**
- `createImpactSystem({ profile, rules })` replacing hockey-tuned `HIT` constants
- Deliverer allow-lists as data
- Contested body state (pinned, held, blocked) separate from limp
- Harness scenarios: open ice hit, wall pin, tackle wrap, pile-up
### 5.7 Object / ball / tool play
**Have:** puck body, blade collider, magnetism possession dial, release step-clear.
**Need:**
- Generic **`PlayObject`**: sphere / cylinder / prolate (ball types), mass, restitution
- **Attachment models**: hard parent, soft magnetism, carry socket, two-hand cradle
- **Release models**: impulse from tool velocity, throw arc, kick from foot bone
- Contested possession (you already noted nearest-index-wins is too coarse)
- Multi-object (only one puck today)
**Left to build:**
- `object/possession.js` parameterized (radius, catch cone, break force, magnetism)
- Tool velocity sampling at release (stick already aims; generalize to foot/hand)
- Interaction matrix: body part × object × surface
- Sport rules for out-of-bounds / last touch (thin event layer)
### 5.8 Arena / surface system
**Have:** NHL rink numbers, board outline, ice clamp, markings texture, nets.
**Need:**
```
ArenaDef {
bounds, // polygon or compound
surfaces[], // friction, restitution, name
staticColliders[],
goals[] | targets[],
spawns[],
markings, // render only
}
```
**Left to build:**
- Containment for rect, rounded-rect, circle, custom polyline
- Surface queries under feet (ice vs turf vs hardwood changes loco)
- Goal/score volumes as triggers (net is hockey-specific geometry)
- Camera volumes / broadcast rails optional metadata
### 5.9 AI brain shell
**Have:** waypoint steer, personal space, board lookahead, carry/chase/support/defend
via nearest-to-puck, intent-only outputs.
**Need:**
```
Brain {
sense(world) → facts
rolePolicy(facts) → role
tactic(role, facts) → goal
motor(goal) → intent + actions
}
```
**Left to build:**
- Blackboard / facts schema (ball, goals, teammates, opponents, clock, score)
- Role set as data per sport (not four hockey enums only)
- Formation / spacing utilities (slots relative to ball and own goal)
- Difficulty as parameter on reaction lag, aim cone, decision rate
- Keeper brain as role using shuffle locomotion (generalize goalie)
- Headless scenario tests: “defend lead”, “press high”, “box out” per pack
Hockey AI depth (forecheck systems, etc.) stays in the hockey pack / ROADMAP.
### 5.10 Match / rules shell
**Have:** `createMatch` loop, shootout phase machine, goal detection helpers.
**Need:**
- Generic **phase machine**: warmup → live → stoppage → restart → end
- Event bus: goal, foul, out, period, possession change, hit
- Score / clock / period as configurable
- Restart spawns from arena + rules (faceoff, kickoff, freethrow, scrum)
**Left to build:**
- `match/runtime.js` with sport rules plugin
- Deterministic event log (gates replay + netcode later)
- Minimal HUD adapter (score/clock) sport-agnostic
### 5.11 Input / action maps
**Have:** Xbox + keyboard, Skill Stick gestures, rumble on hit.
**Need:**
- Action set per sport (`move`, `sprint`, `primary`, `secondary`, `skillAxis`, …)
- Gesture recognizers as plugins (Skill Stick shoot is one plugin)
- Rebind + dual-input last-wins (keep current behavior)
### 5.12 Studio, reference sheets, training harness
This is the differentiator you called out. Today it is hockey-shaped but the **loop**
is correct.
**Have:**
- Live studio with pose/view catalogs
- CLI shot sheet (`img2mesh`)
- Puck machine drill for goalie
- Headless tests + `capture` screenshots
- `hitprobe` for contact
**Need for framework-grade training harness:**
| Capability | Purpose |
|------------|---------|
| **Subject registry** | any athlete role + loadout, not only player/goalie |
| **Pose/view catalogs as data** | sport packs register entries |
| **Reference slots** | `ref/<sport>/<subject>/<pose>_<view>.png` side-by-side |
| **Diff mode** | flip / onion-skin / histogram vs previous capture |
| **Drill factory** | spawn scenario (1v1, shooting gallery, tackle pad, PK) |
| **Metric probes** | blade height, foot plant error, reach error, joint limits, timing |
| **Scenario packs** | headless scripts asserting metrics, not only “no NaN” |
| **Optional photo-guided authoring** | import ref image as camera-aligned overlay (not auto-mesh) |
| **Later: mesh-from-image assist** | silhouette / part labels → loft section hints (research; not blocking) |
**Important scope note:** true **image → production mesh** (full photogrammetry /
generative retopo) is a product of its own. The framework should treat **reference
photos and sheets as the iteration contract**, with procedural gear remaining the
authoritative runtime asset until a mesh pipeline earns its keep.
**Left to build (practical order):**
1. Registry + data-driven catalogs (so new sports dont edit `img2mesh.mjs` internals)
2. Side-by-side ref overlay in studio + CLI compare report
3. Metric HUD (contact points, IK targets, capsule overlays — debug already half there)
4. Drill API used by shootout machine, then tackle/shot drills for other packs
5. Golden metric tests (blade height style) per sport pack
6. Optional: capture matrix in CI on PR (you already have the capture tool)
---
## 6. Sport packs — what each still needs on top of the framework
Once contracts exist, each sport is mostly **content + rules + AI policy**, not a new engine.
### 6.1 Ice hockey (first pack — mostly present)
**Done enough:** skate loco, rink, stick, puck, checks, shootout, basic AI, goalie MVP.
**Pack backlog:** see ROADMAP (full 5v5 rules, goalie depth, positional AI, possession feel).
### 6.2 Fighting / combat (highest reuse from Ludus + impact core)
- Strike / block / grab action layers
- Ring/cage arena
- Stamina and limb disable via `REGION`
- Existing fighting system port (ROADMAP already flags this)
### 6.3 Soccer
- Run plant locomotion + ball foot/chest/head contacts
- Large pitch arena, goals, out/throw-in/corner rules
- No (or soft) limb impact; shoulder challenge profile
- AI: formations, offside line fact, keeper dive (shuffle + dive loco)
### 6.4 Basketball
- Run + jump + plant, ball carry/dribble magnetism variant
- Court, hoop trigger, shot arc from release
- Screen / box-out contact (low severity impact profile)
- AI: pick-and-roll roles, spacing
### 6.5 American football / rugby
- Run + explosive cut; tackle as grapple-to-limp pipeline
- Field, downs/ruck rules plugin
- Heavy impact profile; pile-up stability critical
- AI: playbooks as scripted formations + read trees
### 6.6 Basketball-adjacent / volleyball / handball
- Shared run + jump + catch/throw object model
- Different arenas and score targets
### 6.7 Non-goals for v1 framework
- Full vehicle sports, water sports, golf swing fidelity, licensed broadcast packages
- Complete mocap library (architecture must allow it; content is separate)
---
## 7. Gap list — prioritized build order
Phased so each phase ships a **usable contract** and keeps hockey working as the
proving pack (strangler pattern: extract behind interfaces, re-home hockey).
### Phase 0 — Inventory & seams (days)
- [ ] Draw import graph: mark `shared/*` vs sport-coupled modules
- [ ] Freeze contracts in a short `docs/contracts.md` (or this file §5 as source)
- [ ] Prove Box3D determinism (ROADMAP) — gates multiplayer *and* harness replay
- [ ] Decide monorepo layout (`sports/hockey` vs stay single package with folders)
### Phase 1 — Athlete + gear core (12 weeks)
- [ ] `createAthlete` + loadout list; skater/goalie become configs
- [ ] EquipmentDef schema; move stick/pads to data-ish modules
- [ ] Physique-driven sizing API documented
- [ ] Studio subject registry reads loadouts
### Phase 2 — Locomotion interface (12 weeks)
- [ ] Extract `ILocomotion` from `skaterSim`
- [ ] Keep skate model as implementation #1
- [ ] Stub `runPlant` model good enough for a mannequin jog (even ugly)
- [ ] Foot policy switch (glide vs plant) wired to animator
### Phase 3 — Anim / IK platform (23 weeks)
- [ ] Shared IK solvers module
- [ ] Layer stack API (locomotion / action / reaction / getup)
- [ ] Reaction/stagger as layers driven by impact system
- [ ] Clip adapter interface (null implementation OK)
### Phase 4 — Impact + object cores (23 weeks)
- [ ] Impact profiles + rules callbacks
- [ ] Generic play object + possession magnetism
- [ ] Tool release sampling
- [ ] Contested capture v1
### Phase 5 — Arena + match shell (12 weeks)
- [ ] ArenaDef; rink becomes hockey arena pack
- [ ] Phase machine + event log
- [ ] Score/clock/HUD adapters
### Phase 6 — Brain shell (2+ weeks, ongoing content)
- [ ] Facts blackboard + role policy
- [ ] Formation helpers
- [ ] Keeper role using shared pieces
- [ ] Scenario harness for AI regressions
### Phase 7 — Studio / training harness productize (parallel after Phase 1)
- [ ] Data-driven pose/view catalogs
- [ ] Reference overlay + capture matrix
- [ ] Metric probes + golden tests
- [ ] Drill factory (shooting, tackling, 1v1)
- [ ] Optional ref-image camera plate
### Phase 8 — Second sport pack (proof)
Pick **one** of:
- **Fighting** (max reuse of impact + Ludus), or
- **Soccer prototype** (max pressure on run loco + ball object)
Success criterion: second sport does **not** fork `skeleton`, `ragdoll`, `gearMesh`,
`hits` core, or studio capture — only pack content + profiles.
---
## 8. What “done” looks like for the framework (not for a sport)
You can claim a sports framework when **all** of these are true:
1. **New athlete** = skeleton + bodyStyle + loadout + loco profile + anim profile
2. **New equipment piece** = sections/sockets (+ optional collider) + studio views
3. **New contact rule** = impact profile + rules callback, no hit-system fork
4. **New ball sport** = PlayObject + possession params + arena goals + AI facts
5. **New locomotion** = one module implementing `ILocomotion` + foot policy
6. **New sport AI** = roles writing intents/actions into the same seam as the pad
7. **Regression** = headless metrics + shot sheets vs reference photos for that pack
8. **Hockey still runs** as a pack on top of the same cores
Not required for “framework done”: full NHL parity, licensing, netcode, franchise modes
(those are product; see ROADMAP).
---
## 9. Risks & non-goals
| Risk | Mitigation |
|------|------------|
| Over-abstract before second sport | Extract only when hockey + one other pack demand the seam |
| Run gait looks like skating forever | Foot plant policy is a hard gate for sport #2 |
| Proxy pile-ups | Dedicated multi-body scenarios before rugby/football |
| Mocap FOMO | Keep procedural + layer API; add clips when content exists |
| img2mesh becomes “AI will make the gear” | Refs guide humans/tools; runtime assets stay authored procedural/glTF |
| Determinism ignored | Prove early; harness replays depend on it |
| God-object `match.js` | Event log + rules plugin from the start of Phase 5 |
**Non-goals:** replacing Unity/Unreal; full photogrammetry pipeline; every Olympic sport
in year one; network-complete framework before single-player packs feel good.
---
## 10. Suggested near-term decisions
1. **Keep hockey playable on main** while extracting — no big-bang rewrite.
2. **Name the framework** (e.g. still `tilt` core + `sports/hockey`, or promote Ludus-lineage
body stack to a shared package both Ludus and tilt consume).
3. **Second pack choice** determines Phase 24 emphasis:
- Fighting → impact, reaction layers, stamina
- Soccer → run plant, ball object, large arena
4. **Studio first among tools** — equipment and poses improve only as fast as the
ref-sheet loop; that loop is already the right shape.
5. **Do not wait for mocap** to generalize animation runtime; wait for mocap to *fill* it.
---
## 11. One-page checklist — “left to expand”
**Core extractions**
- [ ] Locomotion interface + run/plant model
- [ ] Foot / arm / look IK module
- [ ] Anim layer stack + clip adapter
- [ ] Athlete factory + data loadouts
- [ ] EquipmentDef / ToolDef schema
- [ ] Impact profiles + rules hooks
- [ ] PlayObject + generic possession
- [ ] ArenaDef + surfaces
- [ ] Brain blackboard + roles
- [ ] Match phase machine + events
- [ ] Action-map input
**Harness / content pipeline**
- [ ] Sport-registered studio catalogs
- [ ] Reference photo overlay + capture matrix
- [ ] Metric probes + golden pose/contact tests
- [ ] Drill factory for training scenarios
**Proof**
- [ ] Hockey re-homed as pack
- [ ] Second sport pack without core forks
- [ ] Determinism + replay of harness scenarios
**Explicitly still sport content (never “framework only”)**
- Poses, gear shapes, AI tactics, rules edge cases, audio, broadcast, modes, licensing
---
## 12. Bottom line
You are closer than a greenfield sports engine because the **hard abstractions are
already proven in anger**:
- intent-driven locomotion
- animator subordinate to physics
- limb-level contact from posed ragdolls
- limp ↔ driven handoff without teleports
- tool-in-hand dependency order
- possession as a dial
- pure sim + headless tests + reference shot sheets
What remains is not “invent sports tech.” It is **peeling hockey off the type system**,
turning each proven spike into a **contract + pack content**, and making the
**studio/harness** the way every new sport earns visual and mechanical correctness
from reference photos and scenario metrics.
Hockey ROADMAP remains the depth plan for pack #1. This document is the breadth plan
for the chassis underneath packs #1…N.