# BYOND DM Compatibility Matrix

This is the working compatibility plan for Craft++. It is based on the
official [BYOND DM reference](https://www.byond.com/docs/ref/contents.html)
and the [Dream Maker guide](https://secure.byond.com/docs/guide/guide.pdf).

“Supported” means implemented and covered by a regression test. “Partial”
means the syntax or a narrow runtime path exists, but BYOND behavior is not
yet complete. “Missing” means it is not safe to claim compatibility.

The global-procedure inventory is a lower-bound audit, not a claim of full
compatibility: registering a name in `BuiltinProcs` only proves that the
interpreter can route the call. A procedure is “Supported” here only after a
focused test covers its argument forms, return value, mutation/side effects,
and error behavior. The official reference also includes language statements
such as `goto`, `do`, and `var`; those are tracked separately from callable
global procedures.

## Current baseline

| Area | Status | Notes |
|---|---|---|
| Lexer and indentation grammar | Supported | Craft++ intentionally uses indentation-defined blocks rather than BYOND braces. |
| Expressions and core operators | Partial | Core arithmetic, comparison, assignment, member access, null-conditional access, lists, interpolation, and ternaries exist; BYOND has additional operators and coercion rules. |
| Procedures, vars, types, inheritance | Partial | Core declarations and inheritance exist; dynamic proc/var reflection and full override semantics remain. |
| Lists | Partial | Basic and associative lists exist; BYOND special lists, ranges, lazy access, sorting, and exact mutation semantics remain. |
| Control flow | Partial | Common conditionals and loops exist; exact DM `for`, switch, fall-through, labeled control flow, and edge cases need broader coverage. |
| Preprocessor | Partial | Includes, conditional branches, and `#undef` exist; `#pragma`, warning controls, compiler macros, and full macro behavior remain. |
| Project manifests (`.dme`) | Partial | Active `#if`/`#elif`/`#ifdef` branches, included files, and basic world dimensions load; full project settings and exact Dream Maker include-selection/build behavior remain. Craft++ also scans every source file in the project folder to satisfy the project-wide validation requirement. |
| Built-in procs | Partial | 182 global names route, but registration is not behavior coverage. This audit fixed vector `walk` and target-step speed forwarding; input filters, native extension loading, exact regex semantics, and hundreds of other documented calls remain unverified or incomplete. Details are below. |
| Runtime objects | Partial | `/datum`, `/atom`, `/mob`, `/obj`, `/turf`, `/area`, and `/world` foundations exist. Tile `atom/movable/Move()` and `step()` use location checks and movement overlap hooks; direct `loc` assignment does not run movement callbacks. Movement, `bounds_dist()`, multi-tile `locs`, and turf `contents` share physical bounds derived from `world.icon_size`, `map_format`, `step_x`/`step_y`, and `bound_*`. Rectangular pixel movement uses separate horizontal/vertical tile dimensions; tile-mode transitions and `TILE_MOVER` normalize offsets and custom bounds. Direct `Move()` and vector `step()` preserve tile locks. `Move()` stops short on blocked same-Z turf slides and returns traveled pixel distance; jumps stay all-or-nothing. Default `Cross()` permits overlap unless both atoms are dense; legacy grouped-mob pixel overlap, mode-dependent group blocking, and eligible default mob swapping during `Bump()` are covered. The current audit also fixed vector `walk`, invalid step directions, target-walk speed forwarding, and the documented `get_steps_to()` range cap. Remaining areas include multi-turf/area event behavior, swept collision at high speeds, default client movement, and broader lifecycle events. |
| Time and concurrency | Partial | `sleep` and `spawn` foundations exist; exact tick scheduling, caller suspension, cancellation, and event ordering need compatibility tests. |
| Maps and spatial APIs | Partial | DMM parsing/editor support exists, and BYOND `.dmm` files are now recognized and converted when included, loaded into projects, or opened in the map editor. Network game clients batch-load their already-received initial replication snapshot before rendering. `locate(Type) in Container` now parses as a scoped type search over direct container contents, while generic `in` remains membership. `view`, `oview`, `range`, movement, contents, areas, and collision semantics still need broader completion. `world.Repop()` now supports explicit initial-population capture and restoration for map-created mobs/objs. |
| Savefiles | Partial | Craft++ savefile support exists; BYOND-compatible directories, typed values, references, `vars`, `issaved`, `initial`, and deduplication remain. |
| Icons, images, sounds, matrices | Partial | Asset formats and editor tools exist; runtime behavior and BYOND proc/var semantics are incomplete. |
| UI skins, browser, HTML, input | Partial | IDE/interface tools exist; BYOND skin language, browser controls, HTML tags, and client UI behavior remain. |
| Networking and clients | Partial | Craft++ Dream Seeker can connect to a Craft++ TCP world server, authenticate, and receive replicated player objects. It uses Craft++ framing/messages, has no BYOND protocol support, and the password UI is loopback-only until TLS is implemented. Resource transfer, server/world lifecycle integration, and full client event parity remain. |
| Website accounts and Hub ownership | Partial | Craft++ Hub accounts now share a persistent account store with Craft++ world-server login. These are still local Craft++ identities; they do not authenticate BYOND accounts or establish ownership on BYOND.com. Live server advertisements and BYOND Hub integration remain absent. |
| Database and regex APIs | Partial | `/database` dispatch is implemented behind a host-supplied `IByondDatabaseAdapter`, rather than BYOND's built-in SQLite provider. Regex objects and helpers route through .NET regular expressions; DM flags, captures, incremental `Find()` state, replacement groups, and PCRE-specific syntax still need a documented compatibility suite. |
| IR VM parity | Partial | The VM now executes captured lambdas, constructors, deletion lifecycle, and built-in object methods; broader differential coverage and exact return propagation remain. |

## Priority order

1. Language correctness: lexer, parser, types, expressions, assignment,
   control flow, procedure dispatch, and exact error locations.
2. Core runtime compatibility: object lifecycle, inheritance, `src`/`usr`,
   vars/procs reflection, lists, text, math, time, and automatic events.
3. World APIs: movement, map/spatial queries, contents, clients, and assets.
4. Persistence and external APIs: savefiles, file APIs, regex, databases,
   browser/UI, and networking compatibility.
5. Compiler/IR parity: every supported language construct must behave the same
   through the interpreter and Craft IR VM, with differential tests.

## Compatibility rule

Craft++ should not label a feature “BYOND-compatible” until it has a focused
test covering syntax, runtime result, mutation/side effects, error behavior,
and (where relevant) interpreter-versus-IR equivalence.

## Specific remaining gaps confirmed by source and reference review

The following are implementation gaps, not generic requests for “more
testing.” Priority P0 means source/runtime semantics can break ordinary DM
program execution; P1 means a documented API family is materially incomplete;
P2 means compatibility and fidelity work after the runtime foundations.

| Priority | DM surface | What Craft++ does now | What is still needed |
|---|---|---|---|
| P0 | `sleep()` and `spawn` | `sleep()` uses decisecond delays but still blocks its host thread and does not suspend/resume caller frames. Interpreter `spawn` now forks delayed execution with copied local slots/shared references; IR spawn copies local slots. Negative delays other than `-1` execute inline. | Replace host-thread blocking with resumable proc scheduling; implement `spawn(-1)` continuation splitting, queue ordering for `spawn(0)`, caller suspension, cancellation/deletion, `src` lifetime, error propagation, and consistent interpreter/IR behavior. BYOND specifies proc-copy and caller-chain semantics. |
| P0 | `walk(Ref, Vector)` | **Implemented:** vector overload now snapshots the 2D displacement, replaces any active walk on that atom, and schedules repeated pixel moves through the normal `Move` override/collision path. Zero vector cancels. Tile-locked movers snap displacement to whole tile increments. | Confirm broader parity around lag scheduling and vector edge cases against BYOND; BYOND documents pixel-vector displacement, copied vector values, and cancellation/replacement of active walks. |
| P0 | Native build/runtime interoperability | Craft++ has a partial DM-inspired parser and produces Craft++ archives; its network transport is Craft++ framing. | If BYOND interchange is a goal, complete DM compiler conformance, native `.dmb`/`.rsc` output, and BYOND wire protocol. The artifact and network formats are separate compatibility targets from runtime semantics. |
| P1 | `input()` / verb arguments | `input(...) as num`, union filters such as `as null|num`, and `as Type in List` choice/type filtering are supported through the text callback. Proc parameter type and direction modifiers are retained in the AST, but verb prompting/validation does not consume them. | Carry parameter metadata and `in` choice expressions into verb dispatch; provide type-aware UI choices and return values for file/icon/sound/key/mob/obj/turf/area/anything; verify cancellation/default/recipient and command-line behavior. |
| P1 | `call_ext()` / `load_ext()` | Calls a delegate registered by the host; it does not discover/load native DLL/SO functions or implement BYOND's string and Byondapi ABIs. | Define and implement an explicitly safe native extension ABI, loading/permission model, typed value marshalling, errors, async calls, and lifetime/refcount behavior—or label these calls unsupported. |
| P1 | `/database` | Dispatch exists, but all real operations require an `IByondDatabaseAdapter`; no built-in SQLite adapter is supplied. | Ship a SQLite-backed adapter and verify parameter binding, typed NULL/number/text/blob values, row iteration, `Columns`, errors, close/reset, and connection/query lifecycle against BYOND's API. |
| P1 | `/regex` | Regex objects use .NET `Regex`; `i`, `m`, global `Find()` and `Find_char()` continuation, Unicode character indexing for `Find_char`, global replacement, and basic captures are implemented. | Match DM pattern extensions (including `[d]`, `[s]`, and fixed-byte lookbehind), byte indexing, stateful behavior across all methods, replacement group syntax, timeout/error behavior, and differential edge cases. |
| P1 | Savefiles and resources | Craft++ savefile/resource support exists but uses Craft++ storage and archive behavior. | Match DM savefile directories, `cd`, sequential buffers and `>>`/`<<`, `Find`, nested savefiles, object `Read`/`Write`, `tmp`, `initial`/`issaved`, resource-cache paths, and BYOND-compatible serialization if interchange is required. |
| P1 | Movement scheduling | Tile/pixel `Move`, `step`, path queries, collision bounds, and scheduled cardinal/target/vector walks exist. | Test `Move()` overrides and multi-turf/area callbacks under pixel movement, swept collisions at speeds larger than bounds, z/non-turf jumps, movement modes, and exact scheduler timing. |
| P2 | Language/preprocessor parity | Indentation grammar supports many DM constructs, including `try`/`throw`, `switch`, `do`, `goto`, and loops. | Build syntax-by-syntax differential cases for precedence/coercion, labels and `goto`, switch/range behavior, dynamic `call`, named args/`arglist`, var initialization/inheritance, compile errors, macros, `#pragma`, compiler macros, and DME include/build rules. Keep braces explicitly documented as a Craft++ dialect difference. |
| P2 | Core object/event model | Core datum/atom hierarchy, selected lifecycle and movement hooks exist. | Complete deletion and `Del`/`Destroy` semantics, world startup/error hooks, `src`/`usr` propagation, waitfor/background, Login/Logout/client reassignment, exact contents/lifecycle ordering, and recursion/error behavior. |
| P2 | Lists and coercion | Basic associative/indexed lists and many helpers exist. | Verify duplicate keys and repeated explicit entries, lazy association writes, `len` resize, list operators, list slicing, list mutation return values, `vars`/special lists, and DM truth/numeric/text coercion and error behavior. |
| P2 | Maps, assets, UI | DMM/DMI handling, editors, client UI callbacks and rendering exist as Craft++ features. | Verify DM map edge cases, complete DMI frame/state/direction semantics, icon arithmetic, filters/appearance, sound channels, browser HTML/JS, skin controls/winset/winget, and resource transfer. These are not equivalent to the native BYOND client. |
| P2 | Interpreter and IR VM | Both execution engines support overlapping language/runtime features. | Add differential execution for every supported syntax and built-in, including return/throw propagation, side effects, mutation, event order, errors, and async scheduling; the current coverage is targeted rather than exhaustive. |

Primary references for the confirmed findings: [BYOND `sleep()`](https://ref.dm-lang.org/proc/sleep), [BYOND `spawn`](https://ref.dm-lang.org/proc/spawn), [BYOND `walk`](https://www.byond.com/docs/ref/info.html), [BYOND `input()` and typed verb arguments](https://ref.dm-lang.org/proc/input), [BYOND `call_ext()`](https://ref.dm-lang.org/proc/call_ext), [BYOND database](https://ref.dm-lang.org/database/index), [BYOND regex guide](https://ref.dm-lang.org/notes/regex), [BYOND savefiles](https://ref.dm-lang.org/savefile/index), and [pixel movement](https://ref.dm-lang.org/notes/pixel-movement).

## Verified project-loading fixes

The DME loader now evaluates conditional branches with the same conditional
expression evaluator used by the source preprocessor, skips inactive includes,
and assigns `maxx`, `maxy`, and `maxz` to their corresponding world dimensions.
Regression coverage is in `CoreLanguageTests.DmeLoadUsesActiveConditionalIncludesAndCorrectWorldDimensions`.
Current verification: main suite 715/715, compiler validation 103/103, and
runtime validation 96/96. These results verify Craft++ behavior; they do not
establish compatibility with the BYOND compiler or runtime.

## Verified movement-event slice

The official reference specifies the order `Exit`, `Enter`, location update,
then `Exited` and `Entered`, and explicitly distinguishes `Move()` from direct
`loc` assignment. Craft++ now implements that tile-movement path for
`atom/movable/Move()` and movement built-ins, including the `oldloc` and
`newloc` arguments, denial behavior, `dir`, and `step_x`/`step_y` updates.
Movements also run `Uncross`/`Cross` checks before committing and
`Uncrossed`/`Crossed` callbacks after commit for movable atoms leaving or
entering the same tile. Spatial registration now clears provisional
pre-registration entries so moved objects do not remain in prior tile buckets;
`LocateAt` also validates live coordinates before returning indexed candidates.
Focused regression coverage is in
`CoreLanguageTests.DmSemantics_EnterExitEvents`,
`DmMovement_DeniedEnterDoesNotCommitLocationOrPostMoveEvents`,
`DmMovement_DeniedExitPreventsEnterAndLocationChange`, and
`DmMovableMove_UsesLocationChecksAndCommitsMovementArguments`, and
`DmMovableMove_UsesSourceDefinedOverride`,
`DmMovement_CrossDenialPreventsOverlapAndReportsBlocker`,
`DmMovement_CrossedAndUncrossedFireAfterSuccessfulLocationCommit`,
`DmMovement_UncrossDenialPreventsLeavingOverlap`, and
`SpatialAndTextCompatibilityTests.RegisterReplacesProvisionalSpatialIndexEntryBeforeLaterMovement`.
This slice does not implement BYOND's complete pixel/slide movement or
pixel-accurate overlap bounds and partial slide movement. See the official
[Move reference](https://www.byond.com/docs/ref/info.html) and
[movement guide](https://www.byond.com/docs/guide/chap07.html).

Verification at completion of the movement-event slice: main suite 715/715,
compiler validation 103/103, runtime validation 96/96, and the Windows IDE
target builds with 0 errors. Passing Craft++ tests verifies these implemented
cases; it is not a BYOND differential conformance result.

## Phase 517: shared pixel-bound collision geometry

The official DM reference defines `bound_x`, `bound_y`, `bound_width`, and
`bound_height` as the atom's collision bounds and describes pixel movement in
relation to `step_x`, `step_y`, and the world tile size. Craft++ now uses one
pixel-bounds helper for `bounds_dist()`, movement overlap hooks, and dense
collision checks. This fixes the root cause where a dense object blocked all
movement in its turf even when the mover's and obstacle's pixel bounds were
separate. Regression coverage is in
`CoreLanguageTests.DmPixelMovementUsesAtomBoundsInsteadOfTreatingWholeTurfAsOccupied`.

Verification: main suite 717/717, compiler validation 103/103, runtime
validation 96/96, and Windows-targeted build succeeds with 0 errors.

## Phase 518: slide versus jump movement

The official `Move()` reference distinguishes pass/fail jumps from same-Z
turf slides, which may stop at a blocking `Cross()` or `Enter()` and return the
greatest pixel distance moved on either axis. Craft++ now classifies short
turf moves, advances them in pixel samples through the shared validation
path, preserves the last valid location and offset on blockage, and returns
the actual slide distance. Moves outside the slide criteria remain atomic
and return 1 or 0. `Exit()` and `Enter()` checks are skipped while changing
pixel offsets within the same turf; overlap checks and post-move overlap
callbacks still run as bounds begin or cease intersecting.

Regression coverage is in
`CoreLanguageTests.DmMovableMoveSlidesUntilPixelBoundsReachDenseObstacleAndReturnsDistance`,
`DmMovableMoveJumpRemainsAtomicWhenDestinationIsBlocked`,
`DmPixelMoveFiresCrossedAndUncrossedWhenBoundsPassThroughAtom`,
`DmStepAppliesStepSizeAndOptionalSpeedInPixels`, and the movement-event tests.
Verification: main suite 720/720, compiler validation 103/103, runtime
validation 96/96, and Windows-targeted build succeeds with 0 errors. Multi-tile
movement traversal and differential BYOND movement coverage remain open.

## Phase 519: default Cross density rule

The official [`Cross()`](https://www.byond.com/docs/ref/info.html) reference
says overlap is permitted by default unless both atoms are dense, and the
[`density` reference](https://www.byond.com/docs/ref/info.html) specifies that
mobs default to dense. Craft++ now shares that rule between direct `Cross()`
calls and collision checks. The direct-method fallback covers inherited atom
procs on `/area`, `/turf`, `/obj`, and `/mob`; the IR VM routes the method through
the same handler while source-defined `Cross()` overrides still run.
Regression coverage is in
`CoreLanguageTests.DmDefaultCrossBlocksOnlyWhenBothAtomsAreDense`.

## Phase 520: Bump argument and receiver semantics

The official [`Bump()` reference](https://www.byond.com/docs/ref/info.html)
specifies that the blocked mover receives `Bump()` with the blocking atom as
its argument. Craft++ previously
called `Bump()` on both atoms and populated formal parameters with null. Bump
dispatch now invokes the mover's proc through normal procedure invocation, so
the obstacle argument and proc context are preserved. Regression coverage is
in `CoreLanguageTests.DmBumpRunsOnBlockedMoverAndReceivesTheDenseObstacle`.
Default group swapping and movement-mode behavior are implemented and tracked
in Phase 521 below.

Verification after Phases 519–520: main suite 722/722, compiler validation
103/103, runtime validation 96/96, and the Windows IDE target builds with 0
errors. Existing compiler warnings are not compatibility evidence.

## Phase 521: movement modes and grouped mob bump behavior

The official [`mob.group`](https://www.byond.com/docs/ref/info.html) reference
defines an empty default list and permits asymmetric membership. `Cross()` and
`Bump()` specify that the obstacle's group membership governs same-group
overlap; legacy mode permits such overlap when either mob uses pixel movement,
while non-legacy modes block it. The default Bump action swaps only full-tile,
tile-stepping group mobs. Craft++ now initializes `group` and
`world.movement_mode` to their documented defaults, applies those Cross rules,
and performs the eligible default swap. A custom Bump override suppresses the
default unless it calls `..()`. Preserving `__proc_args` in object-procedure
frames makes that parent call receive the original obstacle.

Regression coverage is in `MovementGroupParityTests` for default values,
asymmetric group membership, nonmembers, pixel movement, all three symbolic
movement-mode names, custom Bump overrides, and parent dispatch. Verification:
main suite 731/731, compiler validation 103/103, runtime validation 96/96,
and the Windows-targeted build succeeded with 0 errors. Remaining gaps include
the numeric values and compiler exposure of movement-mode constants,
`TILE_MOVER`, multi-tile `locs`, and broader BYOND movement rules.

## Phase 522: movement-mode constants in DM execution

The official reference lists `LEGACY_MOVEMENT_MODE`, `TILE_MOVEMENT_MODE`,
and `PIXEL_MOVEMENT_MODE` as the supported values of `world.movement_mode`.
Craft++ previously recognized those names only when supplied as text; using
the documented identifiers in DM source failed because they were not exposed
as global values. The three names are now available to interpreted DM code and
are forwarded into the IR VM global environment. Their symbolic spelling is
preserved because the official reference does not specify numeric values.
Regression coverage in `MovementGroupParityTests` assigns each identifier to
`world.movement_mode` and verifies the mode's grouped-mob collision behavior.

Sources: [BYOND DM reference: movement_mode](https://www.byond.com/docs/ref/info.html)
and [BYOND 514 release notes](https://www.byond.com/docs/notes/514.html).

Verification: movement parity tests 12/12, main suite 734/734, compiler
validation 103/103, runtime validation 96/96, and the Windows-targeted IDE build
succeeds with 0 errors. Existing obsolete-URI warnings remain. This closes only
the documented identifier lookup gap; movement-mode numeric equivalence and
broader movement behavior remain unverified.

## Phase 523: physical turf coverage and dynamic map geometry

The official [`locs` reference](https://www.byond.com/docs/ref/info.html)
defines `locs` as a read-only view of the turfs covered by a movable atom's
physical bounds, says non-turf locations yield the location itself, null
locations yield an empty list, and requires each covered turf's `contents` to
include the movable. BYOND also documents the dependency of default bounds on
`world.icon_size` and `world.map_format`. Craft++ now computes `locs` from the
anchor turf, `step_x`/`step_y`, bounds, and rectangular tile dimensions; keeps
default bound width/height tied to world geometry while retaining explicit
overrides; and synchronizes turf contents when bounds, location, tile size, or
map format changes. Execution rebinds the active world after resetting the
world registry, so geometry reads the current world's settings.

Regression coverage is in `MovableLocsParityTests` for multi-turf coverage,
step and bounds edits, removal from old turf contents, null/non-turf locations,
read-only assignment, `world.icon_size` changes, rectangular icon sizes, and
map-format-dependent height. Verification: main suite 741/741, focused
movement/locs tests 6/6, compiler validation 103/103, runtime validation
96/96, and Windows-targeted IDE build 0 errors.

## Phase 524: world map-format identifiers

The official [`world.map_format` reference](https://www.byond.com/docs/ref/info.html)
lists `TOPDOWN_MAP`, `ISOMETRIC_MAP`, `SIDE_MAP`, and `TILED_ICON_MAP` as its
documented values. Craft++ now exposes each name as a symbolic DM value and
forwards it into the IR VM's global environment. The rectangular-footprint
test assigns `ISOMETRIC_MAP` directly; a companion test verifies all four
identifiers resolve to their documented spellings. These values remain
symbolic because the reference does not provide numeric equivalents here.
Verification: the main suite includes both direct symbolic assignment and
identifier lookup coverage (741/741 total); compiler validation 103/103,
runtime validation 96/96, and Windows-targeted build 0 errors.

## Phase 525: rectangular pixel movement axes

The official [`world.icon_size`, `step_size`, and `step_x`/`step_y` references](https://www.byond.com/docs/ref/info.html)
define independent icon width and height and movement offsets in pixels; the
reference also cautions that non-square topdown tiles can interfere with pixel
movement. Craft++ now uses tile width for horizontal pixel coordinates and
tile height for vertical coordinates across movement, collision bounds, and
slide calculations. A regression case exercises sequential northward movement
within a 16×48 tile and then a horizontal tile crossing. Verification: focused
movement/`locs` tests 7/7; broader suites are being run for this checkpoint.

Checkpoint verification completed: main suite 742/742, compiler validation
103/103, runtime validation 96/96, Windows-targeted build 0 errors. The build
still reports the existing `Uri.EscapeUriString` obsolete warning.

## Phase 526: per-atom tile movement lock

The official [`movement_mode` and `appearance_flags` references](https://www.byond.com/docs/ref/info.html)
state that `TILE_MOVER` locks an atom to the grid regardless of world movement
mode, and that the flag combines with other flags as a bitfield. Craft++ now
exposes `TILE_MOVER` and makes `step()` clear stale pixel offsets and move a
tile-locked atom by one complete tile while pixel movement is enabled. The
documented reference does not publish the flag's numeric encoding; Craft++ uses
bit 11, inferred from the documented appearance-flag ordering and the known
sequence through `TILE_BOUND`. Regression coverage checks the flag value and
grid-locked movement. Verification: focused movement/`locs` tests 8/8, main
suite 743/743, compiler validation 103/103, runtime validation 96/96, and
Windows-targeted build 0 errors. The build still reports the existing
`Uri.EscapeUriString` obsolete warning.

## Phase 527: canonicalize geometry when tile movement is enabled

The official [`world.movement_mode` reference](https://www.byond.com/docs/ref/info.html)
says `TILE_MOVEMENT_MODE` discards pixel offsets and anomalous bounds, and that
`TILE_MOVER` applies tile-mode behavior to an individual atom. Craft++ now
normalizes already registered movable atoms when the world switches to tile
movement and normalizes an atom when `TILE_MOVER` is added: pixel offsets and
bound origins are cleared, bound dimensions return to the current map's default
tile dimensions, and turf `contents` are resynchronized. The tile-mode test
covers a rectangular icon size and checks the immediate variable and `locs`
results after switching modes. The flag's bit 11 encoding remains an inference
because the official reference documents the flag but omits its numeric value.
Verification: focused movement suites 21/21, main suite 744/744, compiler
validation 103/103, runtime validation 96/96, Windows-targeted build 0 errors,
and `git diff --check` clean. Existing obsolete-URI and compiler-validation
warnings remain.

## Phase 528: client and mob parent movement defaults

The official [`client.Move()` and directional proc references](https://www.byond.com/docs/ref/info.html)
specify that directional procs call `client.Move()`, which then calls
`mob.Move()`; the [DM guide's client movement section](https://www.byond.com/docs/guide/chap09.html)
also describes this override chain. Craft++ previously dispatched the normal
directional case to `mob.Move()`, but `return ..()` inside a custom
`/mob/Move()` executed the registered empty proc body and returned null. The
client default was also absent from `/datum`'s type chain, so a custom
`/client/Move()` could not reach it through `..()`. Parent dispatch now invokes
the host movement default for empty movable `Move` procs and explicitly handles
the host-provided `/client/Move` default when it has no type-chain parent.
Regression tests cover default directional movement, a rejecting mob override,
and the full custom-client `Move()` to parent-default to mob movement chain.
Automated-walk cancellation is implemented separately in Phase 529 below and
is not counted as covered by this phase. Verification:
focused client movement tests 3/3, main suite 747/747, compiler validation
103/103, runtime validation 96/96, and Windows-targeted build 0 errors. The
build reports the existing obsolete-URI warning.

## Phase 529: scheduled directional walk and Center cancellation

The official [`walk()` reference](https://www.byond.com/docs/ref/info.html)
defines continuous movement, tick-based lag, replacement of a previous walk
for the same reference, and `walk(Ref, 0)` cancellation. The same reference
documents that `client.Center()` stops automated movement and that the default
`client.Move()` cancels walking before dispatching to `mob.Move()`. Craft++'s
live `WorldScheduler` now owns per-atom walk commands, advances them on world
ticks through the atom's `Move()` proc, replaces previous commands, and removes
the command on zero direction. Client `Center()` and user-driven default client
movement use that cancellation path. Standalone headless execution without a
started world scheduler retains its immediate one-step behavior; the live
Dream Seeker runtime exercises persistent scheduling. Target following is
tracked in Phase 530; `walk_away` and `walk_rand` are tracked in Phases 531 and
532. Regression coverage verifies repeated live movement and that `Center()`
stops subsequent ticks. Verification: focused automated-walk test 1/1, main
suite 748/748, compiler validation 103/103, runtime validation 96/96, and
Windows-targeted build 0 errors. The build reports the existing obsolete-URI
warning; `git diff --check` is recorded after the source review.

## Phase 530: continuous target-following walks

The official [`walk_to` and `walk_towards` references](https://www.byond.com/docs/ref/info.html)
specify continuously reevaluated movement, world-tick lag, replacement of the
current walk, and use of the `Move()` chain. Craft++ now registers both modes
with the live `WorldScheduler`; `walk_to` requests the path step respecting
Min, while `walk_towards` recalculates its direction from the target each tick.
The shared `get_step()` location fix returns a turf for an empty destination
coordinate, so path steps do not fail solely because a turf instance had not
yet been materialized. Headless execution without a scheduler retains its
existing one-step fallback. Live regressions verify the Min boundary and
arrival behavior. Verification: focused automated-walk tests 3/3, main suite
750/750, compiler validation 103/103, runtime validation 96/96, and
Windows-targeted build 0 errors.

## Phase 531: scheduled `walk_away`

The official [`walk_away` reference](https://www.byond.com/docs/ref/info.html)
specifies continuous movement away from a target, a maximum distance, per-step
lag, speed, and replacement of a previous walk. Craft++ now schedules this
mode in the live world runtime and rechecks the target range at each tick; it
stops once its next-step helper finds the atom outside Max or cannot find a
step. The initial helper was greedy; its obstacle-routing limitation is
addressed in Phase 533. A runtime regression checks that the atom exits Max
and the walk stops. Verification: focused automated-walk tests 4/4.

## Phase 532: scheduled `walk_rand`

The official [`walk_rand` reference](https://www.byond.com/docs/ref/info.html)
specifies continuous random movement, per-step lag and speed, and replacement
of a prior walking command. The live `WorldScheduler` now chooses a new random
direction for each due tick, routes the move through `Move()`, and supports
replacement and cancellation using the existing walk lifecycle. Headless
execution without a running scheduler still uses its immediate one-step
fallback. Runtime regressions verify repeated movement and cancellation via
`client.Center()`. Verification: focused automated-walk tests 5/5, main suite
754/754, compiler validation 103/103, runtime validation 96/96, and
Windows-targeted build 0 errors. The build retains the obsolete-URI warning.

## Phase 533: pathfind away through dense barriers

The official [`get_step_away` and `walk_away` references](https://www.byond.com/docs/ref/info.html)
require a path away from the target that takes obstacles into account. The
previous implementation ranked only adjacent tiles and could oscillate when
the only viable route temporarily approached the target. `get_step_away` now
uses breadth-first search through unoccupied map tiles to a tile at Max+1
Chebyshev distance and returns the first direction on that route. The search
is bounded by the target-distance ring; its grid topology remains a Craft++
approximation and is not asserted to match BYOND's internal pathfinding
exactly. World-edge handling is addressed in Phase 534. Tests cover a barrier that blocks every
immediately outward direction and verify both `step_away` and live scheduled
`walk_away` can route beyond Max and stop. Verification: focused pathfinding
and walk tests 7/7, main suite 754/754, compiler validation 103/103, runtime
validation 96/96, Windows-targeted build 0 errors, and `git diff --check`
clean. The build retains the existing obsolete-URI warning.

## Phase 534: enforce inclusive world map bounds

The official [`world.maxx`, `world.maxy`, and `world.maxz` references](https://www.byond.com/docs/ref/info.html)
define a world as an inclusive turf block from `(1,1,1)` to
`(maxx,maxy,maxz)`. Craft++ now applies those bounds in the shared turf
resolver, so `locate`, `get_step`, ordinary movement, random steps, and the
`get_steps_to`/`get_step_away` path searches cannot create or route through an
out-of-world turf. `get_step_away` also returns no step promptly when the
configured map cannot reach Max+1. The change is based on configured runtime
world extents; worlds without an active interpreter retain permissive registry
behavior for host-side tooling. Boundary regressions cover all three axes,
movement rejection without position changes, path queries beyond the edge,
and a map too small to reach the requested retreat radius. Verification:
boundary tests 2/2, main suite 756/756, compiler validation 103/103, runtime
validation 96/96, Windows-targeted build 0 errors, and `git diff --check`
clean. The build retains the existing obsolete-URI warning.

## Phase 535: byte counts for `spantext()` and `nonspantext()`

The official [`spantext()`](https://www.byond.com/docs/ref/info.html) and
[`nonspantext()`](https://www.byond.com/docs/ref/info.html) references define
their `Start` argument as a byte position and explicitly direct callers to the
`_char` variants when they need character counts. Craft++ previously counted
one per Unicode rune for both standard procs, while its `_char` implementations
already counted Unicode scalars. The standard procs now count the UTF-8 bytes
of each matched rune, preserving the distinct character semantics of
`spantext_char()` and `nonspantext_char()`; a byte start inside a multibyte
sequence advances one malformed byte at a time. Regression coverage compares
both standard and `_char` results on multibyte text and includes a negative
byte start. Verification: focused runtime regression 1/1, main suite 756/756,
compiler validation 103/103, runtime validation 97/97, Windows-targeted build
0 errors, and `git diff --check` clean. Builds retain the existing
obsolete-URI warning.

## Phase 536: numeric range and accepted forms for `noise_hash()`

The official [`noise_hash()` reference](https://www.byond.com/docs/ref/info.html)
specifies one or more numeric inputs or a list of numbers, an optional leading
hash name reserved for future use, deterministic repeatability, and a result
from zero inclusive to one exclusive. Craft++ previously hashed each
argument's display string and returned a nonnegative integer; this also meant
the list and named-list signatures did not match the documented form. It now
hashes each numeric argument's IEEE-754 representation, flattens list inputs,
ignores the currently reserved hash name, and normalizes a stable 32-bit
sample into `[0,1)`. Tests cover repeatability, the range, positional/list
equivalence, and both named forms. This does not claim BYOND's internal hash
algorithm is byte-for-byte reproduced because the reference documents output
properties, not its algorithm. Verification: focused regressions 2/2, main
suite 756/756, compiler validation 103/103, runtime validation 98/98,
Windows-targeted build 0 errors, and `git diff --check` clean. Builds retain
the existing obsolete-URI warning.

## Phase 537: preserve named arguments on builtin calls

The official [`gradient()` reference](https://www.byond.com/docs/ref/info.html)
supports named `index` and `space` arguments and `arglist()` expansion with
named list entries. Craft++ previously flattened every builtin call to a
positional list; a named expression could execute as an assignment in the
caller and its parameter name was lost. The interpreter now separates named
arguments from positional values, extracts named entries from `arglist()`
lists, and passes the names through a new builtin dispatch overload.
`gradient()` consumes named `index`; regressions verify direct and `arglist()`
calls return the same color and leave a caller variable unchanged. Other
builtin-specific named parameters, including `gradient(space=...)`, still need
their own binding/behavior work and are not counted as complete by this phase.
Verification: focused regression 1/1, main suite 757/757, compiler validation
103/103, runtime validation 98/98, Windows-targeted build 0 errors, and
`git diff --check` clean. Builds retain the existing obsolete-URI warning.

## Phase 538: wrap hue during HSL gradient interpolation

The official [`gradient()` reference](https://www.byond.com/docs/ref/info.html)
specifies that the looping red-to-cyan-to-red HSL gradient at index 10 wraps
the position to 4 and returns blue (`#0000ff`). Craft++ already supported
explicit stops, looping, HSL/HSV/HCY conversion, and named/list `space` values,
but interpolated hue as a linear scalar. On the cyan-to-red segment this
crossed hue 120 instead of continuing around the hue wheel through 240. Hue
interpolation now advances across 360 degrees when the next stop's hue is
numerically lower. A regression checks the reference example both with named
arguments and with an associated `space` entry in a reusable gradient list.
This establishes parity for that documented case; it does not claim exact
parity for BYOND's full color conversion implementation. Verification: focused
regression 1/1, main suite 758/758, compiler validation 103/103, runtime
validation 98/98, Windows-targeted build 0 errors, and `git diff --check`
clean. Builds retain the existing obsolete-URI warning.

## Phase 539: default gradient endpoints and duplicate-position steps

The official [color gradient reference](https://www.byond.com/docs/ref/info.html)
defines a default 0-to-1 gradient domain, explains that repeated positions
create a sudden color change, and gives a looping candy-cane gradient with two
stops at 0.5. Craft++ previously kept only the two 0.5 stops, so the gradient
had zero span and returned white for every index. The evaluator now extends
in-range stops to the default 0 and 1 endpoints using the first and last
colors. This preserves duplicate-position discontinuities and lets loop
indices cycle through both colors. Tests also exercise the reference's
omitted-position/omitted-color list pattern. This phase covers listed stop
forms and the specified hard-step example; it does not claim identical edge
behavior for all out-of-range custom domains. Verification: focused gradient
regressions 3/3, full suite 760/760, compiler validation 103/103, runtime
validation 98/98, Windows-targeted build 0 errors, and `git diff --check`
clean. Builds retain the existing obsolete-URI warning.

## Phase 540: expose the documented `COLORSPACE_HSLA` gradient name

The official [color gradient reference](https://www.byond.com/docs/ref/info.html)
uses `COLORSPACE_HSLA` in its HSL color-wheel example, but Craft++ exposed only
`COLORSPACE_HSL`, so that documented source failed to compile. Craft++ now
defines and exports `COLORSPACE_HSLA` as an HSL selector. The runtime already
interpolates alpha independently of RGB/HSL/HSV/HCY, so colors with alpha keep
their `#RRGGBBAA` channel behavior under this alias. Regression coverage
compiles the reference list form and checks that an intermediate alpha is
preserved. The reference does not document the numeric encoding of this
constant; this implementation claims the documented name and color behavior,
not a verified numeric encoding. Verification: focused regression 1/1, main
suite 760/760, compiler validation 103/103, runtime validation 98/98,
Windows-targeted build 0 errors, and `git diff --check` clean. Builds retain
the existing obsolete-URI warning.

## Phase 541: generator distribution constants

The official [`generator()` reference](https://www.byond.com/docs/ref/info.html)
names `UNIFORM_RAND`, `NORMAL_RAND`, `LINEAR_RAND`, and `SQUARE_RAND` as
the supported distribution choices. They were absent from Craft++'s global
environment, so valid generator source failed at runtime with an undefined
variable. Craft++ now exposes the four names in both the interpreter and IR
execution paths, mapped to the distribution selectors already consumed by
`SampleGeneratorRange`. A source-level regression constructs all four
generator forms and checks their stored selectors in order. The reference
lists the names and semantics but not their numeric encoding; the exposed
values follow Craft++'s existing internal selector mapping and are not claimed
as verified BYOND numeric values. Verification: focused regression 1/1, main
suite 761/761, compiler validation 103/103, runtime validation 98/98,
Windows-targeted build 0 errors, and `git diff --check` clean. Builds retain
the existing obsolete-URI warning.

## Phase 542: matrix shortcut constants

The official [`matrix()` reference](https://www.byond.com/docs/ref/info.html)
documents scale, rotate, and translate constructor forms using
`MATRIX_SCALE`, `MATRIX_ROTATE`, and `MATRIX_TRANSLATE`. Craft++ already
implemented those three constructor modes but omitted their names from the
global environment, so valid DM source raised an undefined-variable error.
The constants are now available in interpreter and IR execution, with values
matching the existing constructor dispatch, and a source-level test exercises
all three forms and their resulting components. The reference documents the
symbolic names and behavior but not their numeric encoding; no BYOND numeric
parity claim is made. Verification: focused regression 1/1, main suite 762/762,
compiler validation 103/103, runtime validation 98/98, Windows-targeted build 0
errors, and `git diff --check` clean. Builds retain the existing obsolete-URI
warning.

## Phase 543: affine matrix interpolation

The official [`matrix/Interpolate()` reference](https://www.byond.com/docs/ref/info.html)
says interpolation handles scale/shear before rotation and translation, treats
a 180-degree rotation as a flip, returns a new matrix, and allows `t` outside
0–1 for extrapolation. Craft++ previously linearly blended all six coefficients
in place, which made a halfway 0-to-90-degree rotation shrink to half size and
mutated the receiver. Interpolation now decomposes affine scale, shear, and
rotation, blends translation separately, creates a distinct result, and retains
extrapolation. Degenerate matrices whose first basis column has zero length
fall back to coefficient interpolation because their rotation is undefined.
Regression tests cover halfway rotation without scale collapse, nonmutation,
extrapolation, and the 180-degree flip case. Verification: matrix interpolation
regressions 4/4, main suite 765/765, compiler validation 103/103, runtime
validation 98/98, Windows-targeted build 0 errors, and `git diff --check` clean.
Builds retain the existing obsolete-URI warning.

## Phase 544: preserve degenerate matrices during inversion

The official [`matrix/Invert()` reference](https://www.byond.com/docs/ref/info.html)
says a matrix without an inverse is degenerate and remains unchanged. Craft++
previously replaced a near-zero determinant with `1e-12`, which corrupted a
singular but nonzero scale matrix while manufacturing huge coefficients. The
inversion now returns the original matrix untouched when the determinant is
non-finite or below the existing singularity tolerance. A regression confirms
the matrix identity and all six transform coefficients remain unchanged.
Verification: focused inversion regressions 2/2, main suite 766/766, compiler
validation 103/103, runtime validation 98/98, Windows-targeted build 0 errors,
and `git diff --check` clean. Builds retain the existing obsolete-URI warning.

## Phase 545: unary `~` matrix inversion in interpreter and IR

The official [`~` operator reference](https://www.byond.com/docs/ref/info.html)
defines numeric bitwise-not and specifies that applying it to a `/matrix`
returns a new inverse matrix. The tree-walking interpreter treated every `~`
operand as numeric, while the Craft IR VM passed operands through unchanged.
Both execution engines now preserve numeric bitwise-not and route matrix values
through copy-then-invert semantics, including singular-matrix preservation from
Phase 544. Regressions execute source through the interpreter and directly
through Craft IR, checking inverse scale components, receiver nonmutation, and
numeric `~5 == 16777210`. Verification: focused regressions 2/2, main suite 769/769,
compiler validation 103/103, runtime validation 98/98, Windows-targeted build 0
errors, and `git diff --check` clean. Builds retain the existing obsolete-URI
warning.

