# The Last Hearth An original, standalone Luanti survival prototype: gather flint and sticks, make tools, build a supported shelter, fuel a hearth, cook forage and boil water. It does not depend on Minetest Game (MTG). This is an **environment simulation prototype, not a full physics simulator or a launch-ready public service**. Original game code and procedural assets are MIT-licensed; the separately distributed engine retains its own licenses. ## Status and planning **M0 technical gates are complete. M1 implementation/preflight and M2 gameplay / verification are complete; their human acceptance gates remain open. M3 implementation and automated verification are complete; its two-player acceptance gate remains open.** M4 ecology, preservation, pottery, metalworking and bounded offline process work has passed automated technical verification; its week-long group acceptance remains open. M5 is now beginning with an offline-tested private staging deployment contract, not a live deployment. See [M0 evidence](docs/m0-verification.md), [M1 playtest gate](docs/m1-verification.md), [M2 evidence](docs/m2-verification.md), [M3 implementation and verification](docs/m3-verification.md), and [M4 verification](docs/m4-verification.md). The newer living-ecosystem and botanical field-journal/art integration is an additional implementation pass, **pending main integrated validation and native visual review**. Historical M4 results do not certify this new pass. No version or save-schema bump is part of the journal work. ### Woodland traveler appearance Use `/character`, or **Character appearance** in the inventory, to choose muted woodland clothing, skin, face, hair and details with three equal-mechanics body profiles. Four tabs and a rotatable 3D model preview keep changes in a private draft: **Save / Apply** persists them; **Cancel** keeps the original. Joining restores saved appearance without prompting. Corrupt appearance data is retained with a safe-default warning, never a kick. Existing location forms retain priority. See [character creator and recovery contract](docs/character-creator.md). Focused offline tests do not certify native visuals or client interaction. ### Offline species reader Use `/inspect` while pointing at a known plant/tree within six blocks, or `/inspect oak` / `/inspect Quercus robur` for an exact catalogue ID or Latin name. Field notes include **Inspect target**; `/botany` offers a **Species article** selector for each ten-row page. Harvesting and building controls are unchanged. The **Article** tab shows available cached plaintext Wikipedia introductions, labelled **Wikipedia excerpt (offline)**, with copyable canonical/revision/history URLs, contributor attribution and **CC BY-SA 4.0** licensing. Missing snapshots have explicit availability notes, not counterfeit articles; cache expansion is a separate task. **Current effects** distinguishes simulated game policy from descriptive natural history. This is not a full wiki, embedded browser, or real-world identification/foraging guide. Nothing is fetched or automatically opened; inspection writes no world or player data. Text is escaped and bounded to 8,000 characters, 4,000 per page. See [source coverage, licenses and reader contract](docs/species-references.md). Focused isolated tests cover the reader; native visual/client integration remains pending. Full-engine tests were not run for this change. The [landscape/content expansion](docs/content-expansion.md) now wires ten communities, thirteen tree species, a 100-species botanical catalogue and ordered geology into the seasonal ecosystem. Its eight ecological groups are deliberately uneven: 13 trees, 14 shrubs, 10 grasses, 22 herbs, 11 ferns/mosses, 10 fungi, 10 aquatic taxa and 10 lichens. The additions reflect ecological roles, not a ten-per-category quota. The trees are oak, birch, pine, willow, alder, beech, aspen, rowan, hazel, spruce, crab apple, wild cherry and field maple. All thirteen logs fuel hearths for 180 seconds and craft four matching planks; buildings/planks are not direct fuel. Copper charges/ingots/picks, copper smelting, coal fuel and a three-quartz alternate window recipe are integrated; native validation of the latest botanical pass remains pending. New launcher worlds use a broad-relief v7 preset with a ±4096 bound; **existing saved mapgen/seed/bounds are not retuned**. Old chunks are never regenerated; future unexplored chunks can change and leave seams. Focused registration/tooling tests do not certify new-seed safety or engine visuals. **Human acceptance remains open across M1–M4.** The actual M1 course has not been evidenced as traversed/repeated by several testers, and there are no measured FPS, frame-time, multiplayer, latency or hardware-envelope results. M2 implementation is proceeding under the user's explicit direction; this does not waive those gates or claim the M2 unfamiliar-tester, M3 two-player cabin, or M4 week-long group gate has passed. - [Roadmap: M0–M6 and M1 acceptance](docs/roadmap.md) - [Launch feature checklist: F01–F19](docs/launch-features.md) - [M0 decisions, provisional budgets, risks and evidence](docs/m0-decisions.md) - [Architecture and save/module contracts](docs/architecture.md) The exact development contract is **Luanti 5.18.0, game 0.5.0-m4, save schema 1**. See [release.json](release.json) and [package.json](package.json). Native-first: Windows is natively verified on the existing development host. Linux/macOS path selection has unit coverage only; native execution is unverified on both. No clean machine was tested. A browser client is **not promised launch-ready**. There is no committed public launch date. ## Run and test locally Requires Node.js 22+ (built-in modules only), a separately installed stock Luanti **5.18.0**, and a trusted writable runtime directory. The launcher checks the engine's reported version; it does not download the engine or authenticate it. On non-Windows systems set `HEARTH_ENGINE` to the absolute executable path. On Windows it defaults to the existing Luanti 5.18.0 win64 runtime's bin directory; setting `HEARTH_ENGINE` explicitly also works there. A headless-only server binary can run checks but cannot provide graphical play. From this repository, using Node on PATH: ```text node scripts/run.mjs check node scripts/run.mjs smoke node scripts/run.mjs test node scripts/run.mjs test:seeds npm test node scripts/run.mjs play node scripts/run.mjs test:course node scripts/run.mjs course ``` - **check:** disposable headless world, game startup and compilation of the Lua sources/specs. Compilation alone does not execute the unit assertions. - **smoke:** real-engine registry/crafting/terrain/resource/enclosure checks and isolated execution of the discovered Lua unit specs. Mocked globals do not replace globals in the live game. - **test:** check plus smoke; with `HEARTH_LUA` set to an absolute Lua 5.1+/LuaJIT executable, also runs the standalone Lua harnesses. No separate Lua is otherwise required. Do not rely on historical test counts: record named suites/results. - **test:seeds:** fresh real-engine worlds for eight fixed map seeds; checks safe arrival surfaces and required starting resources without touching the play world. - **M3:** structure removal is refused if it would strand connected construction. `/claim share` manages household access and `/claim show` briefly marks boundaries. See [M3 rules and remaining gates](docs/m3-verification.md). - **npm test:** Node tooling tests only, not the engine suite. The `test:engine` package script runs the engine suite; `test:recovery` is a separate, private offline recovery exercise described below. - **play:** persistent local singleplayer world. Uses normal engine controls. The expanded v7 preset applies only at creation. Use a separate empty `HEARTH_HOME` to try it without migrating/deleting the current world. See [new-world settings and existing-world transitions](docs/content-expansion.md#broad-relief-v7-preset-new-worlds-only). - **course:** a fresh disposable summer course; it never opens or changes worlds/last_hearth. Wait for arrival, then run `/course` to generate the route and receive a temporary kit. The course route covers half-steps, a one-wide doorway, water, two controlled falls, gathering, construction and an arena. Run `/course report` for checkpoint progress and server-step/Lua-callback samples—**not** client FPS. `/spar` opts into a bounded moving sparring opponent; `/practice` uses the stationary reference target. PvP remains disabled. - **test:course:** native headless enrollment/staging and no-consent preflight. It intentionally does not generate terrain, forge a player, or claim traversal. Engine checks require zero exit status **and** a unique per-run success marker. Their outer deadline is 90 seconds; standalone Lua invocations are bounded to 30 seconds. Graphical play has an eight-hour safety bound. Quit normally to save; interrupts/deadlines kill the child and are not graceful-save guarantees. Session configuration and logs are temporary and removed at session cleanup; retain sanitized evidence separately when validating. See [scripts/run.mjs](scripts/run.mjs). ## Data locations and isolation `HEARTH_HOME` overrides the runtime root and must be absolute. Without it: | Platform | Default root (literal environment notation) | | --- | --- | | Windows | %LOCALAPPDATA%/last-hearth-runtime | | Linux | $XDG_DATA_HOME/last-hearth-runtime, or $HOME/.local/share/last-hearth-runtime | | macOS (runner unverified) | $HOME/Library/Application Support/last-hearth-runtime | The **old Windows runtime and world location remain unchanged**. Within the root, the persistent world is under worlds/last_hearth and retained snapshots are under backups. Each invocation packages a generated game into a temporary session's games directory and sets `LUANTI_GAME_PATH`; it does **not** overwrite the engine installation or its games. See [scripts/launcher.mjs](scripts/launcher.mjs). Use a **different absolute `HEARTH_HOME` for staging**, with an explicit `HEARTH_ENGINE` when the engine lives outside it. Changing the root does not copy or migrate the old world. Production must use a separate external deployment, storage and configuration, outside this checkout, packages and webroots. The local launcher is not a dedicated-server deployment tool. It binds loopback, disables announcements, PvP and creative mode, and keeps mod security enabled. ## Package, back up and restore Examples below use absolute Windows destinations; substitute your own trusted paths (POSIX absolute paths on Linux/macOS). **Parents must already exist and each destination must be new. No command overwrites an existing destination.** ```text node scripts/run.mjs package C:/HearthArtifacts/game-0.1.0-m0 node scripts/run.mjs verify C:/HearthArtifacts/game-0.1.0-m0 node scripts/run.mjs backup C:/HearthPrivate/worlds/last_hearth C:/HearthPrivate/backups/manual-001 --offline node scripts/run.mjs restore C:/HearthPrivate/backups/manual-001 C:/HearthPrivate/worlds/restored-001 --offline ``` Without a destination, `package` uses the dist/last_hearth directory, still requiring it not to exist. Packaging generates assets and includes release, configuration, license, mod and JSON fixture inputs plus an exact SHA-256 inventory. It is an engine-independent **game directory**, not an engine/client bundle or installer; it excludes saves, tooling and the full test suite. `verify` verifies a **game package**, not a world backup. Restore verifies a backup before and after copying; [scripts/backup.mjs](scripts/backup.mjs) also exports `verifyBackup()` for programmatic verification. **Before backup, restore, recovery, or launching an existing managed world, stop ALL engines that could access it, including external engines on other machines.** `--offline` is the operator's confirmation, not a mechanism that stops them. Launcher/world locks and SQLite sidecar checks cannot prove remote idleness. Do not delete locks/sidecars merely to bypass a refusal. Clear a stale launcher lock only after confirming every relevant process has stopped. The launcher takes a full retained prelaunch snapshot of an existing managed world; it has no automatic retention deletion. Backups include private map, player, authentication, inventory and mod data: use access-controlled, preferably encrypted storage, never a public artifact directory. Permissions remain the operator's responsibility; portable file modes do not provision Windows ACLs. SHA-256 detects **corruption, not authenticity**; it is not signing or encryption. Preserve the original snapshot and restore to a new directory before considering any operator-controlled cutover. See [scripts/package.mjs](scripts/package.mjs), [scripts/files.mjs](scripts/files.mjs) and [scripts/backup.mjs](scripts/backup.mjs). ### Private old-save recovery evidence The `test:recovery` package script runs [scripts/recovery.mjs](scripts/recovery.mjs). Stop all engines and other Hearth tooling first. `HEARTH_RECOVERY_SOURCE` selects an absolute existing SQLite world; otherwise it selects the legacy Windows world under `LOCALAPPDATA`. **`HEARTH_HOME` changes recovery's working/backup root, not that default source.** Non-Windows operators normally need an explicit source. Recovery retains an untouched snapshot, verifies byte-exact restores, boots only instrumented disposable copies twice, and checks migration/restart behavior. Temporary copies omit old worldmods and use synthetic staging coordinates. A sanitized report is retained beside, not inside, the immutable snapshot. The original world is never launched. The retained successful report records 79 seed and 81 restart assertions, two byte-exact restores, two engine shutdowns and an unchanged source. It tested an earlier package, not the final export; its source had zero claims, so claim-owner/protection coverage uses regression fixtures and mocks, not preservation of existing source claims. This is not a real-client recovery playtest or public-service disaster recovery certification. See the [recovery evidence and qualifications](docs/m0-verification.md#retained-recovery-evidence). ## First play and current rules - **I** opens crafting and field notes; `/guide` reopens help. - **Ecosystem survey** in the field journal, or `/ecosystem`, observes one small loaded habitat patch and reports the actual global active counts for all 23 animal identities. It does not grow plants, spawn animals, force-load terrain or change world state. - **Botanical guide** in the journal/survey, or `/botany [search]`, browses the actual catalogue, ten species per page. Search is literal, escaped and limited to 48 characters; it includes common/scientific names, category, habitat, seasons and ecological roles. Toxicity flags are game labels, **not real-world food-safety advice**; unflagged does not mean edible. Missing catalogue APIs display an unavailable message. See the [100-taxon category list and role limits](docs/botany.md). - **Fauna guide** in the journal/botanical guide/survey, or `/fauna [search]`, browses all 23 animal identities, source URLs and lifecycle status. Field-level source-reported ranges, unverified fallback policies and **UNKNOWN** are distinct; identity citations do not establish numeric timing. The existing plant article reader is unchanged. No runtime network fetch or ecological mutation occurs. - Gather flint, sticks, berries and reeds. Make an axe to harvest timber; build supported walls/roof and fuel a stone hearth with sticks/logs. - Fallen logs are ordinary sideways full cubes. An axe yields **one canonical log**, not two sticks gathered by hand. Existing full-block trees/deadwood are retained; this journal/process pass does not replace their geometry. - Use a cup on water, then use untreated water on a fueled hearth before drinking. - **Aux1** (normally E) plus forward sprints; release after exhaustion and recover stamina before sprinting again. FOV is unchanged by default; `/comfort fov 75` applies a session-only static preference. - `/practice` places a stationary target. In local play or privileged staging, `/spar` opts into one moving opponent. Strike to begin a round; step back/aside to evade or face the attacker and hold right-click with a spear to brace. - The controlled route exists only in the disposable launcher-created course world. `/course retry` restarts its run. A settings flag alone cannot authorize course generation in a survival/production world. - `/claim` protects one 25 × 25 area, extending ±24 vertically. `/claim share` grants resident (build/use) or storekeeper (storage-only) rights; `/claim unshare`, `/claim list`, `/claim show`, and `/claim remove` manage membership and bounds. Death preserves inventory, food, water and wetness; respawn only limits stamina and warmth before safe home/fallback arrival. A home must be inside the player's own claim and is revalidated at use. Offline player needs pause; hearth fuel and queued cooking/boiling use real-time deadlines, while completed output waits for collection. Food cooks in six seconds, water boils in four, and fuel cost is reserved when a job starts. A craftable bedroll grants a small warmth recovery after five uninterrupted sheltered seconds; it does not skip world time. M4 adds seasonal crops and preservation; general food spoilage remains disabled. PvP is disabled. See the [M2 rules and limits](docs/m2-verification.md) and [M4 offline contract](docs/m4-verification.md). ### A living landscape, a botanical field journal The [living ecosystem model](docs/ecosystems.md) is an original implementation inspired by Dynamic Life's ecological ideas, not copied datapack code or assets. Light, shade, moisture and competition shape meadow grass, wildflowers, ferns and slow tree succession. Litter, fungi and dung recycle finite nutrients; grazing debits finite forage and wildlife links habitat to the food web. Calendar organism ages include the full unloaded interval; ecological work remains bounded and loaded-only, never replaying an offline backlog. Named trees use species-profile calendar endpoints, typically years to decades; conservative fallback thresholds are explicitly not researched timings. Fungi do not accelerate tree maturation. Claims, placed plants, crops and construction are excluded from autonomous changes; existing crop and planted-sapling clocks keep their separate rules. Survey counts cover a fixed 5×5×5 patch at your feet, not the whole landscape; unloaded cells are explicitly unknown. Wildlife totals describe all currently active animals, not a local census or saved population. There is no compulsory ecological quest. Content installs the pure lifecycle namespace before biological factories, and publishes wildlife's exact returned fauna catalogue. Human botanical harvest and animal frugivory share `botany_ready_at`: after a successful crop debit it rests one mean real year (**365.2425 days**), then requires its fruit season, not a 24-hour refill. One live pollination credit can add only **one** berry to the existing two-berry crop; empty or cooling bushes never manufacture fruit. Human inventory rejection restores fruit and credit; partial delivery spends both once, and reservations precede inventory callbacks to prevent reentrant duplication. All 23 animal identities register fixed, originally authored skeletal B3D assets with 100 frames and five clips (idle, locomotion, feeding, flight/swim and rest) at 24 fps. Registration/animation contracts are not native visual acceptance. Established recruitment is immigration, **not an adult birth**. Every incomplete profile disables reproduction by default; pairing, pregnancy, nesting, egg/larval development, caste/colony reproduction and delayed implantation remain future work. Unknown lives and source longevity averages never imply automatic death. No offline meals, dung, births, forced map loading or missed-season replay occur. See [calendar evidence and transaction contract](docs/lifecycles.md), [fauna behavior and limitations](docs/fauna.md) and [ecosystem policies](docs/ecosystems.md). This integration was focused-test-only: no engine launch, world change, version bump, wiki-cache edit or claim of complete true-life biology. The [moonlit botanical art direction](docs/art-direction.md) pairs original pixel materials with the eom.dev Mocha interface: base `#1e1e2e`, mantle `#181825`, raised `#292940`, border `#3c3d56`, pale `#cdd6f4` text and `#a6adc8` annotations. Mauve `#cba6f7`, teal `#94e2d5` and yellow `#f9e2af` are restrained navigation, botanical and warmth accents. The eight-page guide, botanical browser, recipes, satchel/crafting and location forms share controls, dark fields, list colors, tooltips and pressed-sprig dividers. HUD needs use labeled percentages and colored tracks on a dark panel rather than ASCII bars. The ten-slot hotbar repeats the authored single-slot texture and uses the authored selection outline; standard crosshair asset integration belongs to the generated-art pass. Client scaling, contrast, long text and artwork still need native visual acceptance; automated checks are not a claim of polished gameplay. ### Location and privacy Optionally set **both** `HEARTH_LATITUDE` and `HEARTH_LONGITUDE` (−90…90 and −180…180). Local worlds can instead use the prompt or `/location`; an unchosen local world shows a disclosed neutral equatorial preview. There is no IP lookup or external location service. Configured/stored coordinates are private data. Dedicated servers require explicit administrator-selected `hearth_latitude` and `hearth_longitude`, even with a stored location. The community location is **not chosen**: the user/operator must approve it before M2 climate staging. The M0 45°N, 0°E synthetic fixture is **not a production location**. The host UTC clock drives a synthetic seasonal model and an approximate fixed-orbit sky, not live weather. Labels are UTC and local solar time, not civil timezone/DST. `HEARTH_FIXTURE` selects `first-session`, `summer`, or `winter` for isolated local or staging work. First-session fixes seed 731104, not the date/location; summer and winter fix UTC/weather/45°N, 0°E. Use a separate staging root/world; never apply fixtures to valued play data. Production rejects preview/test settings. See [tests/fixtures/scenarios.json](tests/fixtures/scenarios.json) and [settingtypes.txt](settingtypes.txt). ## Known limits, not fixes M1 code now implements smoothed stamina/sprint transitions, collision/course test geometry, animated held tools, material feedback and moving sparring. Manual feel/collision evaluation, voluntary repeat testing and performance/network measurements remain open; see [M1 verification](docs/m1-verification.md). This is not a custom engine/client controller; the newer bounded wildlife work is documented separately above. Stock Luanti remains the M1 baseline unless human measurements reveal a specific blocking engine limitation. M2 replaced the old below-world teleport with safe bounded recovery. M3 now provides bounded room/vent-aware comfort, a small building palette, refuse-unsafe-removal, shared resident/storekeeper roles and protected storage. This is not a full structural physics engine or persistent smoke simulation; two-player grief/comfort acceptance is still open. Generated art remains procedural prototype art. Public operations, moderation, identity and disaster-recovery acceptance remain later gates; no account, browser parity or multiplayer-hardening approval is implied.