# @tiptap/track@0.1.0

<!-- Generated by scripts/gen-package-reference.mts from the package source.
     Do not edit: §15.4 — package docs are generated, nobody writes them. -->

**Spec §7.1: `@tiptap/track`** — a course, with nothing driving on it.

§7.1 keeps this **separate from `vehicle`** on purpose, and the reason is the
whole thesis of the catalogue: *"a running race or a boat race wants a track
without tires"*. Package by primitive, never by genre. A `racing` package
would rebuild the bottleneck this plan exists to remove.

So the hard rule here is that **nothing in this crate knows what a car is.**
It came out of `racer/src/track.rs`, where every progress function took a
`&Car`, and the extraction is mostly the work of finding out how little of a
car those functions were actually reading. The answer is three fields:
position, lap, segment. That is [`Runner`], and a rowing boat satisfies it.

| What it does | Type |
|---|---|
| Project a point onto the centre line, with a signed lateral offset | [`project`] → [`Projection`] |
| Rank everyone by how far round they are | [`progress`], [`standings`] |
| Advance checkpoints and laps | [`advance`] over [`Lap`] |

## Checkpoints are "be on the segment", not "cross a line"

A line crossing needs the previous position — a state field nobody else wants
— and it fails for a runner who stops on the line or backs over it. Being *on*
the checkpoint's segment is a test on current state alone. It is only reachable
in order because the caller's own validation refuses a top speed that could
skip a whole segment in one tick, which is the constraint that makes this work
and the reason it is enforced there rather than assumed here.

## Ties break on seat index, everywhere

A sort that is merely *stable* is only stable with respect to an input order,
and two clients that ordered two runners differently have a race with two
answers. Every ordering in this crate is total.

## Types

```rust
pub struct TrackNode
```

One point on the centreline.

```rust
pub struct Track
```

The circuit.

```rust
pub struct Projection
```

Where a point is, relative to the track.

```rust
pub struct Progress(pub u64)
```

How far round the circuit a car is, as one comparable number.

`lap`, then `segment`, then the fraction along it, packed into a `u64` so
standings are an integer sort. Monotone in the direction of travel, which is
the only property that matters and the only one a car that is being pushed
backwards through a chicane will not break.

```rust
pub struct Runner
```

What this crate needs to know about something going round the course.

Three fields. `racer` passes a `Car`'s; a rowing game passes a boat's; a
marathon passes a runner's. The extraction from `racer/src/track.rs` was
largely the work of discovering that the `&Car` those functions took was
nine-tenths unread.

```rust
pub struct Lap
```

Checkpoint and lap counters, advanced by [`advance`].

## Constants

```rust
pub const SURFACE_KINDS: usize = 4
```

How many surface bands a course has.

The bands are track geometry — how far from the centre line each one reaches
— so they live here. What each band *does* to a vehicle is grip, and that is
the caller's table: `racer` indexes `RacerConfig::surfaces` with these, and a
rowing game would index something about current.

```rust
pub const SURFACE_TRACK: u8 = 0
```

The racing surface.

```rust
pub const SURFACE_KERB: u8 = 1
```

The kerb — grippy enough to use, rough enough to unsettle a vehicle.

```rust
pub const SURFACE_ROUGH: u8 = 2
```

Grass, gravel, dirt. Where a mistake is paid for.

```rust
pub const SURFACE_VOID: u8 = 3
```

Past the barrier.

Nothing is ever reported here in `racer` — the barrier clamp runs first — and
the slot exists so the encoding has no unreachable bit pattern that a decoder
would have to decide what to do with.

```rust
pub const MAX_TRACK_NODES: usize = 64
```

Centreline nodes a track may declare.

Spec §11.5: "a bounded body count is a bound; an unbounded one is a CPU bomb
on somebody's phone." The per-tick cost of this module is
`cars × nodes × 1 projection`, so this number and the room size are the two
factors of the host's workload. 64 nodes is a circuit with real corners; it
is also the number to check against a real phone before either is raised.

```rust
pub const MIN_TRACK_NODES: usize = 3
```

The smallest closed loop that is a loop.

```rust
pub const MAX_CHECKPOINTS: usize = 16
```

Checkpoints a track may declare, including the start/finish line.

Sixteen because `next_checkpoint` is a `u8` on the wire and because a circuit
needing more sectors than that to stop a shortcut has a shortcut problem the
checkpoint list is not going to solve.

## Functions

```rust
pub fn segment(&self, index: usize) -> (Vec2, Vec2)
```

The segment from node `index` to node `index + 1`, wrapping.

```rust
pub fn shortest_segment(&self) -> Fixed
```

The shortest segment, which is what bounds how fast a car may travel —
see `Racer::validate_config`.

```rust
pub fn max_half_extent(&self) -> Fixed
```

The widest the drivable band ever gets, half of it, including kerb and
rough. What the barrier is at.

```rust
pub fn reachable_bounds(&self) -> (Vec2, Vec2)
```

The axis-aligned box that contains every point a car can reach.

Used for the wire quantizer's origin and for the extent check in
`validate_config`: a track whose reachable area does not fit the 16-bit
position lattice is a track on which cars clamp to the map edge.

```rust
pub fn point_at(&self, segment: usize, t: Fixed) -> Vec2
```

The centreline point at `segment` and fraction `t`.

```rust
pub fn half_width_at(&self, segment: usize, t: Fixed) -> Fixed
```

Half the racing surface's width at `segment` and fraction `t`.

```rust
pub fn heading_at(&self, segment: usize) -> Angle
```

The direction of travel along `segment`, as an angle.

```rust
pub fn walk_back(&self, segment: usize, t: Fixed, distance: Fixed) -> (usize, Fixed)
```

Walk `distance` backwards along the centreline from `segment`/`t`.

Used to lay out a starting grid behind the line and to place a recovered
car short of the checkpoint it is returning to. Bounded: it gives up
after one lap of segments rather than looping on a degenerate track,
which `validate_config` refuses anyway and this does not rely on.

```rust
pub fn angle_of(v: Vec2) -> Angle
```

The angle a vector points along, by binary search over the quadrant.

# Why not `atan2`

There isn't one. `sim_core::fixed` gives `Angle::sin_cos` (CORDIC, forward
only) and nothing in the other direction, because `arena2d` never needed it —
a top-down shooter is *told* its facing by the input. A racer is not: a car
placed on the grid or recovered onto the track has to be pointed along a
segment, and a segment is a vector.

This is a sixteen-step bisection on the existing forward CORDIC, which is
exact to one `Angle` unit (1/65536 of a turn, 0.0055°) and costs sixteen
`sin_cos` calls. It runs on placement, never per-tick, and it is deterministic
for the same reason CORDIC is: a fixed iteration count and integer
comparisons all the way down.

A native fixed-point `atan2` in `sim-core` would be better and is the kind of
thing a second module discovers that the first one did not need. It is
reported rather than added, because `sim-core` is not this module's to edit.

```rust
pub fn cross_raw(a: Vec2, b: Vec2) -> i64
```

`a × b`, as a raw Q16.16 `i64`.

In `i64` and unnarrowed for `Vec2::dot_raw`'s reason: at a track coordinate
of 1000 the product of two components is 10⁶, whose raw form is 6.6 × 10¹⁰ —
five bits past an `i32`. A cross product that saturates has a sign, which is
all this is used for, but it would saturate to the *same* value for two very
different vectors and the bisection above would stall.

```rust
pub fn Projection::normal(&self) -> Vec2
```

The unit vector across the track, pointing left.

```rust
pub fn surface(&self, track: &Track) -> u8
```

Which surface a point at this lateral offset is on.

```rust
pub fn barrier_limit(&self, track: &Track, body: Fixed) -> Fixed
```

How far the centre of a body of half-width `body` may be from the
centreline before its side is against the barrier.

Saturated at zero rather than allowed to go negative: a track narrower
than the car is a config `validate_config` refuses, and this is the
second line for one that gets through — a negative limit would clamp the
car to the centreline and hold it there, which is at least visible.

```rust
pub fn project(track: &Track, point: Vec2) -> Projection
```

Project a point onto the track.

A full scan — see the module docs for why it is not windowed.

```rust
pub fn progress(track: &Track, runner: Runner) -> Progress
```

How far round one runner is.

The fraction along the segment is **derived from the position** rather than
stored: both sides already agree about the position, and a stored copy would
be two bytes per runner per snapshot carrying something recomputable exactly.

```rust
pub fn standings(track: &Track, runners: &[(PeerIndex, Runner)], out: &mut Vec<(PeerIndex, Progress)>)
```

Everyone, most progressed first, seat index breaking ties.

The order a leaderboard renders in. `out` is filled and sorted; the caller
owns the allocation so a per-tick standings call does not make one.

```rust
pub fn advance(checkpoints: &[u8], state: &mut Lap, segment: u16) -> (Option<u8>, bool)
```

Advance checkpoint and lap counters for the segment `state` is now on.

Returns `(reached_checkpoint, completed_lap)`. Whether completing that lap
*finishes* the race is the caller's question — this crate counts laps and
does not know what winning means.
