context

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Context

上下文(World对象)

"The context IS the world as seen from inside the closure." — Dave Ungar, on lexical scope

"上下文就是闭包内部所看到的整个世界。" — 戴夫·昂加尔,关于词法作用域

What Is It?

什么是World上下文?

The world object is passed to every compiled closure. It provides:
  1. Standard keys — Always present (adventure, player, room, turn)
  2. Extended keys — Contextual (object, target, npc)
  3. Skill namespaces — Skills register state under
    world.skills.skill_name
  4. Utility functions — API for interacting with the world
world 对象会传递给每个已编译的闭包。它提供以下内容:
  1. 标准键 —— 始终存在(adventure、player、room、turn)
  2. 扩展键 —— 上下文相关(object、target、npc)
  3. 技能命名空间 —— 技能会在
    world.skills.skill_name
    下注册状态
  4. 工具函数 —— 用于与游戏世界交互的API

Why "world" not "ctx"?

为什么用“world”而不是“ctx”?

  • More evocative — closures see the WORLD
  • Self-documenting —
    world.player
    ,
    world.room
  • Matches the mental model

  • 更具表现力 —— 闭包看到的是整个“世界”
  • 自文档化 ——
    world.player
    、
    world.room
    一目了然
  • 符合心智模型

Standard Keys

标准键

Always present in every world:
javascript
world.turn           // Current simulation turn
world.timestamp      // ISO timestamp

world.adventure      // Root adventure state
  .name
  .flags             // Global boolean flags
  .world_state       // Global key/value state

world.player         // Current player
  .id
  .name
  .location          // Path to current room
  .inventory         // Array of item ids
  .buffs             // Active buffs

world.room           // Current room
  .id
  .name
  .path
  .exits
  .objects
  .is_dark
  .is_dangerous

world.party          // Party state
  .members
  .leader

每个World上下文中始终存在以下键:
javascript
world.turn           // Current simulation turn
world.timestamp      // ISO timestamp

world.adventure      // Root adventure state
  .name
  .flags             // Global boolean flags
  .world_state       // Global key/value state

world.player         // Current player
  .id
  .name
  .location          // Path to current room
  .inventory         // Array of item ids
  .buffs             // Active buffs

world.room           // Current room
  .id
  .name
  .path
  .exits
  .objects
  .is_dark
  .is_dangerous

world.party          // Party state
  .members
  .leader

Extended Keys

扩展键

Present when relevant:
javascript
// When running object simulate/methods:
world.object         // The object being simulated
  .id
  .state             // Object's mutable state
  // Methods are bound: world.consume_fuel(1)

// When action targets something:
world.target         // The target
  .id
  .type              // "object", "character", "room"

// When NPC is simulating:
world.npc            // The NPC
  .id
  .goals
  .state

仅在相关场景下存在:
javascript
// 运行对象模拟/方法时:
world.object         // 正在被模拟的对象
  .id
  .state             // 对象的可变状态
  // 方法已绑定:world.consume_fuel(1)

// 操作有目标对象时:
world.target         // 目标对象
  .id
  .type              // "object", "character", "room"

// NPC进行模拟时:
world.npc            // NPC对象
  .id
  .goals
  .state

Skill State Namespaces

技能状态命名空间

Skills register state under
world.skills.<skill_name>
using underscores:
javascript
// Skill "economy" → world.skills.economy
world.skills.economy.gold        // 100

// Skill "pie-menu" → world.skills.pie_menu (underscore!)
world.skills.pie_menu.last_selection  // "north"

// Skill "time" → world.skills.time
world.skills.time.hour           // 14
world.skills.time.phase          // "afternoon"
Why underscores? Dashes aren't valid JS/Python identifiers.
foo-bar
skill →
foo_bar
namespace.
This keeps skill state organized and avoids collisions.

技能会使用下划线在
world.skills.<skill_name>
下注册状态:
javascript
// 技能 "economy" → world.skills.economy
world.skills.economy.gold        // 100

// 技能 "pie-menu" → world.skills.pie_menu(使用下划线!)
world.skills.pie_menu.last_selection  // "north"

// 技能 "time" → world.skills.time
world.skills.time.hour           // 14
world.skills.time.phase          // "afternoon"
为什么使用下划线? 短横线不是有效的JS/Python标识符。例如
foo-bar
技能会对应
foo_bar
命名空间。
这样可以保持技能状态的组织性,避免命名冲突。

Utility Functions

工具函数

Methods bound to world for interaction:
绑定到World对象的交互方法:

Narrative

叙事相关

javascript
world.emit("The lamp dies!")              // Show message
world.narrate("Darkness falls.", "dramatic")
javascript
world.emit("The lamp dies!")              // Show message
world.narrate("Darkness falls.", "dramatic")

Events

事件触发

javascript
world.trigger_event("GRUE_APPROACHES", { room: world.room.path })
javascript
world.trigger_event("GRUE_APPROACHES", { room: world.room.path })

Inventory

物品栏操作

javascript
world.has("brass-key")                    // true/false
world.give("gold-coins")                  // Add to inventory
world.take("used-potion")                 // Remove from inventory
javascript
world.has("brass-key")                    // true/false
world.give("gold-coins")                  // Add to inventory
world.take("used-potion")                 // Remove from inventory

Flags

标志位操作

javascript
world.flag("dragon_slain")                // Get flag
world.set_flag("treasure_found", true)    // Set flag
javascript
world.flag("dragon_slain")                // Get flag
world.set_flag("treasure_found", true)    // Set flag

State

状态操作

javascript
world.get("object.state.fuel")            // Get by path
world.set("object.state.lit", true)       // Set by path
javascript
world.get("object.state.fuel")            // Get by path
world.set("object.state.lit", true)       // Set by path

Navigation

导航操作

javascript
world.go("../maze/room-a/")               // Move player
world.can_go("north")                     // Check exit
javascript
world.go("../maze/room-a/")               // Move player
world.can_go("north")                     // Check exit

Buffs

增益效果操作

javascript
world.add_buff({ name: "Caffeinated", effect: { energy: +2 }, duration: 5 })
world.remove_buff("caffeinated")
world.has_buff("grue_immunity")
javascript
world.add_buff({ name: "Caffeinated", effect: { energy: +2 }, duration: 5 })
world.remove_buff("caffeinated")
world.has_buff("grue_immunity")

Logging

日志输出

javascript
world.log("Debug: fuel = " + world.object.state.fuel)

javascript
world.log("Debug: fuel = " + world.object.state.fuel)

Example: Lamp Simulate

示例:油灯模拟

javascript
simulate_js: (world) => {
  if (world.object.state.lit) {
    world.consume_fuel(1);                  // Call object method
    
    if (world.object.state.fuel <= 0) {
      world.extinguish();                   // Call object method
      world.emit("The lamp sputters and dies!");
      
      if (world.room.is_dark && world.room.is_dangerous) {
        world.trigger_event("GRUE_APPROACHES");
      }
    }
  }
}

javascript
simulate_js: (world) => {
  if (world.object.state.lit) {
    world.consume_fuel(1);                  // Call object method
    
    if (world.object.state.fuel <= 0) {
      world.extinguish();                   // Call object method
      world.emit("The lamp sputters and dies!");
      
      if (world.room.is_dark && world.room.is_dangerous) {
        world.trigger_event("GRUE_APPROACHES");
      }
    }
  }
}

Example: Guard Expression

示例:守卫表达式

yaml
guard: "player has the key AND room is not dark"
guard_js: (world) => world.has("brass-key") && !world.room.is_dark

yaml
guard: "player has the key AND room is not dark"
guard_js: (world) => world.has("brass-key") && !world.room.is_dark

Example: Score Calculation

示例:分数计算

yaml
score_if: "player is tired OR room is dark"
score_if_js: (world) => world.has_buff("tired") || world.room.is_dark

yaml
score_if: "player is tired OR room is dark"
score_if_js: (world) => world.has_buff("tired") || world.room.is_dark

Example: Skill State

示例:技能状态

yaml
undefined
yaml
undefined

Skill "economy" needs to check gold

Skill "economy" needs to check gold

guard: "player has at least 10 gold" guard_js: (world) => world.skills.economy.gold >= 10
guard: "player has at least 10 gold" guard_js: (world) => world.skills.economy.gold >= 10

Skill "pie-menu" checks last selection

Skill "pie-menu" checks last selection

score_if: "last pie menu selection was north" score_if_js: (world) => world.skills.pie_menu.last_selection === "north"

---
score_if: "last pie menu selection was north" score_if_js: (world) => world.skills.pie_menu.last_selection === "north"

---

Design Principles

设计原则

Structured, Not Arbitrary

结构化而非随意性

world is NOT just a bag of key/values. It has defined structure:
  • Standard keys are always present
  • Extended keys appear in context
  • Skills namespace their state (with underscores!)
  • Functions are bound methods
World上下文并非简单的键值对集合,它有明确的结构:
  • 标准键始终存在
  • 扩展键仅在相关场景出现
  • 技能使用命名空间管理状态(必须用下划线!)
  • 函数均为已绑定的方法

Skill Namespaces (Underscores!)

技能命名空间(必须用下划线!)

Skills don't pollute root world. They register under
world.skills.skill_name
:
javascript
// Skill "economy" → world.skills.economy
world.skills.economy.gold
world.skills.economy.currency

// Skill "pie-menu" → world.skills.pie_menu (underscore!)
world.skills.pie_menu.last_selection
world.skills.pie_menu.hover_direction

// Skill "foo-bar" → world.skills.foo_bar
world.skills.foo_bar.some_state
Rule:
skill-name
with dashes →
skill_name
with underscores in namespace.
技能不会污染根World上下文,而是注册在
world.skills.skill_name
下:
javascript
// 技能 "economy" → world.skills.economy
world.skills.economy.gold
world.skills.economy.currency

// 技能 "pie-menu" → world.skills.pie_menu(使用下划线!)
world.skills.pie_menu.last_selection
world.skills.pie_menu.hover_direction

// 技能 "foo-bar" → world.skills.foo_bar
world.skills.foo_bar.some_state
规则: 带短横线的
skill-name
会转换为带下划线的
skill_name
命名空间。

Methods Are Bound

方法已绑定

Object methods appear as functions on world:
javascript
// Object defines:
methods:
  consume_fuel: "reduce fuel by amount"

// At runtime, method is bound:
world.consume_fuel(1)  // Works!

对象的方法会作为函数绑定到World上下文:
javascript
// 对象定义:
methods:
  consume_fuel: "reduce fuel by amount"

// 运行时,方法已绑定:
world.consume_fuel(1)  // 可直接调用!

Related Skills

相关技能

  • object — Provides ctx.object
  • room — Provides ctx.room
  • adventure — Provides ctx.adventure
  • buff — Used by ctx.add_buff/has_buff

  • object —— 提供ctx.object
  • room —— 提供ctx.room
  • adventure —— 提供ctx.adventure
  • buff —— 被ctx.add_buff/has_buff使用

Dual Runtime: Python + JavaScript

双运行时:Python + JavaScript

CRITICAL: We always generate BOTH
_js
AND
_py
versions of compiled expressions.
yaml
undefined
关键注意事项: 我们始终为编译后的表达式生成
_js
和
_py
两种版本。
yaml
undefined

Natural language

自然语言表达式

guard: "player has the key AND room is not dark"
guard: "player has the key AND room is not dark"

BOTH generated:

两种版本都会生成:

guard_js: (world) => world.has("brass-key") && !world.room.is_dark guard_py: lambda world: world.has("brass-key") and not world.room.is_dark
undefined
guard_js: (world) => world.has("brass-key") && !world.room.is_dark guard_py: lambda world: world.has("brass-key") and not world.room.is_dark
undefined

Why Dual Runtimes?

为什么需要双运行时?

RuntimePurpose
PythonServer-side simulation, testing, LLM tethering
JavaScriptBrowser runtime, standalone play
运行时用途
Python服务器端模拟、测试、LLM集成
JavaScript浏览器端运行、独立游玩

Keeping Them In Sync

保持双运行时同步

  1. Same semantics — Both should produce identical results
  2. Same world structure —
    world.player
    ,
    world.room
    , etc.
  3. Same utility functions —
    world.has()
    ,
    world.emit()
    , etc.
  4. Generated together — LLM produces both in one pass
  1. 语义一致 —— 两种版本必须产生完全相同的结果
  2. World结构一致 ——
    world.player
    、
    world.room
    等结构完全相同
  3. 工具函数一致 ——
    world.has()
    、
    world.emit()
    等函数行为一致
  4. 同步生成 —— LLM会一次性生成两种版本

The Compilation Event

编译事件定义

yaml
- event: COMPILE_EXPRESSION
  field: guard
  source: "player has the key"
  targets:
    - field: guard_js
      language: javascript
    - field: guard_py
      language: python
  expected_type: boolean
yaml
- event: COMPILE_EXPRESSION
  field: guard
  source: "player has the key"
  targets:
    - field: guard_js
      language: javascript
    - field: guard_py
      language: python
  expected_type: boolean

Python Runtime Class

Python运行时类

python
class World:
    """Python runtime context — mirrors JavaScript World class."""
    
    def __init__(self, adventure_data):
        self.turn = 0
        self.adventure = adventure_data
        self.player = adventure_data['player']
        self.room = None  # Set on navigation
        self.party = adventure_data['party']
        self.object = None  # Set during object simulation
        self.skills = {}  # Skill state namespaces
        
    def has(self, item_id: str) -> bool:
        return item_id in self.player.get('inventory', [])
        
    def flag(self, name: str) -> bool:
        return self.adventure.get('flags', {}).get(name, False)
        
    def emit(self, message: str):
        print(message)  # Or queue for output
        
    def trigger_event(self, name: str, data=None):
        # Event system handles this
        pass
python
class World:
    """Python runtime context — mirrors JavaScript World class."""
    
    def __init__(self, adventure_data):
        self.turn = 0
        self.adventure = adventure_data
        self.player = adventure_data['player']
        self.room = None  # Set on navigation
        self.party = adventure_data['party']
        self.object = None  # Set during object simulation
        self.skills = {}  # Skill state namespaces
        
    def has(self, item_id: str) -> bool:
        return item_id in self.player.get('inventory', [])
        
    def flag(self, name: str) -> bool:
        return self.adventure.get('flags', {}).get(name, False)
        
    def emit(self, message: str):
        print(message)  # Or queue for output
        
    def trigger_event(self, name: str, data=None):
        # Event system handles this
        pass

JavaScript Runtime Class

JavaScript运行时类

javascript
class World {
  /** JavaScript runtime context — mirrors Python World class. */
  
  constructor(adventureData) {
    this.turn = 0;
    this.adventure = adventureData;
    this.player = adventureData.player;
    this.room = null;  // Set on navigation
    this.party = adventureData.party;
    this.object = null;  // Set during object simulation
    this.skills = {};  // Skill state namespaces
  }
  
  has(itemId) {
    return (this.player.inventory || []).includes(itemId);
  }
  
  flag(name) {
    return (this.adventure.flags || {})[name] || false;
  }
  
  emit(message) {
    console.log(message);  // Or queue for UI
  }
  
  triggerEvent(name, data) {
    // Event system handles this
  }
}

javascript
class World {
  /** JavaScript runtime context — mirrors Python World class. */
  
  constructor(adventureData) {
    this.turn = 0;
    this.adventure = adventureData;
    this.player = adventureData.player;
    this.room = null;  // Set on navigation
    this.party = adventureData.party;
    this.object = null;  // Set during object simulation
    this.skills = {};  // Skill state namespaces
  }
  
  has(itemId) {
    return (this.player.inventory || []).includes(itemId);
  }
  
  flag(name) {
    return (this.adventure.flags || {})[name] || false;
  }
  
  emit(message) {
    console.log(message);  // Or queue for UI
  }
  
  triggerEvent(name, data) {
    // Event system handles this
  }
}

Protocol Symbol

协议标识

RUNTIME-CONTEXT — The world passed to closures (Python + JavaScript)
RUNTIME-CONTEXT — The world passed to closures (Python + JavaScript)