35 Commits
Author SHA1 Message Date
Samuel LisonandClaude Opus 4.8 3a0206e566 chore(release): v0.10.0
Promote CHANGELOG Unreleased → 0.10.0 (the schema-driven Build page for world
objects, #11) and bump wally.toml + SurvivorCore.VERSION.

Demo: new demo/server/Stage.luau — one switch for what the demo places in the
world (gather field + quest post, mobs, starting inventory, hand-test props).
The test-station prop rows now default OFF: they're scaffolding for working ON
the engine and crowded the spawn area for everyone else.

Collateral: the Build demo video on the docs Demos line and as an 8th site
video tile; the landing page's Studio card now tells the Build story; version
surfaces bumped across site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 19:29:49 +10:00
Samuel LisonandClaude Opus 4.8 29bd20a93f feat(builder): schema-driven Build page for world objects (#11)
Select a Part or Model in Studio, answer "what is this object?", fill a form —
it becomes a gatherable node, a mob or a quest giver. Closes the gap between
authoring a def and setting up a world object, which until now meant knowing to
tag a part and hand-typing PascalCase attributes in the property panel.

Engine — components can declare an attribute SCHEMA:
- src/components/Schema.luau (new): AttributeSpec/Display/ComponentSchema types,
  normalize/defaults/get/list, and the schemas for Gatherable, Mob, QuestGiver.
  Dependency-free ON PURPOSE: the plugin requires it live at edit time, and the
  component modules themselves can't be required there (Harvesting asserts
  IsServer; Remotes creates instances in ReplicatedStorage).
- Components.define now accepts EITHER the legacy `attr = default` map or a
  schema array, normalizing both to one ordered spec list; bind() reads the
  derived default map, so binding is byte-identical. Legacy maps are sorted, as
  `pairs` order is arbitrary and would make a UI jitter. New getSchema/
  listSchemas. The three shipped components pull name/tag/display/attributes
  from the schema; their onSetup bodies are untouched (defaults verified
  identical, all 23 attributes).

Plugin — the Build page:
- Field.luau (new): coerce/format/equalsDefault, lifted from ConfigAdmin (which
  now delegates), shared by every schema-driven editor.
- FieldRow.luau (new): the shared [○/●] label … control + help row, including a
  ⌄ picker that cycles authored ids for fields declaring `ref`.
- BuildAdmin.luau (new): live schema read with three distinct empty states,
  selection/eligibility/identify, deltas-only attribute writes, applyType
  (tag + clear any other component) and clear.
- BuildAdminUi.luau (new): chooser cards, grouped form, multi-select apply,
  stale-bind-marker warning, SelectionChanged-driven refresh.
- init.server.luau: record()-wrapped buildActions + the page.

Docs: docs/admin-plugin.md Build section + a 60-second walkthrough,
docs/extending.md schema guide, a CONTRIBUTING rule that new creator components
declare one, CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:14:52 +10:00
Samuel LisonandClaude Opus 4.8 f4fad6fc83 chore(release): v0.9.0
Promote CHANGELOG Unreleased → 0.9.0 (player trading #15, the player interact
window, and the bow rate-limit security fix). Bump wally.toml +
SurvivorCore.VERSION to 0.9.0.

Collateral: player-trading demo video as a 7th site video tile and a Demo line
in docs/trading.md + docs/interact.md; a full-width "Player trading" feature
card on the landing page; trading.md + interact.md added to the README doc
index; version surfaces bumped across site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:00:36 +10:00
Samuel LisonandClaude Opus 4.8 7a5aaac0df fix(combat): rate-limit bow shots + validate bow inputs
The bow release handler enforced no cooldown — the only client-driven action
in the engine without one (melee, harvesting and item use all rate-limit). Each
release also costs up to MaxRange/StepSize server raycasts to simulate the arc,
so the gate now runs BEFORE the arrow is spent and before the simulation.

- Combat.Bow.Cooldown (0.35s) added to CombatConfig + the EngineConfig schema,
  so it's tunable no-code in SurvivorCore Studio.
- onBowRelease honours def.weaponCooldown first, falling back to Bow.Cooldown.
  weaponCooldown was previously read only by the melee path, even though the
  authoring form offers it for every weapon — a bow cooldown was silently
  ignored. Its plugin label is now "Cooldown (s)" noting it covers both.
- A release with no matching draw is rejected (a real client fires BowDraw on
  press, BowRelease on release).
- BowDraw validates the sender is alive and holding a bow; it previously
  accepted anything from anyone.
- Aim points are checked for finiteness: a non-finite Vector3 defeats magnitude
  comparisons and would reach the raycast after the arrow was already spent.
- lastShot is cleared in PlayerRemoving alongside lastSwing/drawStart.

Affects v0.8.0 and earlier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 16:56:54 +10:00
Samuel LisonandClaude Opus 4.8 96bafb8345 fix(trade): self-contained + draggable trade window
Two UX bugs found while recording:

1. The trade window relied on the SEPARATE inventory menu for staging, and
   clicking the menu's backdrop closed it with no obvious way to reopen —
   leaving the trade unusable. The window now lists your carried stacks
   INSIDE it (read from the replicated inventory attributes): click a row to
   offer one, "All" for the whole stack. Dragging from the inventory grid
   still works when that menu happens to be open. Removed the auto-open of
   the inventory panel that created the trap.

2. The window couldn't be moved. Its header is now a drag handle (mouse +
   touch), so it can be pulled out of the way.

Also: the in-window backpack live-refreshes on inventory attribute changes
(coalesced per frame) so a mid-trade pickup can't leave it stale. Panel grown
to 420x476 for the added section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 15:03:24 +10:00
Samuel LisonandClaude Opus 4.8 10891b1fcd feat(interact): walk-up player interact window; fix self-prompt (#15)
Replaces the buggy per-character Trade ProximityPrompt — which rendered over
your OWN head (no per-viewer exclusion) — with a TCE-ported interact window.

Walk up to another player → an "[E] Interact" badge floats over THEIR head →
press E / tap → a window shows their name + survival stats and an action list.
Targeting is a client-side nearest-OTHER-player scan (self skipped in the loop,
with hysteresis to stop flicker), so the affordance can never point at you —
the reported bug is fixed by construction.

Extensible: SurvivorCore.Interact.addAction{ id, label, order?, enabled?,
onActivate } — Trade is registered as the first built-in action and just fires
the existing (server-validated) TradeRequest remote, so the invite/Accept flow
is unchanged. Cursor is freed while the window is open; the window auto-closes
on walk-away / target-leaves / death / trade-start.

- src/client/PlayerInteract.luau (new): scan + billboard + window + action registry
- src/systems/Trade.luau: delete the per-character prompt block (keep Died abort)
- src/init.luau: boot PlayerInteract, expose SurvivorCore.Interact
- src/shared/UiConfig.luau: UI.Keybinds.Interact = "E"
- docs/interact.md (new), docs/trading.md, CHANGELOG (Unreleased)

Ported from The Counter Earth's PlayerInspectService/InspectController.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:56:10 +10:00
Samuel LisonandClaude Opus 4.8 177a4118fe feat(trade): secure player-to-player trading (#15)
A new server-authoritative, dupe-proof trade system. Walk up to another player,
trigger the "Trade" prompt; they Accept/Decline; both stage loose backpack
stacks (drag from the inventory grid, with −/+ qty steppers) and must Confirm
before anything moves.

Anti-dupe by construction: staging is by-reference (items never leave the owner
until commit), and the commit is one synchronous, no-yield critical section —
re-validate holds → pre-flight both receivers have room (new Inventory.canAccept)
→ remove both → grant with addUpTo → refund any residue. Item count is conserved
on every branch (verified: 200k-iteration conservation + fit-oracle fuzz).

Auto-cancels on death / leave / out-of-range (MaxDistance) / request timeout; a
staging change resets both confirms. New Trade server system + TradeUi client
window, the "Trading" Config section (tunable in SurvivorCore Studio), hooks
trade:started / trade:completed, and a trades_total progression counter. v1 is
backpack stacks only (worn gear reserved behind AllowEquippedItems).

- src/systems/Trade.luau, src/client/TradeUi.luau, src/shared/TradingConfig.luau (new)
- src/systems/Inventory.luau: exported canAccept (weight+slot fit oracle)
- src/shared/EngineConfig.luau: Trading section; src/init.luau boot wiring
- docs/trading.md, README, CHANGELOG (Unreleased), Hooks catalogue, extending.md
- demo/server/TradeTestStation.server.luau: /tradetest 2-player conservation harness

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:19:06 +10:00
Samuel LisonandClaude Opus 4.8 b15005c09a chore(release): v0.8.0
Promote CHANGELOG Unreleased → 0.8.0 (SurvivorCore Studio, Engine Config #21,
content overrides #40). Bump wally.toml + SurvivorCore.VERSION to 0.8.0.

Collateral: admin-panel demo video tile on the landing site + docs/admin-plugin
Demos line; refresh the admin feature card + value-prop to name SurvivorCore
Studio / Engine Config / content overrides; bump version surfaces across
site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:55:56 +10:00
Samuel LisonandClaude Opus 4.8 3349738779 fix: address adversarial-review findings across engine + plugin
Engine: quest overrides with objective*/reward* fields on nested code quests
now WARN at boot (they merge nothing — QuestData prefers nested tables);
EngineConfig + ConfigAdmin reject non-finite numbers (inf/nan).

Plugin: Config group panels auto-size (fixed-height math clipped the last row
of big groups — Theme group lost its Bold font row); Stats panels get the gap
math right; the Engine Config explainer page now REBUILDS the window when the
engine appears (the old hint was impossible — pages were assembled once at
plugin load); create() refuses ids that already have an override (mirror
guard); failed Create/Override reasons render under the create row; rejected
config edits report in the footer; explicit navigation cancels a pending
debounced search jump; the mount-time page restore no longer clobbers the
saved last-page setting during an engine-less session; undo/redo refresh
skips while typing in one of the plugin's own text boxes; search results past
the 50-cap no longer render empty category headers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:39:56 +10:00
Samuel LisonandClaude Opus 4.8 40bf167318 docs: SurvivorCore Studio + Engine Config + overrides docs, CHANGELOG Unreleased
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:16:11 +10:00
Samuel LisonandClaude Opus 4.8 8bd929a1d4 docs: add v0.7.0 hunting/loot-bags demo video + site video grid tile
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:52:19 +10:00
Samuel LisonandClaude Opus 4.8 44c0f8e25c fix: beacon follows the owner's newest bag; older bags never clear it
Dying again mid corpse-run drops a second bag (old + new coexist in the world,
each on its own 5-minute timer) and re-points the owner's beacon at the new
one. Previously the OLDER bag's later despawn/looting fired the unscoped
beacon-clear and wiped the beam pointing at the newer bag. LootBags now tracks
each owner's latest bag and only its destruction clears the beacon.

docs/loot-bags.md: documented the multi-bag + beacon-follows-newest behavior.

Live-verified: two coexisting bags, beacon on the newest; looting the OLD bag
left the beacon untouched; looting the NEW bag cleared it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:38:26 +10:00
Samuel LisonandClaude Opus 4.8 9951e09a3f feat: hunting/butchering + death loot bags (#13, #19)
Hunting & butchering (#13): mob defs gain flat carcass fields (carcassItem/Hp/
Tool/YieldMin/Max/Seconds); a slain mob leaves a butcherable CARCASS that is a
tagged Gatherable — the whole harvesting pipeline (tool gate, per-hit yields,
HP bar, gather:* hooks, progression counters) is reused as the butcher flow.
Carcass looks come from SurvivorCoreContent.Carcasses.<mobType>; reactions key
on "<mobType>_carcass"; fields editable in the admin Mobs editor. Gatherable
gains generic PromptText/PromptObject attributes.

Death loot bags (#19, TCE port): dying drops inventory AND worn equipment
(config-toggleable) into an anchored ground-clamped bag — IntValue contents,
instant-loot prompt for anyone, floating countdown, owner-only beacon, death
toast, LifetimeSeconds despawn. Pickup is loss-proof: equipment restores to
empty slots first (satchel re-grows capacity before stacks), the rest grants
up-to-fit and the remainder stays bagged. New player:died lifecycle → deaths
counters via Progression; lootbag:dropped/collected hooks; TCE respawn camera
fix. New Inventory APIs: getEquipment, clearAll (capacity-safe order), addUpTo,
restoreEquip.

Fixed: ToolEquip forces CanBeDropped=false on cloned creator templates.

Demo: stone_knife + raw_meat (risky raw: Hunger -25, Poison +8), boar carcass,
multi-objective hunt_boar quest, hunter/butcher/hard_way achievements. Docs:
mobs.md butchering section + loot-bags.md; CHANGELOG; site card copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:05:22 +10:00
Samuel LisonandClaude Opus 4.8 ce676fa4d5 docs: add v0.6.0 quests/achievements demo video + refresh site video grid
Wire the demo video (makertube uSGJ2MHEFjSSKxMiJBJ6Y5) into quests.md,
achievements.md, content-authoring.md and admin-plugin.md, and feature it in
the landing page's video grid (replacing the oldest embed; that video stays
linked from docs/inventory.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:37:58 +10:00
Samuel LisonandClaude Opus 4.8 9caa888369 feat: quests + achievements — the goals & progression release (#10)
Quests (#10): a Quests registry + server runtime — objectives (gather/craft/
kill/use × count, blank target = any) and rewards, autoStart + requires chains
(completing a prerequisite auto-starts dependents), optional turn-in at a
tagged QuestGiver (component + prompt). Rewards are never lost: a full
inventory parks the quest as ready and the grant retries on inventory change.
Quests menu tab (L) with per-objective progress bars; QuestLog JSON attribute
replicates state; quest:started/progress/completed/blocked via Hooks + bus.

Achievements: an always-on runtime for the existing registry, ported
architecturally from TCE. A shared Progression layer translates bus events
into auto-derived counters (gathers_reed, crafts_total, kills_husk, …) so a
def is just { key, name, counter, threshold } — flat in code and no-code.
Unlock-once + toast + Achievements tab (J) with progress bars.

Toasts: themed top-right notification queue (Notify remote + Toasts.show).

No-code: admin plugin gains Quests (single-objective + "+ Quest giver" drop)
and Achievements (counter/threshold) editors; the engine loads both from
SurvivorCoreContent. Demo: a 3-quest chain + 4 achievements + a giver post.

Fixed: registerPanel now ADOPTS a template-scaffolded tab (hides the
placeholder, builds into the authored frame) instead of silently no-opping —
this replaces the Quests/Achievements "coming soon" placeholders.

EventBridge parity: gather:*, craft:* and item:use now also cross the bus.
Changed: rojo 7.6.1 → 7.7.0 (rokit pin; CI follows; gate verified).

Docs: quests.md + achievements.md (new), content-authoring/admin-plugin/
extending/README updated, CHANGELOG Unreleased, site feature card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:26:19 +10:00
Samuel LisonandClaude Opus 4.8 2c68bcc6b0 feat: mob & AI engine + combat (melee + ranged) (#17, #12, #14)
Mob & AI engine (#17): a `Mob` component + a `Mobs` FSM runtime
(idle/wander/chase/attack/flee/leash/death), faction-driven profiles
(hostile/passive/neutral), Humanoid-based mobs so combat/health/death share one
path, per-mob-type reactions, and a `Mobs` Config section.

Combat (#12, #14): server-authoritative melee + ranged reusing the v0.4.0 swing
pipeline; the `combat:hit`/`combat:kill` kill-event schema designed once. Bows use
a TCE-style aim (hold RMB to aim with an over-the-shoulder camera + crosshair and
charge ring, hold LMB to draw, release to fire); the server simulates the gravity
arc and sends the path so the client flies a cosmetic arrow along the real curve.
Arrows are their own configurable ammo item (weight/damage/curve/range/speed).

No-code: admin plugin gains Mob, Weapon and Arrow editors (+ "Add to World" /
"Tool model" drops); the engine loads Weapons/Arrows/Mobs from SurvivorCoreContent.

Fix: scope the orphan hotbar-pin sweep to the removed/consumed item, so consuming
one item never clears an unrelated hotbar-pinned weapon.

Docs: combat.md + mobs.md (with demo video); CHANGELOG Unreleased entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 20:18:51 +10:00
Samuel LisonandClaude Opus 4.8 8606564b83 docs: link v0.4.0 demo videos (gathering/crafting + no-code content)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 16:12:21 +10:00
Samuel LisonandClaude Opus 4.8 d679850f90 feat: tool-swing harvesting, hand crafting & no-code content (#1, #4, #11)
Closes the gather → craft loop and lays the no-code content layer.

- Tool-swing harvesting (#1): equip a hotbar tool (a real Tool via the new
  ToolEquip bridge), click a node, server-validated hit (range / line-of-sight
  / equipped tool / cooldown) granting a per-hit random yield, blocking the hit
  when the inventory is full. Bare-hand hold-E kept. The engine's first
  client-input → RemoteEvent → server-validation pipeline (combat reuses it).
  A floating HP bar shows a node's remaining hits.
- Hand crafting (#4): server-authoritative consume → produce with a
  complexity-scaled craft channel + a progress bar above the crafter; a
  Crafting tab lists hand recipes and gates each on what you carry.
- No-code content (#11, Builder first slice): a Resources registry + a
  content-from-instances loader (Registry.loadFromFolder reads a
  SurvivorCoreContent folder at start), Gatherable binds to a named Resource,
  and a per-resource-type reaction API (reed sways, tree fells + leaves a
  stump). The admin plugin becomes one widget with Stats + Content tabs to
  create/edit items + gatherables, including "Add to World".

New hooks: gather:blocked, craft:start / craft:end / craft:blocked. Docs +
CHANGELOG. Engine stays content-free; the demo supplies the sample content.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:43:34 +10:00
Samuel LisonandClaude Opus 4.8 1b5ef088b3 fix(hud): keep a single HUD, preferring the authored one over the fallback
Both the authored template and the built-in fallback name their ScreenGui
"SurvivalHud", and the fallback fires on a 1s timer if no bars have bound
yet. The dedupe ran only once at startup, so a fallback that raced the
template (more likely now startClient does more before the template copies
in) left two HUDs on screen — a restart usually shuffled the timing enough
to hide it, until it didn't.

Tag the fallback, make the dedupe continuous (re-runs whenever another HUD
appears) and always prefer the authored HUD, and don't build the fallback
when a HUD ScreenGui already exists. Also link the inventory/hotbar demo
video in docs/inventory.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:23:17 +10:00
Samuel LisonandClaude Opus 4.8 5ab855fa1b feat(ui): inventory, hotbar & tabbed menu UI (#7, #9, #3)
Server-authoritative slots+weight inventory, a 9-slot hotbar (keys 1-9),
equipment slots, and a restyleable tabbed menu (functional Inventory +
Character Sheet; Codex/Achievements/Quests scaffolded), built the engine's
way: authored ScreenGui templates + attribute-discovering binders, with a
zero-setup fallback.

- Drag-and-drop is driven by a per-frame cursor poll (immune to the grid
  ScrollingFrame that swallows InputChanged) with GUI-inset-corrected drop
  hit-testing so releases land on the actual slot.
- Menu key defaults to Tab; the engine frees it by disabling the CoreGui
  player roster (ReclaimCoreKeys) and moves the chat to bottom-left so it
  clears the top-left HUD (Chat config). Toggle ignores focused TextBoxes.
- Consumables apply onConsume via the stat-effects layer + fire item:use;
  gather yields flow into the inventory; pickups auto-pin to the hotbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:06:54 +10:00
Samuel LisonandClaude Opus 4.8 95d5d0b819 feat(survival): bleeding out = instant death; attach demo video to docs
- Blood reaching 0 now kills INSTANTLY (humanoid.Health = 0), not a per-second
  drain. Removed the BledOut drain rate from the Consequences config.
- Add the HUD/stats/plugin demo video to the survival-stats + admin-plugin docs.

Gate green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:57:11 +10:00
Samuel LisonandClaude Opus 4.8 3d8fd24cd9 feat(survival): realistic default rates; poison hurts only at 100%; hide Roblox health GUI
Tuning + fixes from playtest feedback:
- Poison drains health ONLY at 100% (was scaled from any level) — no more health
  ticking down from leftover/partial poison.
- Hide Roblox's built-in top-right health GUI (CoreGuiType.Health); the engine ships
  its own Health bar. (Retries a few frames since CoreGui can refuse it at session start.)
- Realistic default drift (all in config): Hunger/Thirst ~8h to max, Fatigue ~24h.
  Starving/dehydrated each take ~8h to kill (stack → ~4h when both). Default bleed/poison
  SOURCE rates ~1h (Consequences.Affliction) for real gameplay.
- Poison-at-max health drain 1.0/s and bled-out 3.0/s kept as sensible defaults (tunable).

Demo test station uses EXAGGERATED bleed/poison rates (visible in seconds) and gains
STARVE/DEHYDRATE cubes (jump the need to max) so the slow real-world consequences are
testable without waiting hours.

Gate green (stylua/selene/luau-lsp/build).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:42:40 +10:00
Samuel LisonandClaude Opus 4.8 aaac7a12af feat(survival): consequences — stats drain health, bleed-out/starvation kill
Make the survival stats matter, end to end (server-authoritative, tunable via the
new "Consequences" Config section):

- Starving (Hunger maxed) and dehydrated (Thirst maxed) drain health.
- Poison drains health scaled by its level (full rate at 100%).
- Blood at 0 → bleed out → death (fast health drain).
- Drains STACK and reduce the character's real Humanoid health, so death + Roblox
  respawn happen for free.
- Energy stops regenerating while starving, dehydrated, or fully fatigued — overriding
  the post-sprint regen, so a depleted player stays depleted until they fix the cause.

Supporting engine work:
- SurvivalConsequences system: the drain tick + keeps the "Health" stat attribute in
  lockstep with the Humanoid (HUD Health bar now reflects real damage) + resets all
  stats and clears modifiers on every (re)spawn — a fresh body, no death-loop.
- SurvivalStats: getDefinition() (read a stat's max) + resetPlayer().
- Movement: energy-regen gate reads Hunger/Thirst/Fatigue.
- Demo test station drops its hand-rolled health mirror (the engine does it now).

Verified: gate green (stylua/selene/luau-lsp/build); drain math checked (stacked = 6.5/s,
poison scales, regen gates). Tuning + behaviour ported from TheCounterEarth's StatsConfig.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:23:06 +10:00
Samuel LisonandClaude Opus 4.8 b72350757f feat(movement): sprint/jump/energy + low-stat feedback (ported from TheCounterEarth)
Sprinting did nothing because Energy shipped display-only. This ports TCE's
proven movement system into the engine, server-authoritative:

- Hold Shift → sprint: drains Energy while moving, raises WalkSpeed to SprintSpeed,
  forces ExhaustedSpeed at 0 energy; Energy regenerates after an idle delay.
- Jumps cost energy and are gated below MinToJump (JumpPower → 0), with the same
  0.15s multi-signal throttle TCE uses.
- Energy is written through the stat-effects layer (Stats.adjust), so it stays a
  replicated Player Attribute the HUD already shows — no extra remotes for state.

Adds the engine's FIRST RemoteEvent plumbing (shared/Remotes.luau → SprintIntent,
created server-side, awaited client-side) and a tunable "Movement" Config section
(shared/MovementConfig.luau) carrying TCE's exact numbers + the free vignette/
breathing/heartbeat asset IDs.

Client (MovementFeedback, booted by startClient): Shift input → SprintIntent, plus
the low-stat feedback — a screen vignette + breathing loop that intensify as Energy
drops and a heartbeat loop below 40% health, all smoothed per frame.

New files: src/shared/{Remotes,MovementConfig}.luau, src/systems/Movement.luau,
src/client/MovementFeedback.luau. Wired into start()/startClient().

Gate green (stylua/selene/luau-lsp/build x3). Needs an in-Play test after a Studio
restart (Play-Solo stale-bytecode cache). Thirst/fatigue/campfire regen gating is a
follow-on with the full consequence-system port (StatsConfig is the blueprint).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:49:41 +10:00
Samuel LisonandClaude Opus 4.8 619052a790 feat(stats): dynamic per-player stat effects (adjust + rate modifiers)
The base ratePerSecond is a constant drift per stat — fine for hunger creeping
up, but it can't express event-driven, per-player behaviour: poison ticking
until cured, bleeding until clotted, sprint draining energy until you stop.
(That's why Poison/Blood ship at rate 0 and Energy is display-only.)

Adds a server-side modifier layer on top of the baseline, surfaced on
SurvivorCore.Stats once start() has run:

  - adjust(player, name, delta)       one-time signed delta, clamped to 0..max
  - addModifier(player, name, spec)   named rate modifier {ratePerSecond, source, duration?}
  - removeModifier(player, name, src) remove by source key
  - getValue(player, name)            read current value

The tick now applies base + Σ(active modifiers) per player; timed modifiers
expire on their own; a leaver's modifiers are dropped (no leak). Same-source
re-add replaces (no implicit stacking). Server-only / authoritative.

Verified: gate green (stylua/selene/luau-lsp/build); algorithm exercised in
Studio (adjust→clamp, poison modifier ticks up, cure stops it, timed expiry,
negative bleed). Foundation for sprint/jump energy + poison/bleed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:18:25 +10:00
Samuel LisonandClaude Opus 4.8 c118ced576 feat(plugin): add reversible edit-mode HUD preview (icons + sample fills)
Studio doesn't run the HUD client binder in Edit view, so an authored SurvivalHud
shows its static template there — full bars, blank readouts, and only the shipped
default icons (an icon override isn't visible until Play). The admin plugin now has
a footer with **Preview HUD** / **Clear** that paints, in Edit, what the running
game would render, so owners tune-and-see without pressing Play.

- plugin/HudPreview.luau (new): mirrors the engine binder's resolution — per-bar
  `Icon` attribute › the stat's effective icon (config/admin override else shipped
  default) for icons; FillAxis-aware sample fill; per-stat ValueFormat for the
  readout; a sample counter value. Every property is snapshotted once before the
  first write and clear() restores them exactly (so it's fully reversible);
  apply() takes an optional hud root for testability. Skips the Assets registry
  tier (runtime-only, empty in Edit) and never guesses engine-owned invert/dangerHigh.
- StatAdminUi: a footer bar with Preview / Clear buttons + a status readout.
- init.server: wires both through ChangeHistory (each is one undo step).
- Verified in Studio: synthetic-HUD logic test (icon resolution, sample fill/value,
  exact restore) + a live visual pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:26:54 +10:00
Samuel LisonandClaude Opus 4.8 69bbf12be9 feat(hud): ship free default stat icons (visible in Studio Edit)
Owner relaxed the asset side of the content-free rule — assets in this repo are
free to use — so the engine now ships its generated HUD icons as defaults instead
of leaving blank slots. Two wins: the HUD is iconed out of the box, and the icons
render in Studio's EDIT view (no Play needed), so you can author/tune the HUD and
see the real thing — or edit it straight from the Explorer.

- StatDefs.luau: each of the 7 stats carries an `icon` default. Putting it here
  (not as a per-bar HUD attribute) keeps the admin-panel/config override working —
  a per-bar attribute would shadow it. resolveIcon: per-bar attr > config/def.icon
  (now the shipped id) > Assets > "".
- assets/hud/SurvivalHud.model.json: bake each bar's child `Icon` ImageLabel
  (Image + Visible=true) so it shows in edit mode; the Credits counter (no StatDefs
  entry) also gets a per-bar `Icon` attribute to drive its runtime resolution.
- Retire demo/client/HudIcons.client.luau (+ its demo.project.json mount): the
  runtime icon-assigning script is now redundant.
- Relax the docs/PR-template "content-free" wording to "design-free": free default
  ART may ship (overridable per stat); game-specific DESIGN (items/recipes/lore)
  still never ships. Updated design-language, survival-stats, CONTRIBUTING.
- CHANGELOG: record default icons + add the missing admin-plugin entry; note CI
  now builds all three Rojo targets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:02:39 +10:00
Samuel LisonandClaude Opus 4.8 2e7bd69c2c docs: make admin-plugin install explicit + discoverable
Owner feedback: synced the engine into a fresh place, couldn't find the admin
plugin. Root cause is a docs gap — nothing told the reader that a plugin is
installed separately from a place sync.

- admin-plugin.md: lead the Install section with the key distinction (it's a
  Studio editor tool, not place content, so an engine sync does NOT install it);
  add per-OS plugins-folder paths (macOS / Windows); spell out the restart-once /
  hot-reload-after behaviour; and note the form needs a place with the engine
  synced (else the empty state), incl. the restart-drops-unsaved-sync caveat.
- getting-started.md: link Survival Stats + the admin plugin from Next steps,
  flagging that the plugin installs separately from the engine.
- README: add a "Tuning, no code" pointer to the admin plugin from the front page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:33:43 +10:00
Samuel LisonandClaude Opus 4.8 4256edfd87 feat(plugin): add Survival Stats admin Studio plugin (deltas-only, locked tuning)
A Studio dock widget that lets the experience owner tune the survival stats
through a validated form instead of hand-editing Attributes on the
SurvivalStatsConfig instance — the first slice of the Builder/Admin plugin (#11).

The point is compatibility: edits are LOCKED against engine updates. StatAdmin
(the pure, headlessly-testable logic layer) writes deltas only — it sets an
attribute solely when the owner changes a field from the live engine default,
and removes it on reset / edit-back-to-default. So unset fields keep following
the (improvable) engine defaults across a SurvivorCore release, while explicit
overrides live on the owner's instance, which the engine only ever seeds and
never overwrites. Nothing tuned is lost; nothing left alone is frozen.

Hard guardrail: the plugin can read/write only the seven owner-tunable fields
(STUDIO_ATTR_MAP). A write() assert makes it impossible to ever set the
engine-owned semantics Invert / DangerHigh — re-freezing the affliction
fill-direction bug is structurally unreachable. Runtime-verified in Studio:
every write path exercised (including rejected Invert/DangerHigh attempts) left
zero banned attributes on the instance.

- plugin/StatAdmin.luau     — logic: roster, effective values, deltas-only writes
- plugin/StatAdminUi.luau   — the dock-widget form (per-field reset, override dots)
- plugin/init.server.luau   — toolbar/widget wiring + ChangeHistory undo steps
- plugin.project.json       — separate Rojo tree; build with --plugin to install
- CI: stylua + a plugin-sourcemap luau-lsp pass + a plugin build
- docs/admin-plugin.md + cross-links; fix stale Invert row in the no-code table

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:22:57 +10:00
Samuel LisonandClaude Opus 4.8 63b1bbd6fb docs: 'providing your own HUD art' + the Studio/Rojo stale-Play-cache gotcha
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:28:42 +10:00
Samuel LisonandClaude Opus 4.8 0d6ff2e064 docs: add the project design language (UI style, palette, icon pipeline)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:03:38 +10:00
Samuel LisonandClaude Opus 4.8 45e2c41a52 docs: document the redesigned HUD (panel, collapse, Value/Icon, StatIcons)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:00:24 +10:00
Samuel LisonandClaude Opus 4.8 772b555578 Document survival stats; lint the HUD loader in CI
Add docs/survival-stats.md (the stat model, no-code SurvivalStatsConfig tuning, the
SurvivorStatBar/Stat contract, the Rojo one-way-sync caveat) and cross-link it.
CHANGELOG Unreleased entry. CI + CONTRIBUTING now run stylua/luau-lsp over assets/
so the HUD loader is checked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:30:12 +10:00
Samuel LisonandClaude Opus 4.8 4436a4bbd6 Add CONTRIBUTING, CHANGELOG, and getting-started/extending docs
CONTRIBUTING mirrors FediHome's structure for the Roblox stack: prerequisites
(Studio + Rojo plugin 7.6.1, rokit, wally), local dev, code style (no hardcoded
asset IDs, content via register()/components, content-free core), the dev/main
branching model, PR flow, changelog rule, and label conventions. Seed
CHANGELOG.md (Keep a Changelog) with Unreleased + a 0.1.0 foundation entry. Add
getting-started (Rojo+Wally and drop-in .rbxm) and extending (register() API,
components, Hooks) guides; cross-link from architecture.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 18:05:33 +10:00
Samuel LisonandClaude Opus 4.8 286e2f5f91 Scaffold SurvivorCore foundation (v0.1.0)
Foundation (Config/Assets/EventBridge/Hooks/Registry), content registry family, creator-owned component layer + Gatherable example, runnable demo place, Rojo/Wally/Rokit config, and release CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:30:32 +10:00