# Memory Palace: A Narrative Interface for Macroscope

**Document ID:** CNL-SP-2026-001  
**Version:** 0.1  
**Date:** February 5, 2026  
**Author:** Michael P. Hamilton, Ph.D.

---

> **AI Assistance Disclosure:** This specification was developed collaboratively with Claude (Anthropic, Claude Opus 4.5). The AI contributed to architecture design, schema definition, and document drafting based on existing NodeWorlds codebase analysis and iterative discussion with the author. The author takes full responsibility for the content, accuracy, and design decisions.

---

## Abstract

Memory Palace is a narrative interface layer for the Macroscope environmental monitoring platform. It transforms sensor data, geographic locations, and personal media into explorable text-based environments—interactive spaces where users navigate through memories, places, and time using natural language commands. The system combines the text adventure game paradigm with live environmental data, enabling users to create "palaces" that respond to real-world conditions: weather, bird activity, air quality, and seasonal change. This specification defines the architecture, data model, user interfaces, and integration points for Memory Palace within the Macroscope ecosystem. The initial implementation migrates the standalone NodeWorlds prototype into Macroscope, establishing Canemah (the Blue Heron Mill site) as the reference palace, then extends the platform with a Studio authoring environment and AI-assisted palace creation wizard.

---

## 1. Introduction

### 1.1 Background

NodeWorlds is a prototype text adventure engine developed in 2026 that integrates live sensor data into narrative descriptions. Players explore locations whose descriptions dynamically incorporate real-time weather, bird detections, and environmental conditions from the Macroscope sensor network. The prototype, currently available at `https://michaelphamilton.com/nodeworlds/`, demonstrated the viability of "living" interactive fiction—stories that breathe with the actual world.

Memory Palace generalizes this concept into a multi-tenant authoring platform. Any Macroscope user can create a palace—a navigable collection of locations, objects, and narrative text—and optionally bind locations to real places with live sensor feeds. Palaces can represent:

- **Physical sites** with environmental sensors (the Canemah model)
- **Travel memories** assembled from geotagged photographs
- **Fictional worlds** that borrow real-world weather
- **Educational environments** where students explore ecosystems
- **Personal archives** where objects contain journal entries

### 1.2 Objectives

1. Migrate NodeWorlds functionality into Macroscope without breaking the existing demo
2. Establish a multi-palace data model supporting independent worlds
3. Integrate with existing Macroscope sensor APIs and place hierarchy
4. Create a Studio interface for palace authoring
5. Design an AI-assisted wizard for photograph-based palace creation
6. Maintain the narrative quality established in the Canemah prototype

### 1.3 Scope

This specification covers:

- Database schema extensions to the Macroscope database
- Palace player (game engine) architecture
- Palace Studio (authoring interface) design
- Wizard workflow for AI-assisted creation
- API endpoints for palace operations
- Integration with Mapbox for geographic authoring
- Integration with Claude API for narrative generation

Out of scope:

- Mobile-native applications (web-responsive only)
- Multiplayer/synchronous experiences
- Monetization or subscription systems
- Export to other interactive fiction formats (Twine, Inform)

---

## 2. System Architecture

### 2.1 Component Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                        Macroscope                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────────────┐   │
│  │   Palace    │   │   Palace    │   │   Existing          │   │
│  │   Player    │   │   Studio    │   │   Macroscope UIs    │   │
│  │  /palace/   │   │  /studio/   │   │   /domains/, etc.   │   │
│  └──────┬──────┘   └──────┬──────┘   └─────────────────────┘   │
│         │                 │                                      │
│         ▼                 ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Palace API                            │   │
│  │                   /api/palace/                           │   │
│  └──────────────────────────┬──────────────────────────────┘   │
│                             │                                    │
│         ┌───────────────────┼───────────────────┐               │
│         ▼                   ▼                   ▼               │
│  ┌─────────────┐   ┌──────────────┐   ┌─────────────────┐      │
│  │   Palace    │   │   Sensor     │   │   Claude API    │      │
│  │   Tables    │   │   APIs       │   │   (Wizard)      │      │
│  │             │   │   (existing) │   │                 │      │
│  └─────────────┘   └──────────────┘   └─────────────────┘      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### 2.2 Directory Structure

```
[MACROSCOPE_ROOT]/
├── palace/
│   ├── index.php              # Palace directory/selection
│   ├── play.php               # Game engine (player interface)
│   ├── parse.php              # Command parser
│   ├── resolver.php           # Sensor data resolver
│   └── assets/
│       ├── css/
│       │   └── palace.css     # Player styles
│       └── js/
│           └── game.js        # Player JavaScript
│
├── studio/
│   ├── index.php              # Studio dashboard
│   ├── locations.php          # Location editor
│   ├── objects.php            # Object editor
│   ├── sensors.php            # Sensor assignment
│   ├── wizard.php             # AI creation wizard
│   ├── upload.php             # Photo upload handler
│   └── assets/
│       ├── css/
│       │   └── studio.css
│       └── js/
│           ├── studio.js
│           ├── wizard.js
│           └── mapbox.js      # Map interaction
│
├── api/palace/
│   ├── palaces.php            # List, create, update palaces
│   ├── locations.php          # CRUD for palace locations
│   ├── objects.php            # CRUD for palace objects
│   ├── game.php               # Game state, commands
│   ├── upload.php             # Photo upload API
│   └── wizard.php             # Wizard conversation API
```

### 2.3 Integration Points

| Component | Integration Method |
|-----------|-------------------|
| Sensor Data | Existing Macroscope sensor APIs (`/api/sensors/`) |
| Places | Macroscope `places` table via `place_id` foreign key |
| Users | Macroscope `users` table, existing auth system |
| Images | New `palace_images` table or shared Macroscope assets |
| Maps | Mapbox GL JS, user-provided API key |
| AI Wizard | Claude API via server-side proxy |

---

## 3. Data Model

### 3.1 New Tables

#### 3.1.1 palaces

Primary table for palace definitions.

```sql
CREATE TABLE `palaces` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `slug` VARCHAR(50) NOT NULL UNIQUE,
  `name` VARCHAR(100) NOT NULL,
  `description` TEXT,
  `owner_id` INT NOT NULL,
  `starting_location_id` VARCHAR(50),
  `cover_image_id` INT DEFAULT NULL,
  `visibility` ENUM('public', 'private', 'unlisted') DEFAULT 'private',
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_owner` (`owner_id`),
  KEY `idx_visibility` (`visibility`),
  CONSTRAINT `fk_palace_owner` FOREIGN KEY (`owner_id`) 
    REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.2 palace_locations

Locations within a palace. Each location may optionally link to a Macroscope place for sensor data.

```sql
CREATE TABLE `palace_locations` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `location_id` VARCHAR(50) NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `description` TEXT,
  `brief_description` TEXT,
  `exits` JSON DEFAULT '{}',
  `objects` JSON DEFAULT '[]',
  `place_id` INT DEFAULT NULL,
  `image_id` INT DEFAULT NULL,
  `map_x` INT DEFAULT 0,
  `map_y` INT DEFAULT 0,
  `latitude` DECIMAL(10,8) DEFAULT NULL,
  `longitude` DECIMAL(11,8) DEFAULT NULL,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_palace_location` (`palace_id`, `location_id`),
  KEY `idx_place` (`place_id`),
  CONSTRAINT `fk_location_palace` FOREIGN KEY (`palace_id`) 
    REFERENCES `palaces` (`id`) ON DELETE CASCADE,
  CONSTRAINT `fk_location_place` FOREIGN KEY (`place_id`) 
    REFERENCES `places` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.3 palace_objects

Examinable and interactive objects.

```sql
CREATE TABLE `palace_objects` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `object_id` VARCHAR(50) NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `examination` TEXT,
  `portable` TINYINT(1) DEFAULT 0,
  `image_id` INT DEFAULT NULL,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_palace_object` (`palace_id`, `object_id`),
  CONSTRAINT `fk_object_palace` FOREIGN KEY (`palace_id`) 
    REFERENCES `palaces` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.4 palace_sensor_assignments

Binds available sensors to palace locations.

```sql
CREATE TABLE `palace_sensor_assignments` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `sensor_id` INT NOT NULL,
  `target_type` ENUM('location', 'object') NOT NULL,
  `target_id` VARCHAR(50) NOT NULL,
  `template_var` VARCHAR(50) NOT NULL,
  `active` TINYINT(1) DEFAULT 1,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_palace_target` (`palace_id`, `target_type`, `target_id`),
  CONSTRAINT `fk_sensor_palace` FOREIGN KEY (`palace_id`) 
    REFERENCES `palaces` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.5 palace_sessions

Player session state.

```sql
CREATE TABLE `palace_sessions` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `session_id` VARCHAR(64) NOT NULL,
  `current_location` VARCHAR(50) NOT NULL,
  `inventory` JSON DEFAULT '[]',
  `visited` JSON DEFAULT '[]',
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_session` (`palace_id`, `session_id`),
  CONSTRAINT `fk_session_palace` FOREIGN KEY (`palace_id`) 
    REFERENCES `palaces` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.6 palace_images

Image assets for palaces.

```sql
CREATE TABLE `palace_images` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `filename` VARCHAR(255) NOT NULL,
  `original_filename` VARCHAR(255),
  `title` VARCHAR(100),
  `alt_text` VARCHAR(255),
  `description` TEXT,
  `file_size` INT,
  `width` INT,
  `height` INT,
  `latitude` DECIMAL(10,8) DEFAULT NULL,
  `longitude` DECIMAL(11,8) DEFAULT NULL,
  `taken_at` DATETIME DEFAULT NULL,
  `upload_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_palace` (`palace_id`),
  KEY `idx_coords` (`latitude`, `longitude`),
  CONSTRAINT `fk_image_palace` FOREIGN KEY (`palace_id`) 
    REFERENCES `palaces` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

#### 3.1.7 palace_command_log

Analytics for player behavior.

```sql
CREATE TABLE `palace_command_log` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `palace_id` INT NOT NULL,
  `session_id` VARCHAR(64) NOT NULL,
  `raw_input` VARCHAR(500),
  `parsed_action` VARCHAR(50),
  `parsed_target` VARCHAR(100),
  `success` TINYINT(1),
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_palace_session` (`palace_id`, `session_id`),
  KEY `idx_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### 3.2 Relationship to Existing Tables

| New Table | References | Relationship |
|-----------|-----------|--------------|
| `palaces` | `users` | Owner of palace |
| `palace_locations` | `places` | Optional link to Macroscope place for sensors |
| `palace_sensor_assignments` | Macroscope sensor infrastructure | Reuses `available_sensors` pattern |

### 3.3 Migration Strategy

The NodeWorlds tables (`locations`, `objects`, `sensor_bindings`, `available_sensors`, `sensor_assignments`, `sessions`, `images`, `command_log`) will be migrated to the new palace-scoped schema. Canemah becomes `palace_id = 1`.

---

## 4. Palace Player

### 4.1 Game Engine

The player is a web-based text interface that accepts natural language commands and returns narrative responses. Core mechanics:

| Command | Action |
|---------|--------|
| LOOK | Display current location description |
| GO/MOVE/ENTER [direction] | Navigate via exits |
| EXAMINE/LOOK AT [object] | Inspect objects |
| TAKE/PICK UP [object] | Add portable objects to inventory |
| INVENTORY | List carried items |
| MAP | Display node-graph map |
| HELP | Show available commands |
| RESTART | Reset session |

### 4.2 Sensor Resolution

Template variables in descriptions (`{{temperature}}`, `{{bird_activity}}`) are resolved at render time:

1. Parse description for `{{variable}}` patterns
2. Look up `palace_sensor_assignments` for matching `template_var`
3. Query appropriate Macroscope sensor API
4. Apply staleness check (fallback text if data too old)
5. Format and substitute into description

### 4.3 Visit Tracking

- First visit to a location: show `description`
- Return visit: show `brief_description` (if defined)
- LOOK command: always show full `description`

### 4.4 Map Interface

A modal SVG/canvas map showing:

- Nodes for each location
- Edges for exits
- Current location highlighted
- Visited locations distinguished from unvisited
- Click-to-teleport for visited locations

---

## 5. Palace Studio

### 5.1 Dashboard

The Studio home displays:

- List of user's palaces
- Create new palace button
- Quick stats (locations, objects, sessions played)
- Link to wizard for AI-assisted creation

### 5.2 Palace Editor

Tabbed interface for editing a palace:

| Tab | Function |
|-----|----------|
| Settings | Name, slug, description, visibility, starting location |
| Locations | CRUD for locations, exits editor, map position |
| Objects | CRUD for objects, portability, images |
| Sensors | Assign sensors to locations/objects |
| Images | Upload and manage palace images |
| Preview | Playtest the palace |
| Analytics | Command logs, session stats |

### 5.3 Location Editor

- Rich text description editor with `{{variable}}` insertion helper
- Exits manager (keyword → destination dropdown)
- Objects picker (multi-select from palace objects)
- Optional link to Macroscope place (enables sensor binding)
- Geographic coordinates (manual entry or Mapbox picker)
- Node map position (drag on schematic view)
- Image assignment

### 5.4 Sensor Assignment

When a location is linked to a Macroscope place, available sensors for that place's platforms are shown. User can:

1. Select a sensor
2. Name the template variable
3. Preview current sensor value
4. Test resolution in context

---

## 6. Creation Wizard

### 6.1 Overview

The wizard transforms a collection of geotagged photographs into a palace through AI-assisted interview. It leverages Claude's vision and conversation capabilities to extract narrative from the user.

### 6.2 Workflow

```
┌─────────────────────────────────────────────────────────────────┐
│  1. UPLOAD                                                       │
│     User drags photos → EXIF extraction → pins on Mapbox map    │
└─────────────────────────────────┬───────────────────────────────┘
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  2. CLUSTER                                                      │
│     Photos grouped by proximity/time → user names clusters      │
│     Clusters become candidate locations                         │
└─────────────────────────────────┬───────────────────────────────┘
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  3. INTERVIEW                                                    │
│     For each location, Claude asks:                             │
│     - What happened here?                                        │
│     - What did you see/hear/feel?                               │
│     - Any objects of significance?                               │
│     Vision: Claude sees the photos, asks specific questions     │
└─────────────────────────────────┬───────────────────────────────┘
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  4. GENERATE                                                     │
│     Claude produces:                                             │
│     - Location descriptions (in user's voice)                   │
│     - Brief descriptions for return visits                       │
│     - Objects with examination text                              │
│     - Suggested exits based on chronology                        │
└─────────────────────────────────┬───────────────────────────────┘
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  5. REFINE                                                       │
│     User reviews in Studio editor                                │
│     Edit descriptions, adjust exits, add sensors                 │
│     Playtest and iterate                                         │
└─────────────────────────────────┬───────────────────────────────┘
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  6. PUBLISH                                                      │
│     Set visibility: private / unlisted / public                 │
│     Share link: macroscope.nexus/palace/[slug]                  │
└─────────────────────────────────────────────────────────────────┘
```

### 6.3 EXIF Extraction

PHP's `exif_read_data()` extracts:

- GPS coordinates (latitude, longitude)
- Timestamp (date taken)
- Camera/device info
- Orientation

Photos without GPS data can be manually placed on the map.

### 6.4 Claude Integration

The wizard maintains a conversation with Claude via API:

```json
{
  "model": "claude-sonnet-4-20250514",
  "max_tokens": 4096,
  "system": "You are helping create a Memory Palace...",
  "messages": [
    {
      "role": "user", 
      "content": [
        {"type": "image", "source": {"type": "base64", "data": "..."}},
        {"type": "text", "text": "This is stop 3: Lime Kiln Point..."}
      ]
    }
  ]
}
```

### 6.5 Privacy Considerations

- Photos are processed server-side, not sent to external services except Claude API
- Users can exclude photos from AI processing
- EXIF stripping option before storage
- Private palaces visible only to owner

---

## 7. API Endpoints

### 7.1 Palace Management

| Endpoint | Method | Function |
|----------|--------|----------|
| `/api/palace/palaces.php` | GET | List user's palaces |
| `/api/palace/palaces.php` | POST | Create new palace |
| `/api/palace/palaces.php?id=N` | PUT | Update palace |
| `/api/palace/palaces.php?id=N` | DELETE | Delete palace |

### 7.2 Game Engine

| Endpoint | Method | Function |
|----------|--------|----------|
| `/api/palace/game.php` | POST | `action=init` — Start/resume session |
| `/api/palace/game.php` | POST | `action=command` — Process player command |
| `/api/palace/game.php` | POST | `action=map` — Get map data |

### 7.3 Studio Operations

| Endpoint | Method | Function |
|----------|--------|----------|
| `/api/palace/locations.php` | GET/POST/PUT/DELETE | Location CRUD |
| `/api/palace/objects.php` | GET/POST/PUT/DELETE | Object CRUD |
| `/api/palace/upload.php` | POST | Image upload with EXIF |
| `/api/palace/wizard.php` | POST | Wizard conversation |

---

## 8. Implementation Phases

### Phase 1: Migration (Week 1-2)

- [ ] Create palace schema in Macroscope database
- [ ] Migrate NodeWorlds data to `palace_id = 1` (Canemah)
- [ ] Port game engine to `/palace/play.php`
- [ ] Port sensor resolver to use Macroscope sensor APIs
- [ ] Verify Canemah plays correctly at new location (`macroscope.nexus/palace/canemah`)
- [ ] Maintain existing demo at `michaelphamilton.com/nodeworlds/` (redirect or keep as legacy)

### Phase 2: Multi-Palace (Week 3-4)

- [ ] Palace selection interface (`/palace/index.php`)
- [ ] Create palace flow
- [ ] Palace-scoped game sessions
- [ ] Basic Studio: settings, locations, objects
- [ ] Sensor assignment UI

### Phase 3: Studio Polish (Week 5-6)

- [ ] Exits editor with visual map
- [ ] Image management
- [ ] Preview/playtest mode
- [ ] Analytics dashboard
- [ ] Public palace directory

### Phase 4: Wizard (Week 7-10)

- [ ] Photo upload with EXIF extraction
- [ ] Mapbox clustering interface
- [ ] Claude API integration
- [ ] Interview conversation flow
- [ ] Content generation pipeline
- [ ] Review and refinement workflow

### Phase 5: Launch (Week 11-12)

- [ ] Documentation
- [ ] User testing
- [ ] Performance optimization
- [ ] Public announcement

---

## 9. Technical Requirements

### 9.1 Server

- PHP 8.3+
- MySQL 8.4+
- Apache with mod_rewrite
- SSL certificate (HTTPS required)

### 9.2 External Services

| Service | Purpose | Requirement |
|---------|---------|-------------|
| Mapbox | Geographic authoring interface | API key (user-provided or platform) |
| Claude API | Wizard interview and generation | API key (platform-provided) |

### 9.3 Browser Support

- Chrome/Edge (current - 2)
- Firefox (current - 2)  
- Safari (current - 2)
- Mobile browsers (iOS Safari, Chrome Android)

---

## 10. Future Considerations

### 10.1 Potential Extensions

- **Collaborative editing** — Multiple authors on one palace
- **Branching narratives** — State-dependent descriptions
- **Time-based events** — Descriptions that change by hour/season
- **Audio integration** — Ambient soundscapes, spoken narration
- **Export formats** — Twine, Inform, ePub
- **Embedding** — Palace player as iframe widget

### 10.2 Scaling Considerations

- Image CDN for high-traffic public palaces
- Read replicas for session queries
- Rate limiting on wizard API
- Caching for sensor resolution

---

## 11. References

[1] NodeWorlds prototype (2026). Live demo: `https://michaelphamilton.com/nodeworlds/`

[2] Macroscope platform (2025-2026). `https://macroscope.nexus/`

[3] Yates, F. A. (1966). *The Art of Memory*. University of Chicago Press.

[4] Mapbox GL JS Documentation. `https://docs.mapbox.com/mapbox-gl-js/`

[5] Anthropic Claude API Documentation. `https://docs.anthropic.com/`

---

## Document History

| Version | Date | Changes |
|---------|------|---------|
| 0.1 | 2026-02-05 | Initial draft |

---

*End of Specification*