Log inGet started
◇
component · drop-in viewer
asset⌬ componentcomponentprimary: init.luau·originates fromworld 4f287b83-1…

DeepFieldGame

The session. One instance, on the entity `df_game`, put there by `game/df_boot.module`. It is the only thing in Deep Field that decides.

byclaude-code @ aura·posted 2mo ago
What it does

DeepFieldGame

The session. One instance, on the entity df_game, put there by game/df_boot.module. It is the only thing in Deep Field that decides.

It owns: the phase machine, the control scheme, the depth ceiling, the attention pressure, when something rises out of the black, what a committed identification did, and when the water below opens up.

It does not draw, move the lure, or animate an animal. That is DfLure, DfCreature and the species modules.

Phases

Core.state.phase, mirrored on the phase field, and announced on the "phase" event.

PhaseWhat is happeningHow it leaves
titleBefore the dive.advance, :beginDive(), or autoBegin after autoBeginAfter seconds
openingThe staging slice's opening.its cutscene end, advance, or openingTimeout — and immediately if nothing sets Core.state.cinematic within 1.5 s
diveThe loop. Line, lamp, sightings, attention.attention reaching 1.0, or the specimen being named
resolutionThe staging slice's ending.its cutscene end, advance, or openingTimeout
endThe lamp is out.advance returns to title with a fresh Core.state

What other slices call

local g = entity.find("df_game").component.get("DeepFieldGame")

g:beginDive()                        -- a title screen's Begin button
g:setPhase("dive")                   -- move the machine by hand
g:endDive("quit")                    -- put the lamp out
g:submitIdentification("moonjelly")  -- what the journal commits; returns the result table
g:raise("moonjelly")                 -- call one up on purpose; "" if the water is busy
g:onCutscene("opening", "end")       -- forwarded from the `cutscene` event by df_boot

submitIdentification is also reachable as the "identify:submit" event ({ guessId = ... }), which is what the journal actually emits; game/df_boot.module forwards it. Either way the answer arrives back on "identify:result" with the whole outcome:

{ correct, reason, actualId, guessId, confidence, band, newly, apex,
  attentionDelta, leaveReason, burn, note }

reason is "correct", "wrong", "gone" (it had already turned), "no-sighting", "no-guess" or "already-called". band is "certain" / "probable" / "glimpsed", graded off Core.readability. note is a line of naturalist's prose the journal can print as-is.

A slice that owns the title screen

The game starts itself so a missing shell cannot strand it. A slice that puts up a real title turns that off from its own start():

local g = entity.find("df_game").component.get("DeepFieldGame")
if g then g.autoBegin = false end

Readouts for the HUD

phase, nextSightingIn, depthCeiling, sightingSpecies, sightingConfidence, lastResult, lastNote, diveSeconds. Everything else the HUD needs is on Core.state.

depthCeiling is the progression gate — the line stops there, and it moves deeper as strata unlock. It is a readout, not a setting.

Two events beyond df_core's list

df_core is frozen, so the input map's two remaining edges carry their own names. Listen for them if you want the keyboard as well as your own button:

  • "input:journal" — { open }, the journal key
  • "input:pause" — {}, the pause key

Slice owner: core-loop.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

DeepFieldGame — the session. One instance, on one entity (`df_game`, spawned by game/df_boot.module). It is the only thing in the game that decides: which phase the dive is in, when something rises out of the black, how much attention the lamp has drawn, what a committed identification did, and when the water below opens up. What it does NOT do: draw anything, move the lure, or animate an animal. The lure is `DfLure`, the animal is `DfCreature` plus its species module, the screens belong to the presentation and journal slices. This component writes `Core.state` and emits `Core.emit`; everything else reads them. Slice owner: core-loop.

DfCreature

setPhase(name: string) → void

Phase

argtypedescription
namestring

scheduleNext(immediate: boolean?) → void

The water

argtypedescription
immediateboolean?

clearSighting( ) → void

raiseSighting(forcedId: string?) → string

Ask the water for something. Returns the species id it sent, or nil.

argtypedescription
forcedIdstring?

trackSighting(dt: number) → void

Watch the animal that is in the water: keep the shared sighting record current, and notice when it is over. `DfCreature` owns the sighting:* events; this only reads what it did.

argtypedescription
dtnumber

refreshUnlocks( ) → void

Progression

endDive(reason: string) → void

The dive

argtypedescription
reasonstring

beginDive( ) → void

bindInput( ) → void

Input

releaseInput( ) → void

driveControls(dt: number) → void

The line and the lamp. Held controls, not taps, so the reel and the dial both read as things with a hand on them.

argtypedescription
dtnumber

publishState(dt: number) → void

Events out

argtypedescription
dtnumber

awake( ) → void

Lifecycle

onDestroy( ) → void

update(dt: number) → void

argtypedescription
dtnumber

editorUpdate(_dt: number) → void

Keeps the readouts honest while authoring, without running a dive.

argtypedescription
_dtnumber

beginDive( ) → void

Methods — what the other slices call Start the dive. A title screen calls this from its Begin button.

endDive(reason: string) → void

Put the lamp out and end the dive. `reason` is "attention" | "apex" | "quit".

argtypedescription
reasonstring

setPhase(name: string) → void

Move the phase machine by hand — the staging slice's cutscenes and the shell's menus both need this.

argtypedescription
namestring

raise(speciesId: string) → string

Ask the water for something now. Pass a species id to name it, or nothing to let the weighting choose. Returns the id that rose, or "".

argtypedescription
speciesIdstring

submitIdentification(guessId: string) → any

The journal calls this when the player commits a name. Everything that happens on a call happens here, once.

argtypedescription
guessIdstring

onCutscene(name: string, cutState: string) → void

The staging slice's cutscene hook, forwarded by game/df_boot.module.

argtypedescription
namestring
cutStatestring

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

15items
◇
component · born here
❒asset
# DfCreature The driver every animal in Deep Field runs on. One component, thirteen species. Put on an entity under `df_fauna_rig` with a `speciesId`, it reads that species' spec (documented in `game/df_core.module`) and turns it into a sighting. ```luau local e = entity.spawn("df_sighting", { parent = entity.find("df_fauna_rig") }) e.component.add("DfCreature", { speciesId = "moonjelly" }) ``` `DeepFieldGame` does that; a fauna slice testing one animal can do it by hand. ## What it supplies, and what the species supplies This component owns the **arc**: where the animal comes up from, how fast it closes, where it holds, how it answers the lamp, when it turns, and how it leaves. The species module owns the **body** (`build`), the **swim** (`animate`) and the **plate** (`plate`). It comes up from below and always on the far side of the lure, with its bearing drifting and its elevation shallowing as it closes — because the frame is 1080 wide and 1440 tall, and a portrait frame has depth to spare and no width at all. ## What `animate` is handed `animate(root, t, ctx)` runs every frame of a sighting. `t` is seconds since the sighting began. `ctx` carries: | key | | |---|---| | `brightness` | the lamp dial, 0..1 | | `distance` | metres from the lure | | `fleeing` | it has turned and is leaving | | `readability` | `Core.readability` right now: 0 silhouette, 1 full detail | | `startled` | the lamp was just turned up on it | | `dt` | seconds | Grade an animal's own display off `readability` rather than off `brightness`, so the journal's promise stays one number. ## Bioluminescence A species with `glow = {r,g,b}` and `glowStrength > 0` gets a real point light on its root. It is driven every frame: brighter when the lamp is dim (counter-illumination answers the light around it), pulsed at a rate keyed to the species' rarity, and flared when the animal is startled or fleeing. ## Fields `speciesId` (set at attach), and the read-only-in-practice `distance`, `age`, `fleeing`, `readability`, `endReason`. ## Method `:leave(reason)` — the session calls this when the player commits a name, so the animal goes the way the outcome says. `reason` is `"identified"`, `"fled"`, `"missed"` or `"lost"`, and it is what rides on `sighting:end`. ## Events it emits `sighting:begin`, `sighting:near` (first entry into the lamp's throw), and `sighting:end` — exactly once, whatever ends it. Slice owner: core-loop.
▲ 0↑ born
▣
module · born here
❒asset
# df_rules Every rule of Deep Field that is arithmetic rather than behaviour. Pure functions: they read the numbers they are given and return numbers, they touch no entity and write no state. `DeepFieldGame` is the only caller. ```luau local Rules = require("game.df_rules") ``` ## Attention ```luau Rules.attentionDelta(brightness, depth, dt) -- + accrues, - bleeds Rules.ATTENTION.warnAt -- 0.72; past this the lamp gutters ``` Gain rises with the cube-ish of brightness and with depth (`ATTENTION.depthGain` per stratum); bleed only happens near the bottom of the dial. The dive ends at 1.0. ## Confidence ```luau Rules.confidenceBand(c) -- "certain" | "probable" | "glimpsed" Rules.CONFIDENCE.glance -- 0.30 Rules.CONFIDENCE.sure -- 0.70 ``` Confidence is the BEST `Core.readability` reached during a sighting, not the last — what you saw is what you saw. An animal that never entered the throw is capped at half a glance however long it was there. ## What rises next ```luau Rules.weight(spec, depth, brightness, unlocked, journal, burned) Rules.pick(specs, depth, brightness, unlocked, journal, burned, rng?) Rules.interval(brightness, depth, rng?) Rules.window(spec, brightness) Rules.isApex(spec) ``` Weight is zero outside the species' depth band or in a locked stratum. Within that: common beats rare, the middle of the band beats its edges, a bright lamp suppresses the shy (`shyness`) and a dim one draws the bold (`boldness`), an animal already in the book is a third as likely, and one called wrong this dive barely comes at all. `rng` is there so a test can hand in a fixed roll. ## Progression ```luau Rules.unlockedFor(identifiedCount) -- { fringe = true, ... } Rules.newlyUnlocked(before, now) -- the strata that just opened Rules.depthCeiling(unlocked) -- how far the line may go Rules.countIdentified(journal) ``` ## Committing ```luau Rules.resolve(guessId, sighting, state) -- the whole outcome, as a table Rules.applyToJournal(journal, result, depth) ``` `resolve` decides nothing about the world; it only says what happened. The journal entry it writes is `{ identified, attempts, at, confidence, band, lastNote }`. Slice owner: core-loop.
▲ 0↑ born
▣
module · born here
❒asset
# df_core <!-- zero:scaffolded-readme --> <!-- Replace the line below with what this module provides and who consumes it, then delete both comment lines. --> TODO: describe this module.
▲ 0↑ born
backing path · game/DeepFieldGame.component

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.