# Crash BASIC 1.46.0 Release Notes

*~written by Crash-tan~*

## THE "RIG IT UP" RELEASE

A sprite is rarely just one sprite. A character is a torso with a head, two
arms, a sword in one hand — a little tree of pieces that move together. Until
now you wired all of that up by hand, every time, in code, and there was no way
to save the result and bring it back. 1.46.0 starts to fix that: you can now
**save and load whole sprite rigs** to JSON, give child sprites **real rotation**
so an arm swings around a shoulder, drive a limb to a target with **inverse
kinematics**, anchor a sprite with **`ORIGIN`**, put **branching logic inside a
behavior or pattern declaration**, and **clip a map layer to part of the screen**
so your HUD has somewhere to live.

The throughline is reuse and real rigging: build a rig once, save it, drop it
into any project — then articulate it with `IK`, `PIN`, and `LIMIT` constraints,
the building blocks a tool like DragonBones or Spine is made of.

---

## Save and load rigs, behaviors, and patterns

The headline. Three new pairs of statements serialize the moving parts of your
sprites to JSON files and load them back:

```basic
SAVE BEHAVIOR "walk" TO "walk.json"
LOAD BEHAVIOR "walk.json"

SAVE PATTERN "ai" TO "ai.json"
LOAD PATTERN "ai.json"

SAVE RIG FROM SPRITE 0 TO "hero.rig.json"
LOAD RIG "hero.rig.json"
LOAD RIG "hero.rig.json" ONTO SPRITE rootId
```

**`SAVE BEHAVIOR` / `SAVE PATTERN`** write a single named behavior or pattern —
its commands (or steps), its `@param` defaults, its loop flag — to a file.
`LOAD` re-registers it under the name stored in the file, exactly as if you'd
typed the `BEHAVIOR`/`PATTERN` block again. Re-loading a name overwrites it,
the same as re-declaring.

**`SAVE RIG`** is the big one. Point it at a root sprite and it captures the
*whole tree*: the root, every child (and their children), each piece's relative
offset, its image and frame, its bounding box, flip, visibility, alpha,
rotation, origin (and rotation pivot), elevation, layer, its `RIGID` flag, and
its **`IK` / `PIN` / `LIMIT` constraint config** — **plus the behaviors and
pattern attached to each piece**. All the behavior and pattern definitions those
pieces reference come along in the same file. (A constraint's *runtime target* —
the live point an `IK`/`PIN` chases — isn't saved; you re-aim it after loading.
The configuration that defines the rig is what persists.)

```basic
' Build a two-part rig...
SET SPRITE 0, 100, 100, "torso"
SET SPRITE 1, 100, 80, "head"
SET SPRITE 1 PARENT(0)
SET SPRITE 1 BEHAVIOR "bob"
SAVE RIG FROM SPRITE 0 TO "hero.rig.json"

' ...then spawn a fresh copy somewhere else, later, or in another project:
rootId = NEXTFREESPRITE()
SET SPRITE rootId, 200, 150, "torso"
LOAD RIG "hero.rig.json" ONTO SPRITE rootId   ' head re-attaches at its offset
```

`LOAD RIG … ONTO SPRITE id` rebuilds the children onto a root you've already
placed — the saved offsets re-attach the head, the arm, the sword exactly where
they were, and their behaviors/patterns re-register and re-bind. Plain
`LOAD RIG file$` with no `ONTO` just registers the rig's behaviors and patterns
without spawning any sprites — handy when you want the logic but will place the
sprites yourself.

This is the foundation for a **sprite rigger**: author a character's hierarchy
and motion once, save it as a reusable asset, and instantiate it on demand.

Files go through CrashPlayer's normal storage, so this works the same on
desktop and in the browser. Each file carries a format version; a file newer
than the player understands is refused with a clear message rather than loaded
half-way.

---

## `RIGID` — child sprites that actually rotate with the parent

Attach a child to a parent and, by default, the child *follows* the parent —
it tracks the parent's position, keeping its offset. But it didn't used to
**rotate** with the parent. Spin the torso and the arm slid along beside it
instead of swinging around the shoulder.

That default stays (it's what you want for a HUD pin, a name tag, a held item
that shouldn't tilt). When you *do* want articulation, opt in with `RIGID`:

```basic
SET SPRITE 2, 20, 0, "forearm"
SET SPRITE 2 PARENT(upperArm) RIGID
```

A `RIGID` child treats its offset as rigidly fixed to the parent's frame: as the
parent rotates, the child **orbits** around the parent's origin *and* **inherits
the parent's spin**. That's the whole game for articulated rigs — chain
`shoulder → upperArm → forearm → hand` with `RIGID` at each joint and the arm
moves as one limb. Without `RIGID`, the old translation-only behavior is
unchanged.

(Scale inheritance — a child shrinking when the parent shrinks — is still off
the table for now. One gap at a time.)

---

## `IK` — inverse kinematics, the part that makes rigs feel alive

`RIGID` is *forward* kinematics: you rotate the shoulder, and the hand follows.
Inverse kinematics is the other direction — you give the **hand** a target point,
and the solver figures out the shoulder and elbow rotations needed to reach it.
That's the "grab the hand and the whole arm bends to follow" interaction that
DragonBones and Spine are built on, and it's now one line:

```basic
' A chain: the tip plus its LENGTH ancestors via PARENT.
SET SPRITE hand IK TARGET(mx, my) LENGTH 2 BEND CCW

' ...then every frame, just re-aim it:
SET SPRITE hand IK TARGET(mx, my)
```

The chain is the tip sprite plus the `LENGTH` sprites above it in the `PARENT`
hierarchy — so it rides entirely on the rigs you already build. A **FABRIK**
solver (any chain length, not just two bones) rotates every joint so the tip
reaches the target, and the rest of the chain trails naturally.

- **`TARGET(x, y)`** — the world point the tip reaches toward (an `(x, y)` pair
  or a Coordinate, so the mouse, another sprite, or a computed point all work).
- **`LENGTH n`** — how many bones above the tip to include.
- **`BEND CW|CCW`** — which way the interior joints bend (the elbow/pole hint).
- **`MIX m`** — blend 0..1 between the plain FK pose and the solved pose.
- **`ITERATIONS k`** — solver pass cap (default 10; more = tighter reach).

A bare `TARGET` on an already-configured tip just re-aims it (the chain config
sticks), and `IK NONE` removes the constraint. Declaring IK automatically marks
the chain links `RIGID` so the solved rotations actually propagate. **Give each
chain member an `ORIGIN` at its joint** (below) so it rotates around the right
point — without that, a sprite pivots around its corner and slides off the bone.

It's all per-tick and local, so an IK rig behaves identically in single-player
and across CrashNet with nothing new on the wire.

---

## `PIN` and `LIMIT` — the other two constraints

Two smaller constraints round out the rigging kit:

**`PIN`** eases a sprite's position toward a target each tick — independent of
any rotation chain. Good for "the eyes follow the cursor", a tracking reticle, a
camera that lags behind the player:

```basic
SET SPRITE eye PIN TARGET(mx, my) MIX 0.3   ' 0..1: how hard it chases
SET SPRITE eye PIN NONE
```

**`LIMIT`** clamps a child's local offset to a range, or locks it to a single
axis — for mechanical rigs like pistons, sliders, and treads:

```basic
SET SPRITE piston PARENT(block) RIGID
SET SPRITE piston LIMIT X 0, 20 AXIS X   ' slides 0..20 on X only
SET SPRITE piston LIMIT NONE
```

---

## `ORIGIN` — one anchor for positioning *and* rotation

Sprites have always been anchored at their **top-left corner** — `SET SPRITE`
positions that corner, and rotation pivoted somewhere else entirely. That's
fine until you parent, rotate, or rig something, at which point you want the
sprite anchored at a sensible point — usually its center. Now you can say so:

```basic
SET SPRITE 0, 160, 120, "ball" ORIGIN(0.5, 0.5)   ' anchored at its center
SET SPRITE 0 ROTATE(45)                            ' ...and spins around it
```

`ORIGIN(ox, oy)` takes relative 0–1 coordinates (`(0,0)` top-left, `(0.5,0.5)`
center, `(1,1)` bottom-right) — or a Coordinate value. It's the single anchor
the sprite is **positioned at, parented at, IK-jointed at, and rotated around**.

That last part is the important bit: the rotation pivot **follows the origin by
default**, so a sprite rotates around its anchor instead of some unrelated
point. (If you genuinely need the rotation centre to differ from the position
anchor, an explicit `ROTATE(angle, px, py)` pivot still overrides just the
rotation.) This is what makes IK look right — anchor each bone at its joint and
the whole chain bends cleanly.

Default behavior is unchanged: a sprite with no `ORIGIN` is still anchored at
its top-left, exactly as before.

---

## Branching logic inside `BEHAVIOR` and `PATTERN` declarations

You can now put `IF` / `THEN` / `ELSIF` / `ELSE` / `END IF` and `SELECT CASE`
**inside** a `BEHAVIOR` or `PATTERN` block, to choose which commands or steps
the declaration actually contains:

```basic
BEHAVIOR "enemy"
  IF hardMode THEN
    BMOVE 4, 0
    BGRAVITY 0.5
  ELSE
    BMOVE 2, 0
  END IF
END BEHAVIOR

PATTERN "ai" LOOP
  IF boss THEN
    "charge" DURATION 60
  ELSE
    "walk" DURATION 30
  END IF
  SELECT CASE mode
    CASE 1
      "patrol" DURATION 90
    CASE ELSE
      "idle" DURATION 30
  END SELECT
END PATTERN
```

This is **declaration-time** logic — the condition is evaluated once, against
your live variables, at the moment the `BEHAVIOR`/`PATTERN` is registered, and
it bakes the chosen commands into the definition. Re-declare the same behavior
with a changed variable to swap what it does:

```basic
hardMode = TRUE
BEHAVIOR "enemy"          ' now bakes in the hard-mode commands
  ...
END BEHAVIOR
```

`SELECT CASE` supports the full grammar you'd expect — `CASE 2, 3` lists,
`CASE IS > 5` comparisons, `CASE ELSE`. It's the same `IF`/`SELECT` you write
everywhere else, just usable in this new position.

This pairs with — and doesn't replace — pattern `WHEN`. `WHEN` is the *runtime*,
per-tick test ("do this step only while a key is held"); declaration-time
`IF`/`SELECT` decides *which steps the pattern is built from in the first place*.
Both work together.

---

## `CLIP` — give a map layer its own corner of the screen

Map layers assume they own the whole screen — a tilemap or plane fills every
pixel. That's a problem the moment you want a HUD or a menu strip, because the
map paints right over it. `SET LAYER n CLIP (x1,y1)-(x2,y2)` restricts a layer
to a screen rectangle so it leaves the rest free:

```basic
CREATE MAP FROM map TILESET "tiles" TILESIZE 32 AS LAYER 0
SET LAYER 0 CLIP (0,0)-(212,240)   ' map only renders in the left 212px
' ... draw your HUD on another layer in the right strip ...
SET LAYER 0 CLIP NONE              ' later: back to full screen
```

The rectangle is in logical screen pixels, normalized (corners ordered, clamped
to the screen) and mapped through any letterbox. It's a property of the layer,
so it composes cleanly with everything a layer can already do:

- a layer `SHADER` (the shaded output is clipped, not an intermediate),
- `AFFINE` / `PERSPECTIVE` plane modes (the Mode-7 floor clips to the box),
- sprites assigned to the layer — they clip with it.

The clip persists across frames until you change it, so set it once at setup.
`CLIP NONE` removes it and the layer fills the screen again.

---

## A lot more sprites — and they stay fast

The ceiling on how many sprites you can have at once jumped from **1,000 to
100,000**. Bullet-hell screens full of projectiles, a thick field of particles,
a crowd, a forest — go wide. `NEXTFREESPRITE` and `RESERVE SPRITE` reach across
the whole range, and IDs that used to be off-limits (a sprite at, say, 99,999)
just work.

The bigger deal is what happens while you're *making* them. Spawning a large
wave of sprites used to get slower and slower the more were already on screen —
filling a dense field could hitch for a noticeable beat. That's gone: creating
sprites now stays fast no matter how many are already live, so a level that
suddenly spawns thousands of them does it in one smooth step instead of a
stutter. Everything else — moving them, animating them, collision — keeps the
speed it always had.

Nothing in your code changes. The same `ENABLE SPRITE` / `SET SPRITE` /
`NEXTFREESPRITE` you already write just has a lot more headroom and no slowdown
behind it.

---

## Multiplayer

The layer features cross the wire like their neighbors: `SET LAYER … CLIP` is
layer configuration that replicates the same way `SHADER` and `ALPHA` already
do, so every client clips the layer identically. Rigs, behaviors, patterns,
`RIGID` attachment, and the `IK` / `PIN` / `LIMIT` constraints all resolve
per-interpreter (world transforms have always been computed locally), so they
behave the same in single-player and CrashNet without anything new on the
network. `ORIGIN` rides on the existing sprite-state channel, so a sprite's
anchor replays correctly on a late-join or `SET ROOM` transition.

---

## Compatibility notes

- **Everything you already wrote still works.** The new statements and modifiers
  (`SAVE`/`LOAD BEHAVIOR`/`PATTERN`/`RIG`, `RIGID`, `IK`, `PIN`, `LIMIT`,
  `ORIGIN`, declaration-time `IF`/`SELECT`, and `SET LAYER … CLIP`) are all
  strictly additive.
- **Child sprites still default to translation-only.** Rotation inheritance is
  opt-in via `RIGID` — existing parent/child code is unchanged.
- **Sprites still anchor at their top-left by default.** `ORIGIN` is opt-in; a
  sprite with no `ORIGIN` positions and rotates exactly as it did before. Where
  `ORIGIN` is set, the rotation pivot follows it unless an explicit
  `ROTATE(angle, px, py)` pivot overrides it.
- **`CLIP` is a new optional clause on `SET LAYER`.** Layers with no clip render
  full-screen exactly as before.
- **The sprite ceiling went up, not down.** The 1,000 → 100,000 raise and the
  faster bulk spawning are pure headroom — any program that ran under the old
  limit runs identically, just with far more room and no slowdown as the count
  climbs.

---

*Build the rig once. Save it. Bring it back. Go make a game.*

*— Crash-tan*
