Saxonberg Server API
    Preparing search index...

    Hierarchy

    Index

    Constructors

    Properties

    _decayProductPath: string | null = null

    Path to the daughter Material singleton. Resolves lazily on each getDecayProduct() call via findByTemplatePath.

    appearance: string = ''

    Free-prose appearance phrase for the substance as it reads in a holder — e.g. 'dark, steaming coffee', 'clear water'. The bulk substrate composes this into a holder's description (look thermos) and a surface puddle's line (a puddle of water). Plain property field; storage IS the value.

    Material composes PerceptibleMixin for its keyword pool (so drink coffee resolves a holder by its bulk material) but NOT Visible / Named — substance identity stays out of the perception-target machinery (no Sensor, scene, or light behavior), so material keywords never leak into room scope. Keywords are purely authored; appearance is the rendered phrase.

    atomicNumber: number | null = null

    Atomic number (Z). Element-only.

    autoDeriveKeywords: boolean = true

    Opt-out for auto-deriving keywords from the host's display name (via NamedMixin) and short description (via VisibleMixin). Default true — most hosts want "a brass thermometer" to fold into ['brass', 'thermometer'] automatically. Set to false in template data when you want hand-curated keywords only (e.g., a "scroll of resurrection" where you want just 'scroll', not ['scroll', 'of', 'resurrection'] — though "of" would be dropped as a stop word anyway, "resurrection" wouldn't).

    biologicalSource: BiologicalSource | null = null

    Source-species link for biological materials. null for non- biological materials and for biological materials where the source species isn't modeled. The species side carries _defaultMaterialPath pointing back here — the link is bidirectional per slate.

    composition: CompositionEntry[] = []

    Constituent breakdown for mixtures / alloys / composite materials. Pure elements have an empty list. Each entry's materialPath resolves lazily through StuffApi.findByTemplatePath at query time; same shape as _speciesPath / _materialPath cross-refs.

    decayMode: "" | DecayMode = ''

    Empty default for the same reason as halfLife. Production materials should set this in the seed data block.

    edibility: boolean = false

    Whether this material can be eaten. v1 has no consumer.

    formula: string | null = null

    Chemical formula (e.g. 'H2O'). Compound-only.

    halfLife: number = 0

    Half-life in years. 0 default reads as "not yet authored" — the mixin is composed onto Materials whose halfLife is meaningful; a zero value during testing should round-trip without crashing.

    name: string = ''

    Display name (e.g. 'iron', 'oak', 'fruit-flesh').

    nutrientAmounts: Record<string, number> = {}

    Inspectable nutrient amounts (tag → mg per serving) — the education-by-reference profile examine <food> surfaces. Parallel to nutrients: the tags drive routing, these amounts are data + display only (no body-side machinery). A flat Record<string, number> → default-Hydrator round-trip (the reserves precedent), no marshaller.

    nutrients: string[] = []

    Tagged nutrient categories ('protein', 'water', 'sugar') — the tags that drive metabolism's macro routing (kept as bare tags for back-compat with existing seeds). The inspectable per-amount profile lives in nutrientAmounts.

    primaryKeyword?: string

    Authored primary keyword. When set, getPrimaryKeyword() returns this value (after fail-soft validation against the live keyword pool). Persistent — author-set via template data:.

    Hydrator routes through setPrimaryKeyword (the Phase 1 dispatch prefers a set<Field> method), so an authored-but-invalid value in a template is logged + dropped at clone time rather than silently sitting in the slot waiting to confuse a renderer.

    savedPropMarshallers: Record<string, string> = {}

    Per-prop marshaller bindings. Maps prop name → marshaller templatePath. Persistent and arrives alongside savedProps during hydration. setProp / getProp consult this map to decide whether to invoke toStored / fromStored for a given value. Props without a binding here round-trip raw, the way scalar props always have.

    Auto-initialized to an empty object; populated by initProp(prop, { marshaller: '/path' }).

    savedProps?: Record<string, PropValue> = {}

    Persistent properties — STORED SHAPE. Host-internal storage; setProp applies marshaller.toStored before writing here when a marshaller is bound for the prop, and getProp applies marshaller.fromStored on read so external callers see the runtime type. The hydrator's bracket-assign deposits the raw record directly without per-key conversion — the marshaller binding lives on savedPropMarshallers and runs lazily at access time.

    stuffId: string

    Runtime ID for this object (generated using nanoid). This is NOT the MongoDB _id - it's a runtime identifier.

    symbol: string | null = null

    Element symbol (e.g. 'Fe', 'C', 'U'). Element-only.

    tags: string[] = []

    Free-form classification tags. See class header for layer-1 description; vocabulary intentionally not centrally registered.

    toxicity: ToxinTag[] = []

    Per-consumable toxin doses — {type, amount}[]. type is the toxin (and its Condition key, e.g. 'alcohol'); amount is the dose per serving (mg for solids / derived for liquids). The per-body rate params (absorption, clearance, potency, severity bands) live on the toxin's Condition seed, NOT here — the same amount-vs-rate split as nutrients. A list of flat objects → default-Hydrator round-trip (the composition precedent), no marshaller.

    transientProps: Record<string, PropValue> = {}

    Transient properties (memory only, lost on restart).

    _mixinName: string = 'RadioactiveMixin'
    fieldMarshallers: {
        density: string;
        molarMass: string;
        specificHeat: string;
        thermalConductivity: string;
    } = ...

    Field-marshaller bindings. The persistence pipeline routes hydration / save through these marshallers; setters stay strict on the runtime value type.

    persistentFields: string[] = ...
    subscribableFields: SubscribableFieldDescriptor[] = ...

    Live-query projection for primaryKeyword. Lives on the mixin (not on Stuff) because the field is mixin-gated: only Perceptible-composed hosts have a keyword pool. The substrate's prototype-chain walk unions this with Stuff.subscribableFields at projection time. Non-Perceptible hosts contribute no primaryKeyword descriptor; the substrate omits the field from their wire records, same shape quantity uses on Globbable.

    dependsOnFields lists the leaf sources: the authored override (primaryKeyword) AND the two fields the derived-pool head folds in (name via NamedMixin, shortDescription via VisibleMixin). Renaming or re-describing a Perceptible host re-projects the keyword surface without an explicit setter call. Shadow-lifecycle support rides on ShadowChangedEvent for parity with displayName.

    Accessors

    • get keywords(): string[]

      Host-internal accessor pair (Pattern D). External callers go through getKeywords() / setKeywords(). The private setter still fires when the Hydrator bracket-assigns target['keywords'] = data['keywords'] — bracket access bypasses TS visibility, so the normalization invariant runs during hydration.

      The getter returns the derived keyword pool: authored keywords plus, when autoDeriveKeywords is true, tokenized words from the host's display name (NamedMixin) and short description (VisibleMixin). Authored entries always lead so an exact-keyword match outranks a tokenized match (see scope-walk.scoreCandidate). Internal callers that need the raw authored set go through _keywords directly.

      Returns string[]

    • set keywords(value: string[]): void

      Parameters

      • value: string[]

      Returns void

    Methods

    • Consent seam for the residency (self-eviction) sweep. The sweep asks each idle object whether it may be culled; the object decides, reading its own knowledge. Default is cull ({ ok: true }) — a fresh backing class is reclaimable by default and only becomes sticky when its author deliberately vetoes, the correct bias for a leak-plugger. Return { ok: false, reason } to veto.

      Vetoes layer on the mixin/class that owns the relevant relationship, composed via super.canEvict(context) — base Stuff stays permissive and does not reach into Container/Shadow/Avatar/ Exit knowledge. The relational vetoes derive from the R2.x ref-cleanup rules: an object in an owned/symmetric live-ref relationship vetoes while its anchor is alive (see docs/subsystems/residency.md).

      Distinct from canDestruct: an object that permits eviction can still canDestruct-veto, so the sweep's enforce path tolerates a DestructError (logs + continues). The sweep calls this on the raw target (via RAW_TARGET) so asking never counts as a touch.

      Parameters

      Returns VetoResult

      Invoked by the residency sweep (ResidencyLogic) on idle candidates. Veto seam{ ok: false, reason } keeps the object resident. Override on the owning mixin/class and chain super.canEvict(context) so composed layers run. Public and ungateable (a subclass's super.canEvict() is author code).

    • Check if property exists AND the caller is allowed to see it. Returns the prop's options when both are true, null otherwise.

      Single answer to "does this prop exist and can I read it?": the Get access op gates visibility, so a denied caller gets the same null as for a non-existent prop. Lets EventApi.on disambiguate "no such event / not allowed to subscribe" from "exists and emitted-but-no-payload-yet" without sentinels.

      Type Parameters

      Parameters

      Returns PropOptions<T> | null

    • Destroy this object.

      Locked down by @CallSecurity(ApiOnly) — only callers under mud/api/ (in practice, StuffApi.destruct) may invoke it. @Unshadowable because the unregistration path must always run; a shadow that intercepts and skips it would leak the object into the registry forever. @Final because subclass overrides would defeat the same invariant — the loader hook throws FinalViolationError at import time on any subclass redefinition.

      Subclass cleanup belongs on the optional onDestruct() witness (consulted by StuffApi.destruct while the target is still live); refusal logic belongs on canDestruct(). This terminal destroy() is the unshadowable mark-and-unregister step only.

      Returns void

    • Aggregate chemistry view. Returns null when none of the chemistry fields are populated; otherwise returns an object carrying whichever subset is set. For programmatic chemistry inspection where reading a few fields at once is more convenient than four individual getters.

      Returns ElementChemistry | null

    • Read density. Strict-shape on Quantity<'kg/m³'>; the QuantityMarshaller absorbed authoring-shape coercion at the persistence boundary, so callers see only the runtime type.

      Returns Quantity<"kg/m³">

    • Read the recency timestamp. Read by the residency sweep — which calls it on the raw target (via RAW_TARGET) so the sweep's own introspection never counts as a touch.

      Returns number

    • Self-presentation — the casual-register render string for this object, the answer to "what does this Stuff call itself?" Three- step resolution:

      1. Named.name if present and non-empty — the object's proper name ("Alice", "Excalibur", "Town Square").
      2. Visible.shortDescription if present and non-empty — the object's visual identity ("a heavy oak door").
      3. The baked-in fallback (DEFAULT_PRESENTATION).

      For a Globbable stack (quantity !== 1) the count folds in as an affix — "30 coins" — pluralized via GrammarApi.pluralize (which honors host-side getPluralForm() overrides for irregulars). Named takes precedence over Visible so a Named-with-description renders by its proper name; code that needs the formal register calls getFullName() when typed as Named.

      Viewer-blind by design. This is the shared baseline every Stuff exposes; the viewer-aware naming step (recognition / identification — see docs/subsystems/belief.md) composes on top of it. Left shadowable (NOT @Final) so masking / disguise effects can override the rendered identity via a method shadow.

      Returns string

    • Build the composable Mml fragment for this object's display name — the Mml sibling of getPresentation. Mml.ref (and so every <item> / <name> / … identity tag) renders this, not a raw string, so a name joins the compose chain as a fragment like everything else. The label is the already-resolved, viewer-aware name (recognition runs in the render layer and hands it in).

      Return null for the plain default — Mml.ref then wraps the label in Mml.text, which escapes it exactly once, so player-authored names / status decoration are safe by construction and the fragment is never re-escaped downstream. Override to build a richer fragment (a TPA terminal wraps its name in <color> to tint by state). The plain-string getPresentation stays the surface for non-prose consumers (logs, context.note, MQL scalars).

      Parameters

      • _label: string

      Returns Mml | null

    • Read the primary keyword for this Stuff. Returns the authored value when it appears in the current derived keyword pool; otherwise the last derived-pool entry; otherwise undefined.

      Last-pool-entry (rather than first) is the better default for English modifier-noun phrases. Derived-pool ordering is authored keywords first, then tokenized name (NamedMixin), then tokenized shortDescription (VisibleMixin). For a Named "Oak Door" the tokens land in order ['oak', 'door']; for 'a brass thermometer' the tokens land ['brass', 'thermometer']. In both cases the head noun is the trailing token — what a player would naturally type to refer to the thing — and what look <X> click-affordances should send.

      Authors who need a non-trailing keyword pin it explicitly via setPrimaryKeyword(...). The substrate default is just a sensible last-resort.

      Intentionally does NOT call setPrimaryKeyword from the getter — the setter is a separate event surface from rendering.

      Returns string | undefined

    • Get property value (with masks applied).

      Lazily auto-initializes prop options when savedProps carries a hydration-delivered entry but propOptions doesn't yet — otherwise the value would be unreachable through the public API (getProp returns null without a config). Auto-init uses transient: false so the prop's persistence flag matches its storage location.

      Type Parameters

      Parameters

      Returns T | null

    • Read-only view combining saved + transient properties. Saved props are returned in their RUNTIME form — marshalled props pass through marshaller.fromStored on the way out so callers see Quantity instances and friends, not the raw stored shape.

      Returns Readonly<Record<string, PropValue>>

    • Read seam. Instance method, but unwraps via ProxyApi.unwrap before reaching the # slot — this inside an instance method called through the proxy is the proxy, and the # slot lives on the raw target.

      Returns string | null

    • Check if this object has been destroyed.

      @Unshadowable: the destroyed-state read is a framework invariant — any shadow that lied about it would let consumers touch a torn-down Stuff. @Final: subclasses overriding this would defeat the same invariant; the loader hook throws FinalViolationError at import time on any subclass that redefines it.

      Returns boolean

    • Terminal onDestruct no-op. Exists so subclasses and mixins overriding onDestruct can call super.onDestruct() without the cast-to-optional-callable dance — the chain is guaranteed to bottom out here. StuffApi.destruct invokes the hook via the optional-method dispatcher in api/stuff.ts; that path still works (always finds a function on the prototype).

      Override (not extend with super) at any layer that wants cleanup; chain to super.onDestruct() from the override so intermediate layers in a mixin chain run too.

      Returns void

      Invoked by StuffApi.destruct (and forceDestruct) while the target is still live, after canDestruct passes and before shadow-detach + destroy(). Witness — the return value is ignored (it cannot veto; canDestruct is the veto seam). Override to release resources/listeners and chain super.onDestruct() so mixin layers run.

    • Bulk-set chemistry. setChemistry(null) clears all four chemistry fields; passing a partial record sets the named fields and leaves the others at their current values? No — the convenience setter REPLACES the whole chemistry block to keep the holder/component contract symmetric. Use the individual setters for partial updates.

      Parameters

      Returns void

    • Set density. Strict on Quantity<'kg/m³'> — authors who hold a raw number wrap it via Quantity.of(n, 'kg/m³') at the call site. The QuantityMarshaller handles raw-shape coercion only on the persistence path; in-process callers commit to the typed value.

      Parameters

      Returns void

    • Replace the keyword list. Equivalent to this.keywords = keywords, kept for symmetry with the addKeyword/removeKeyword API.

      Parameters

      • keywords: string[]

      Returns void

    • Author-set the primary keyword. Stores the normalized value unconditionally; pool-membership is a cross-field invariant (the pool depends on shortDescription via VisibleMixin and name via NamedMixin) and the Hydrator's Phase 1 dispatch makes no ordering guarantee across mixins. Validating in the setter would (and did) silently drop authored values when this mixin's setter ran before the others contributing to the pool.

      The getter (getPrimaryKeyword) does the lookup: if the stored value is in the current pool, return it; otherwise fall back to pool[0]. That keeps authored intent honored regardless of hydration order, and a runtime caller passing a bogus value gets the same silent override behavior the getter already implements for any out-of-pool entry.

      Passing undefined clears the explicit override; subsequent getPrimaryKeyword() calls fall back to the derived-pool head.

      Parameters

      • value: string | undefined

      Returns void

    • Set property value (auto-initializes if doesn't exist).

      If savedProps already carries an entry for this name (e.g. delivered by hydration from a seed template), auto-init treats the prop as transient: false so subsequent writes route back to savedProps rather than landing in transientProps. Without this branch, hydrated values would be silently shadowed by the first set call.

      Type Parameters

      Parameters

      Returns boolean

    • Stamp this Stuff's templatePath and re-key the byTemplatePath index so future findByTemplatePath lookups see the new path. No-op when path matches the current value.

      Locked down by @CallSecurity(ApiOnly) because flipping a Stuff's identity post-clone would break FromTemplate policies and any caller-side caching of template-path identity. @Final @Unshadowable because the index update has to run for every successful set — a subclass override that forgot the index call (or a shadow that intercepted) would silently desync byTemplatePath.

      Unwraps via ProxyApi.unwrap so the #-slot access lands on the raw target (see comment on #templatePath above).

      Parameters

      • path: string

      Returns void

    • Set the spatial zone. Gated by FromSpatialZone — only the SpatialZone class and its subclasses (CartesianZone, SphericalZone) may call this through the proxy. The addLocation / removeLocation chokepoints on the zone side are the legitimate callers; everyone else is rejected.

      Clone-time seeding from StuffApi.#cloneInner doesn't go through this method — it uses the caller-allowlisted _stampZone seam below.

      @Final @Unshadowable because the index of substrate invariants that consult getZone() (containment's cross-zone gate, Mobile.traverse, MQL scope walks) trusts the slot's value; a subclass override or shadow that lied about it could break those invariants. No legitimate subclass needs to extend this anyway — the only legitimate write paths are the SpatialZone chokepoints and clone-time.

      Parameters

      Returns void

    • Get a string representation of this idea (for debugging). Subclasses should override to provide more specific information.

      Returns string

    • Refresh the recency timestamp to now. Timestamp-fixed (no caller-supplied value). Called on the raw target by the security gate on every successful dispatch (Phase 2) and by the residency presence walk.

      Returns void