# Astra Craft

![Astra Craft icon](pwa-512x512.png "Astra Craft App Icon")

A shared pocket-sized creative building game. Explore a 128 × 128 world with open meadows, scattered trees, sandy lakeshores and gentle hills. Walk, jump or fly, remove blocks and build with eight unlimited colored materials, up to 48 blocks high.

Designed for modern phones in portrait. Left thumb moves; right thumb turns the camera. You can also drag the world to look. Walking is the default, with gravity, jumping and automatic one-block step-up. Tap Walking/Flying (or F) to toggle creative flight. Jump becomes Up in flight; Down is enabled only while flying. A player-sized collision box blocks movement through solid terrain in both modes; substeps prevent tunneling, and walls allow sliding. Water is solid for movement: players walk on its surface and cannot fly beneath it. Previously saved underwater positions recover into clear space above the water. Placement avoids known player bodies; a simultaneous remote placement that encloses someone moves them into clear space. Aim within eight blocks: white outlines the targeted block and mint outlines the placement. Tap Place or Remove. Keyboard controls are described in the in-game help.

Options contains Invite players, Change player name and a fullscreen toggle. Invite retains RCWeb's standard QR panel and copyable room link. Player names use the shared rcwebName local-storage key; updates broadcast immediately and propagate between same-browser tabs. Names are limited to 32 characters and rendered as plain canvas text. Each player appears to others as a block-built character with head, face, torso, arms and legs, a camera-facing overhead nameplate, interpolated movement, head direction and walking animation. The local camera remains first person. Presence updates are throttled to 10 per second, with a background heartbeat; stale characters and their GPU resources are removed. No controller app is needed.

World changes and camera position save in local storage under the room ID. Bookmark the invite URL to return to the same world. The base terrain is deterministic and versioned. Version 3 expands the landscape to 128 × 128 and migrates version 1 and version 2 edit coordinates and tombstones without deleting the original saves. Generated scenery has 43 trees (previously 110) and ground elevations up to 12 blocks. Saved builds retain their coordinates and override the reshaped terrain. New messages use versioned callback names so old clients cannot misinterpret new voxel indices; all participants should refresh after upgrading. Each voxel stores a Lamport counter, a random per-page actor ID and a material, including retained air tombstones. Merge takes the highest counter and then actor ID (with material as a final deterministic tie-break). Concurrent changes to different blocks survive; conflicts at one block resolve consistently, not by wall-clock time. All incoming records are validated. Live edits broadcast immediately; joins, visibility resumes and periodic 12-second repair requests exchange bounded batches. Reconnects also send locally retained edits. Same-browser tabs merge local-storage events and read-before-write snapshots.

Saves live on participating browsers, not the server. Clearing browser data loses that browser's copy; another participant can restore it when connected. Offline changes merge on reconnection. Storage and invalid-data failures are shown visibly. This uses RCWeb's trusted-room transport, not a security boundary against malicious room participants.

Uses the repository's existing Three.js and QR libraries, with no new dependencies. A local imagegen material atlas supplies natural grass, earth, sand, bark, end grain, stone, leaves, snow and colored plaster textures, with filtered mipmaps and subtle bump shading. Directional sunlight, hemisphere lighting, cached soft shadow maps, vertex contact shading and tone mapping light the landscape and player characters. A procedural cloud sky and distance fog complete the scenery. Exposed terrain faces render in 16 × 16 column chunks; edits rebuild only affected chunks and boundary neighbors over successive frames. Modern JavaScript, WebGL and touch Pointer Events required.

Water animates on the GPU and reflects the current raster color and depth buffers using bounded screen-space sampling. Reflections fade at screen edges and use a sky color when no visible surface is found; off-screen objects cannot appear. Shallow water shows the lake bed through depth-based absorption. No ray-traced geometry or mirrored scene camera is used. Browsers without depth textures retain animated water with sky reflections.

Graphics automatically adjust render resolution and reflection sample count to target 60 fps. Static terrain shadows are cached; moving player shadows refresh at most every 150 ms. Performance depends on the device: the local RTX 3090 check measured about 144 fps at a 412 × 915 mobile viewport, including a 4× CPU-throttled movement/edit test (95th-percentile frame time 7.1 ms, occasional edit/input spikes up to 35 ms). This is not a physical-phone benchmark or a guarantee that every frame meets 16.7 ms. Inspect current readings with `astraCraft.graphicsStats()` and run adaptive-quality checks with `node src/main/apps/app/astra-craft/graphics.test.cjs`.

Tree trunks end below the leaf canopy. Alpha-tested leaf sprays extend beyond exposed leaf blocks, and crossed grass tufts grow from uncovered grass surfaces. Decoration is deterministic, batched per terrain chunk, and rebuilt with supporting blocks after local or remote edits. Grass fades out over 20–28 blocks and leaf sprays over 40–48 blocks to limit distant detail. Decorations receive lighting and shadows but have no extra collision or network state. Saved player block edits continue to override generated scenery.

The game preloads [material-atlas.webp](material-atlas.webp) (1024 × 1024, 508,294 bytes) and [foliage-atlas.webp](foliage-atlas.webp) (512 × 512, 198,994 bytes). Both use WebP quality 90; foliage retains lossless alpha after resizing. Combined texture downloads are 707,288 bytes, down 88.6% from the 6,216,896-byte PNG sources. The reduced dimensions also lower texture memory usage. Preloads share the texture loader's anonymous CORS mode so the browser reuses each download.

The built-in imagegen prompts and original source assets are retained in [material-atlas-prompt.md](material-atlas-prompt.md), [material-atlas.png](material-atlas.png), [foliage-atlas-prompt.md](foliage-atlas-prompt.md) and [foliage-atlas.png](foliage-atlas.png). These PNG sources are not downloaded by the game. Run canopy, tuft, visibility and persistence checks with `node src/main/apps/app/astra-craft/foliage.test.cjs`.

Run behavior checks with `node src/main/apps/app/astra-craft/world.test.cjs`.



Avatar behavior checks: node src/main/apps/app/astra-craft/avatars.test.cjs.

Natural lake surfaces meet the lowest surrounding banks (main lake height 6, original lake height 4). Water ripples and reflections animate each frame; terrain meshes and walkable collision surfaces remain stationary. Saved player edits still override generated terrain.
Hair and facial details are textures on a single head cube, eliminating overlapping hair geometry. Each browser gets randomized top and pants colors on first use, saved under astra-craft:outfit. Options → Change player name includes independent color pickers; Save player persists the outfit and sends it with presence updates. Other players validate and apply the same colors, including sleeves and both legs. Nameplates measure the rendered name and use fixed padding, so their box grows only as needed rather than leaving a large empty rectangle.



## Screenshots

![Tree leaf sprays and grass tufts](screenshot-foliage.png)

![Astra Craft with natural textures, sunlight and reflective water on mobile](screenshot-lighting-mobile.png)

![Astra Craft options on mobile](screenshot02.png)

![Astra Craft with sunlight and screen-space lake reflections on desktop](screenshot-lighting-desktop.png)
