Lamium's world-overlay foundation is integrated rather than compile-only. Shapes, Chunk Borders, Hitboxes and the light overlay share the world-rendering infrastructure. Shapes have a dedicated editor and local-world sidecar persistence. Basic Shapes rendering/persistence, Java-style Chunk Borders and ordinary Hitboxes have runtime evidence; broad graphics-mode, resource-pack, crowded-world and lifecycle coverage remains incomplete.
ShapeCollection is the game-independent shape manager: stable session IDs,
names, visibility, dimension ownership and cached block-surface geometry.
Geometry is built when a shape changes, not during read-only drawing. Failed
generation or budget checks leave the previous entry intact. The collection
defaults to 32 shapes and 200,000 total cached lines, including hidden shapes;
removing entries frees the budget. IDs are not reused by clear, so a stale
editor selection cannot refer to a new shape.
The runtime owns the collection behind a mutex and exposes definition-only
snapshots/mutations through ShapeSession.h. Visible shapes in the current
dimension draw from cached CPU geometry and uploaded meshes. World exit and
overlay shutdown release session state/resources. Local-world joins bind the
workspace to lamium/shapes.json under the resolved world directory; unsupported
or remote identities remain session-only.
Cell overlays (L-138, built 2026-10-11): Shapes, the breaking region and
the schematic save area draw through one builder: CellSurface.h (faces on
the cells' own planes and the outline, pure and tested) and CellMesh
(upload, face material, outline coloring, pull toward the eye by the
Depth.h rules). Each keeps its own colors and decides when it shows.
Shapes open from the pinned settings sidebar entry or the initially unbound
openshapes key. The Shape drawing feature in settings has a switch that
hides or shows every shape, a toggleshapes binding on its parent row and
the openshapes command on a child row (L-83).
The view places a shape list beside an editor. The list shows color, name,
type (other dimensions are dimmed and tagged) and a visibility switch. The
editor shows the name, a top-down block preview of one layer (planes are seen
along their normal) with a layer stepper, and fields grouped as shape,
position and display. Fields come from ui/ShapeEditor.h: adding a shape type
means adding its entry and fields there. The header toggles all shape drawing,
links to the Shape rendering row in settings, and docks the view to the right
edge so the world stays visible (the draw-all switch then moves to the
toolbar). Editing keeps both scroll positions.
"New shape" first asks for a type, then opens a draft that is previewed in the world as light-blue lines but not saved. The center reference is the standing block (snapped to its center), the exact position (no snapping) or the targeted block; "Move here" uses the same reference for existing shapes. The standing and exact references follow the drawn view (L-248): while Freelook or FreeCamera detaches it, they use the camera's virtual feet (its position minus the player's eye height) instead of the body, the same reference the schematic placement actions use. A targeted block comes from the hit alone, so it does not depend on a usable view pose. Create adds the draft; Cancel or leaving the view discards it. Delete requires a second press.
Shapes are drawn from the blocks that form them, not as smooth wireframes. The current presets include circle, cylinder, sphere, box, cone, frustum, pyramid, ellipsoid and dome, plus rectangular planes; ShapeSpec presets can be oriented on Y/X/Z where supported. Each shape has a style (faces: translucent block faces with a faint outline; lines: block edges) and one of the shared shape colors. Older version-1 files load with compatible defaults for fields that did not exist yet.
Each shape's faces and lines are uploaded once per geometry revision, relative to the shape's first block, and positioned each frame with the world matrix. Meshes are released when shapes are removed or the world is left. Face materials follow graphics mode as documented in DESIGN.md (Fancy uses the hologram-pointer path where available; Simple/Vibrant Visuals use the lightning/strong-line fallbacks). Runtime work established the current translucent/line strategy, but alternate packs and graphics modes are not exhaustively covered.
Depth (L-110, 2026-10-08): every face overlay follows the rules in
overlay/Depth.h (tested in OverlayGeometryTests). Faces lie on their cell's
own plane and the mesh is pulled toward the eye by a fraction, so it stays in
front of the block face there at any distance and angle. The earlier 0.005
inset into the cell (2026-09-23) fell behind the block face when looking at a
grazing angle a few blocks away, which made Shapes and the breaking
restriction's faces fight with the terrain; it is gone. Offsets along the
normal are allowed only toward the side the camera must be on (light tints
lift into their air cell). Pulls per layer: ghosts .998, faces and tints
.997, light digits .995, digit lines .993.
Pure tests cover type definitions, editor rows, stepping and validation, reference placement, preview layers and runs, and the view's hit testing.
The definition codec uses version 1 JSON with a shapes array. Every entry
stores name, dimension, visible, style, color and geometry.
Runtime IDs and derived faces/lines are never persisted.
Shape geometry types are circle, cylinder, sphere, box, cone,
frustum, pyramid, ellipsoid and dome. They store a three-number
center, snap (block_center, block_corner, off), radius,
integer height, axis (y, x, z), topRadius, heightRadius
and dome. Fields added after the first version-1 files are optional on read
and receive legacy-compatible defaults. Plane geometry uses type: plane,
integer origin, width, depth, spacing and plane (xz, xy,
yz).
Decoding rejects unsupported versions/options, malformed values, documents over 1 MiB, more than 32 entries and collections exceeding geometry budgets. Integer fields never silently truncate fractional values. Collection replacement builds and validates a complete candidate before swapping it in; failed loading keeps the previous definitions, IDs and caches. Successful replacement assigns fresh IDs. Codec tests cover legacy fields, new presets/axes, UTF-8 metadata, large-coordinate precision and malformed input.
ShapeStore reads at most 1 MiB plus one detection byte and validates before
returning definitions. Its Windows writer validates first, reserves a sibling
temporary file with exclusive creation, writes and flushes it, then replaces
the destination. On failure it cleans up only its own temporary file and leaves
the previous destination intact. Filesystem tests cover first save, replacement,
UTF-8 names, invalid data, oversized reads and replacement blocked by an open
Windows handle. The store is connected to the local-world workspace: supported local joins
load and save lamium/shapes.json; unsupported/remote identities stay
session-only. Save-before-publish behavior preserves the previous live/file
state on failure.
Chunk Borders defaults off. It draws the current chunk walls with a yellow 2-block grid, blue 16-block section lines/current-chunk corners and red neighbor-chunk corners, using floor division at negative coordinates and the dimension height range. During Freelook/FreeCamera the view chunk replaces the player chunk as the center. The Java-style color structure has been compared against a Java reference in game.
Hitboxes draw white actor bounds plus a red eye marker and blue 2-block look
line for ordinary mobs. Ender Dragon multipart damage boxes are deliberately
not guessed; L-30 tracks whether Bedrock exposes real part boxes. Hitbox lines
use each actor's frame-interpolated render position. The eye marker adds an
interpolated, actor-specific eye offset sampled from getEyePos(); the view
vector uses the same frame alpha. White bounds and the revised eye marker were
confirmed in game by 2026-09-28 (L-51). Chunk Borders and
Hitboxes submit grouped per-color line batches through the shared tessellator
path, pulled toward the eye by 0.994 (Depth.h; without a pull lines lying on
block faces broke up into dashes, L-157; at 0.996 the vanilla selection
outline still covered them), and
retain no actor/player pointer across frames. Basic visible output is past the
compile-only stage; crowded-world performance, graphics/resource-pack variants
and broader lifecycle cases still need coverage.
Known bug (L-176, reported 2026-10-14): both Chunk Borders and Hitboxes lose
their line colors with Vibrant Visuals enabled; Hitboxes is now confirmed
in game, not only suspected from the shared path. drawLines() submitted
one debug mesh with vertex colors. Fixed 2026-10-14 (2d176aa; colors seen
in Vibrant Visuals on 9b3b8a9): it now submits each nonempty color group separately (up to five for Chunk
Borders, three for Hitboxes) with the LineColor.h selection-outline
material and that group's shader color, restored after every draw; vertex
colors stay for the debug fallback. Geometry, the eye pull and caching are
unchanged. Ordinary modes, graphics switching and depth are still to check
(VALIDATION.md).
Chunk border line coordinates are cached per render thread by chunk origin and dimension height range. Movement within a chunk reuses the same CPU geometry; crossing a chunk boundary or changing the height range rebuilds it. Reuse across worlds with identical bounds is safe because the cache contains only coordinates. Inputs are validated even on cache hits, and failed generation preserves the last valid cache entry. GPU meshes remain temporary and camera-relative vertices are still submitted each frame. Unit tests cover reuse, positive/negative boundary crossings, height changes, and invalid input; runtime performance is unmeasured.
World-space lines and wire boxes use continuous coordinates. Building guides use integer block cells and exposed block faces. They are distinct representations; turning center snapping off never converts a building guide into a smooth mesh.
Shape centers default to the containing block's center (floor(position) + 0.5),
including negative coordinates. Block Corner uses the containing block's lower
corner, and Off retains the supplied center. Radius tests sample block centers.
The filled representation of a circle is a single disk layer; its horizontal
boundary cells form a ring. A cylinder repeats that disk upward from the center's
block Y for the specified number of layers. A sphere uses three-dimensional
distance. Boundary extraction removes shared internal faces; shell cells can be
obtained separately. These are explicit Lamium conventions, not a claim of exact
voxel-for-voxel equivalence with another mod.
Rectangular planes support XZ, XY, and YZ orientations. Unit spacing fills the plane; larger spacing produces grid lines with a complete outside border. Face vertices lie on block boundaries and have outward winding for subsequent line or triangle rendering.
gridSurfaceLines converts exposed block faces into unique unit-length edges.
It preserves grid seams on the outside surface so individual block positions
remain visible, while excluding edges contributed only by internal faces.
Canonical integer endpoints avoid reversed-edge duplicates and floating-point
matching. The operation rejects inputs over 250,000 cells or its configurable
line budget (one million by default); it never returns a truncated guide.
Tests cover a single block, adjacent blocks, a solid cube, internal-edge removal,
and budget rejection. These lines use the same Line representation accepted
by the world renderer and the session Shape Manager/Editor. CPU geometry
conversion alone does not establish visible rendering correctness.
Enumeration has a default work limit of 250,000 candidate cells. Oversized shapes are rejected before enumeration rather than silently truncated. Coordinates are checked before integer conversion and retain neighbour-arithmetic headroom. Shape generation must be cached outside per-frame drawing when connected to the game; the work limit alone is not a frame-time guarantee.
Pure tests cover negative-coordinate snapping, translations, known small shapes, shared-face removal, rings, plane orientation, grid gaps, face winding, new shape-profile/axis cases and invalid/oversized input. Runtime checks cover the basic renderer/editor path, while exhaustive depth/material, camera-relative precision, performance and lifecycle coverage remains incomplete.
ShapeWorkspace owns a collection and an optional resolved world-specific file.
Entering another workspace clears previous shapes before reading. Successful
loads allocate fresh session IDs so an old editor selection cannot target a
different shape. A failed load leaves an empty collection and blocks editing
until a successful retry or explicit departure; it cannot overwrite the
unreadable source with an empty document.
Changes prepare a candidate collection and publish it only after the complete file has been written successfully. Failed writes preserve both previous live values and the destination file. Leaving clears the file binding; subsequent session-only changes cannot save into the departed world's file. Candidate copies and geometry validation have a cost and must remain outside rendering.
This boundary is connected to primary-player world entry and world exit. For
local joins, the current game's FilePathManager::mWorlds and Level ID resolve
an existing direct-child world directory containing level.dat. The shape file
is lamium/shapes.json inside that world, separating identical IDs in different
storage roots/profiles and allowing the sidecar to travel with a copied world.
The resolver rejects relative roots, traversal/separator IDs and directories
that do not look like worlds. It does not scan or guess personal directories.
Changes save before publishing to rendering. Save errors have a dedicated message and keep previous values; load errors clear the previous world's collection and block edits until reentry. Resolving no supported local target leaves an explicitly session-only collection. Remote persistence, in-screen load retry, and broader multi-world/failure runtime validation remain outstanding. One local-world save/reentry was verified with the stored name, coordinates, radius, visibility and snap mode restored in the editor and the guide visible. Runtime testing also verified a replacement-denied save: the previous live geometry and file survived, a save error was shown, and retyping the edit after the lock was released successfully saved without leaving the world.
An opt-in shape_trace build records bounded primary-player join diagnostics.
One local world was verified to return its storage directory name as Level ID,
unchanged across save/exit/reentry (see VALIDATION-LOG.md). Persistence integration
uses the storage root to scope local IDs and must separately resolve remote
identities; a world display name or server address alone is insufficient.