Technical Memo: Intrinsics in JSHACK 🧠
Overview
This memo proposes introducing intrinsics as a first-class concept in JSHACK. Intrinsics represent meaningful game facts about an entity that are not stored directly as raw components but are instead derived from world state, event history, or virtual relationships.
From the perspective of systems consuming them, intrinsics behave similarly to components. However, unlike components, their values are evaluated rather than stored. This allows higher-level game rules to operate against stable semantic concepts without requiring ad-hoc flags scattered throughout the ECS data model.
Typical consumers of intrinsics include:
- dialog systems
- quest logic
- faction reactions
- item attunement
- environmental interactions
- achievement checks
The goal is to provide a clear semantic layer that sits between low-level simulation data and high-level gameplay logic.
Motivation
JSHACK currently favors a pure data model where most state is represented as ECS components. This works well for structural state but becomes awkward for facts that are:
- derived from relationships (e.g., hierarchy or membership)
- temporal (e.g., something that has never happened)
- policy-driven (e.g., moral or faction interpretations of actions)
Attempting to encode these facts directly as components tends to produce brittle logic or proliferating flags.
Intrinsics solve this by representing derived truths about entities that can be queried consistently without requiring them to exist as stored state.
Concept
An intrinsic represents a semantic property of an entity.
(subject, intrinsic_name) → value
Most intrinsics will be boolean, though numeric or categorical values are possible.
Intrinsics should represent game meaning, not mechanical signals.
For example:
peaceful
never_hit_monster
These are gameplay truths, not implementation details like counters or timestamps.
Example Intrinsics
peaceful
Represents whether a player has maintained peaceful behavior.
Possible evaluation criteria:
- no hostile verbs executed
- no aggressive actions within a defined window
- no intimidation or theft events
never_hit_monster
Represents whether the player has ever dealt damage to a monster.
Evaluation condition:
playerDamageToMonsterCount == 0
Note that this intrinsic may intentionally diverge from other behavioral concepts such as peacefulness.
Implementation Direction
Intrinsics are expected to be implemented as a hybrid of:
- virtual components
- evaluation rules
Virtual components already provide a mechanism for derived state within ECS. Intrinsics extend this idea by allowing evaluation logic to incorporate additional signals such as event history.
Core Structure
A minimal implementation might include:
Intrinsic Registry
Maps intrinsic names to evaluation functions.
intrinsic_name → evaluator
Intrinsic Evaluator
Function responsible for computing the intrinsic value.
evaluate(world, entityId) → value
Evaluators may inspect:
- ECS components
- virtual components
- indexed event facts
- hierarchical relationships
Per-Tick Memoization
Intrinsic values should be cached during a simulation tick to avoid repeated evaluation.
(entityId, intrinsicName) → cachedValue
This ensures intrinsic checks remain inexpensive even when frequently queried.
Event-Derived Facts
Many intrinsics depend on historical events.
Instead of scanning the entire event log repeatedly, the engine should maintain compact indexed facts per entity as events are applied.
Examples:
playerDamageToMonsterCount
playerHasEverHitMonster
lastAggressiveActionTick
Intrinsics can then evaluate cheaply using these indexed values.
Example:
never_hit_monster = playerDamageToMonsterCount == 0
This allows intrinsics to remain efficient without sacrificing expressiveness.
Usage: Gates
The primary consumer of intrinsics will be gates.
A gate represents a rule boundary where a condition must be evaluated before allowing some behavior to proceed.
Examples include:
- dialog options
- quest progression
- faction reactions
- shrine interactions
- item attunement
- achievements
Instead of embedding low-level checks:
if (player.damageDealtToMonstersCount === 0)
systems would instead query the intrinsic:
intrinsic(player, "never_hit_monster")
This keeps rules declarative and stable.
Design Principles
Intrinsics should follow several guiding principles.
Semantic meaning
Intrinsics represent meaningful gameplay truths rather than low-level mechanical signals.
Deterministic evaluation
Given the same world snapshot and event facts, intrinsic results should always be the same.
Cheap queries
Evaluation should be inexpensive through memoization and indexed facts.
Small surface area
The set of intrinsic names should remain small and stable.
Minimal persistence
Intrinsic values themselves should generally not be persisted. Instead, the underlying facts required for evaluation should be stored.
Benefits
Introducing intrinsics provides several structural improvements.
- Gameplay rules become declarative and expressive
- Semantic game truths become centralized
- ECS components remain focused on structural state
- Narrative systems gain a stable gating interface
- Derived conditions can evolve without breaking consumers
Intrinsics effectively introduce a semantic layer above raw simulation data.
Conclusion
Intrinsics provide a clean mechanism for representing derived gameplay truths within the JSHACK simulation.
They allow systems to reason about meaningful concepts such as peacefulness or pacifism without depending on raw counters or flags. By combining virtual components, evaluation logic, and indexed event facts, intrinsics can remain both expressive and efficient.
Conceptually, intrinsics sit above components and events as a lightweight semantic layer that enables more maintainable rule systems and richer gameplay logic.
Technical Memo: Intrinsics in JSHACK 🧠
Overview
This memo proposes introducing intrinsics as a first-class concept in JSHACK. Intrinsics represent meaningful game facts about an entity that are not stored directly as raw components but are instead derived from world state, event history, or virtual relationships.
From the perspective of systems consuming them, intrinsics behave similarly to components. However, unlike components, their values are evaluated rather than stored. This allows higher-level game rules to operate against stable semantic concepts without requiring ad-hoc flags scattered throughout the ECS data model.
Typical consumers of intrinsics include:
The goal is to provide a clear semantic layer that sits between low-level simulation data and high-level gameplay logic.
Motivation
JSHACK currently favors a pure data model where most state is represented as ECS components. This works well for structural state but becomes awkward for facts that are:
Attempting to encode these facts directly as components tends to produce brittle logic or proliferating flags.
Intrinsics solve this by representing derived truths about entities that can be queried consistently without requiring them to exist as stored state.
Concept
An intrinsic represents a semantic property of an entity.
Most intrinsics will be boolean, though numeric or categorical values are possible.
Intrinsics should represent game meaning, not mechanical signals.
For example:
These are gameplay truths, not implementation details like counters or timestamps.
Example Intrinsics
peacefulRepresents whether a player has maintained peaceful behavior.
Possible evaluation criteria:
never_hit_monsterRepresents whether the player has ever dealt damage to a monster.
Evaluation condition:
Note that this intrinsic may intentionally diverge from other behavioral concepts such as peacefulness.
Implementation Direction
Intrinsics are expected to be implemented as a hybrid of:
Virtual components already provide a mechanism for derived state within ECS. Intrinsics extend this idea by allowing evaluation logic to incorporate additional signals such as event history.
Core Structure
A minimal implementation might include:
Intrinsic Registry
Maps intrinsic names to evaluation functions.
Intrinsic Evaluator
Function responsible for computing the intrinsic value.
Evaluators may inspect:
Per-Tick Memoization
Intrinsic values should be cached during a simulation tick to avoid repeated evaluation.
This ensures intrinsic checks remain inexpensive even when frequently queried.
Event-Derived Facts
Many intrinsics depend on historical events.
Instead of scanning the entire event log repeatedly, the engine should maintain compact indexed facts per entity as events are applied.
Examples:
Intrinsics can then evaluate cheaply using these indexed values.
Example:
This allows intrinsics to remain efficient without sacrificing expressiveness.
Usage: Gates
The primary consumer of intrinsics will be gates.
A gate represents a rule boundary where a condition must be evaluated before allowing some behavior to proceed.
Examples include:
Instead of embedding low-level checks:
systems would instead query the intrinsic:
This keeps rules declarative and stable.
Design Principles
Intrinsics should follow several guiding principles.
Semantic meaning
Intrinsics represent meaningful gameplay truths rather than low-level mechanical signals.
Deterministic evaluation
Given the same world snapshot and event facts, intrinsic results should always be the same.
Cheap queries
Evaluation should be inexpensive through memoization and indexed facts.
Small surface area
The set of intrinsic names should remain small and stable.
Minimal persistence
Intrinsic values themselves should generally not be persisted. Instead, the underlying facts required for evaluation should be stored.
Benefits
Introducing intrinsics provides several structural improvements.
Intrinsics effectively introduce a semantic layer above raw simulation data.
Conclusion
Intrinsics provide a clean mechanism for representing derived gameplay truths within the JSHACK simulation.
They allow systems to reason about meaningful concepts such as peacefulness or pacifism without depending on raw counters or flags. By combining virtual components, evaluation logic, and indexed event facts, intrinsics can remain both expressive and efficient.
Conceptually, intrinsics sit above components and events as a lightweight semantic layer that enables more maintainable rule systems and richer gameplay logic.