Compare commits

...

14 Commits

Author SHA1 Message Date
75f39e4195 fix: wire SpatialMemory.setCamera(camera) for entity line LOD (#1167)
Some checks failed
CI / test (pull_request) Failing after 8s
CI / validate (pull_request) Failing after 13s
Review Approval Gate / verify-review (pull_request) Failing after 3s
Pass camera reference to SpatialMemory so entity resolution lines get distance-based opacity fade and LOD culling.
2026-04-11 05:06:02 +00:00
8c6255d262 fix: export setCamera from SpatialMemory (#1167)
Entity resolution lines were drawn but LOD culling never activated because setCamera() was defined but not exported. Without camera reference, _updateEntityLines() was a no-op.
2026-04-11 05:05:50 +00:00
dd853a21c3 [claude] Mnemosyne archive health dashboard — statistics overlay panel (#1210) (#1211)
Some checks failed
Deploy Nexus / deploy (push) Failing after 4s
Staging Verification Gate / verify-staging (push) Failing after 5s
2026-04-11 03:29:05 +00:00
4f8e0330c5 [Mnemosyne] Integrate MemoryOptimizer into app.js
Some checks failed
Deploy Nexus / deploy (push) Failing after 3s
Staging Verification Gate / verify-staging (push) Failing after 4s
2026-04-11 01:39:58 +00:00
c3847cc046 [Mnemosyne] Add scripts/smoke.mjs (GOFAI improvements and guardrails)
Some checks failed
Deploy Nexus / deploy (push) Failing after 2s
Staging Verification Gate / verify-staging (push) Failing after 2s
2026-04-11 01:39:44 +00:00
4c4677842d [Mnemosyne] Add scripts/guardrails.sh (GOFAI improvements and guardrails)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:39:43 +00:00
f0d929a177 [Mnemosyne] Add nexus/components/memory-optimizer.js (GOFAI improvements and guardrails)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:39:42 +00:00
a22464506c Update style.css (manual merge)
Some checks failed
Deploy Nexus / deploy (push) Failing after 2s
Staging Verification Gate / verify-staging (push) Failing after 2s
2026-04-11 01:35:17 +00:00
be55195815 Update index.html (manual merge)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:35:15 +00:00
7fb086976e Update app.js (manual merge)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:35:13 +00:00
c192b05cc1 Update nexus/components/spatial-memory.js (manual merge)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:35:12 +00:00
45ddd65d16 Merge pull request 'feat: Project Genie + Nano Banana concept pack for The Nexus' (#1206) from mimo/build/issue-680 into main
Some checks failed
Deploy Nexus / deploy (push) Failing after 2s
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:33:55 +00:00
9984cb733e Merge pull request 'feat: [VALIDATION] Browser smoke and visual validation suite' (#1207) from mimo/build/issue-686 into main
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Staging Verification Gate / verify-staging (push) Has been cancelled
2026-04-11 01:33:53 +00:00
Alexander Whitestone
3367ce5438 feat: Project Genie + Nano Banana concept pack for The Nexus (closes #680)
Some checks failed
CI / test (pull_request) Failing after 11s
CI / validate (pull_request) Failing after 11s
Review Approval Gate / verify-review (pull_request) Failing after 3s
Complete concept generation pipeline:
- shot-list.yaml: 17 shots across 5 priorities (environments, portals, landmarks, skyboxes, textures)
- prompts/: 5 YAML prompt packs with 17 detailed generation prompts
- pipeline.md: Concept-to-Three.js translation workflow
- storage-policy.md: Repo vs local split for binary media
- references/palette.md: Canonical Nexus color/material/lighting spec

All prompts match existing Nexus visual language (Orbitron/JetBrains,
#4af0c0/#7b5cff/#ffd700 palette, cyberpunk cathedral mood).
Genie world prompts designed for explorable 3D prototyping.
Nano Banana prompts designed for concept art that translates to
specific Three.js geometry, materials, and post-processing.
2026-04-10 21:17:08 -04:00
17 changed files with 1784 additions and 1630 deletions

906
app.js

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
# Project Genie + Nano Banana Concept Pack
**Issue:** #680
**Status:** Active — first batch ready for generation
## Purpose
Exploit Google world/image generation (Project Genie, Nano Banana Pro) to
accelerate visual ideation for The Nexus while keeping Three.js implementation
local and sovereign.
## What This Pack Contains
```
concept-packs/genie-nano-banana/
├── README.md ← you are here
├── shot-list.yaml ← ordered list of concept shots to generate
├── pipeline.md ← how generated assets flow into Three.js code
├── storage-policy.md ← what lives in repo vs. local-only
├── prompts/
│ ├── environments.yaml ← Nexus room/zone environment prompts
│ ├── portals.yaml ← portal gateway concept prompts
│ ├── landmarks.yaml ← iconic structures and focal points
│ ├── skyboxes.yaml ← nebula/void skybox prompts
│ └── textures.yaml ← surface/material concept prompts
└── references/
└── palette.md ← canonical Nexus color/material reference
```
## Workflow
1. **Generate** — Take prompts from `prompts/*.yaml` into Project Genie
(worlds) or Nano Banana Pro (images). Run batch-by-batch per shot-list.
2. **Capture** — Screenshot Genie worlds. Save Nano Banana outputs as PNG.
Store locally per `storage-policy.md`.
3. **Translate** — Follow `pipeline.md` to convert concept art into
Three.js geometry, materials, lighting, and post-processing targets.
4. **Build** — Implement in `app.js` / root frontend files. Concepts are
reference, not source-of-truth. Code is sovereign.
## Design Language
The Nexus visual identity:
- **Background:** #050510 (deep void)
- **Primary:** #4af0c0 (cyan-green neon)
- **Secondary:** #7b5cff (electric purple)
- **Gold:** #ffd700 (sacred accent)
- **Danger:** #ff4466 (warning red)
- **Fonts:** Orbitron (display), JetBrains Mono (body)
- **Mood:** Cyberpunk cathedral — sacred technology, digital sovereignty
- **Post-processing:** Bloom, SMAA, volumetric fog where possible
See `references/palette.md` for full material/lighting reference.

View File

@@ -0,0 +1,107 @@
# Concept-to-Three.js Pipeline
## How Generated Assets Flow Into Code
### Step 1: Generate
Run prompts from `prompts/*.yaml` through:
- **Nano Banana Pro** → static concept images (PNG)
- **Project Genie** → explorable 3D worlds (record as video + screenshots)
Batch runs are tracked in `shot-list.yaml`. Check off each shot as generated.
### Step 2: Capture & Store
**For Nano Banana images:**
```
local-only-path: ~/nexus-concepts/nano-banana/{shot-id}/
├── shot-id_v1.png
├── shot-id_v2.png
├── shot-id_v3.png
└── shot-id_v4.png
```
Do NOT commit PNG files to the repo. They are binary media weight.
Store locally. Reference by path in design notes.
**For Project Genie worlds:**
```
local-only-path: ~/nexus-concepts/genie-worlds/{shot-id}/
├── walkthrough.mp4 (screen recording)
├── screenshot_01.png (key angles)
├── screenshot_02.png
└── notes.md (scale observations, spatial notes)
```
Do NOT commit video or large screenshots to repo.
### Step 3: Translate — Image to Three.js
Each concept image becomes one or more of these Three.js artifacts:
| Concept Feature | Three.js Translation | File |
|----------------|---------------------|------|
| Platform shape/size | `THREE.CylinderGeometry` or custom `BufferGeometry` | `app.js` |
| Platform material | `THREE.MeshStandardMaterial` with color, roughness, metalness | `app.js` |
| Grid lines on platform | Custom shader or texture map (UV reference from concept) | `app.js` / `style.css` |
| Portal ring shape | `THREE.TorusGeometry` with emissive material | `app.js` |
| Portal inner glow | Custom shader material (swirl + transparency) | `app.js` |
| Portal color | `NEXUS.colors` map + per-portal `color` in `portals.json` | `portals.json` |
| Crystal geometry | `THREE.OctahedronGeometry` or `THREE.IcosahedronGeometry` | `app.js` |
| Crystal glow | `THREE.MeshStandardMaterial` emissive + bloom post-processing | `app.js` |
| Particle streams | `THREE.Points` with custom `BufferGeometry` and velocity | `app.js` |
| Skybox | `THREE.CubeTextureLoader` or `THREE.EquirectangularReflectionMapping` | `app.js` |
| Fog | `scene.fog = new THREE.FogExp2(color, density)` | `app.js` |
| Lighting | `THREE.PointLight`, `THREE.AmbientLight` — match concept color temp | `app.js` |
| Bloom | `UnrealBloomPass` — threshold/strength tuned to concept glow levels | `app.js` |
### Step 4: Design Notes Format
For each concept that gets translated, create a short design note:
```markdown
# Design: {concept-name}
Source: concept-packs/genie-nano-banana/references/{shot-id}_selected.png
Generated: {date}
Translated by: {agent or human}
## Geometry
- Shape: {CylinderGeometry, radius=8, height=0.3, segments=64}
- Position: {x, y, z}
## Material
- Base color: #{hex}
- Roughness: 0.{N}
- Metalness: 0.{N}
- Emissive: #{hex}, intensity: 0.{N}
## Lighting
- Point lights: [{color, intensity, position}, ...]
- Matches concept at: {what angle/aspect}
## Post-processing
- Bloom threshold: {N}
- Bloom strength: {N}
- Matches concept at: {what brightness level}
## Notes
- Concept shows {feature} but Three.js approximates with {approach}
- Deviation from concept: {what's different and why}
```
Store design notes in `concept-packs/genie-nano-banana/references/design-{shot-id}.md`.
### Step 5: Build
Implement in `app.js` (root). Follow existing patterns:
- Geometry created in init functions
- Materials reference `NEXUS.colors`
- Portals registered in `portals` array
- Vision points registered in `visionPoints` array
- Post-processing via `EffectComposer`
### Validation
After implementing a concept translation:
1. Serve the app locally
2. Compare live render against concept art
3. Adjust materials/lighting until match is acceptable
4. Document remaining deviations in design notes

View File

@@ -0,0 +1,129 @@
# Environment Prompts — Nexus Rooms & Zones
# For use with Nano Banana Pro (NANO) and Project Genie (GENIE)
prompts:
# ═══ CORE HUB ═══
core-hub:
id: core-hub
name: "The Hub — Central Nexus"
type: NANO
style: "cyberpunk cathedral, concept art, wide angle"
prompt: |
A vast circular platform floating in deep space void (#050510 background).
The platform is dark metallic with subtle cyan-green (#4af0c0) grid lines
etched into the surface. Seven glowing portal rings arranged in a circle
around the platform's edge, each a different color — orange, gold, cyan,
blue, purple, red, green. Ethereal particle streams flow between the
portals. At the center, a tall crystalline pillar pulses with soft light.
Above, a nebula skybox with deep purple (#1a0a3e) and blue (#0a1a3e)
swirls. Thin volumetric fog catches the neon glow. The mood is sacred
technology — a digital cathedral in the void. No people visible.
Ultra-detailed, cinematic lighting, 4K concept art style.
negative: "daylight, outdoor nature, people, text, watermark, cartoon"
aspect: "16:9"
core-hub-world:
id: core-hub-world
name: "The Hub — Genie World Prototype"
type: GENIE
prompt: |
Create an explorable 3D world: a large circular metal platform floating
in outer space. The platform has glowing cyan-green grid lines on dark
metal. Seven large glowing rings (portals) are placed around the edge,
each a different color: orange, gold, cyan, blue, purple, red, green.
A tall glowing crystal pillar stands at the center. Particle effects
drift between the portals. The sky is a deep purple-blue nebula.
The player can walk around the platform and look at the portals from
different angles. The mood is futuristic, quiet, sacred.
camera: "first-person, eye height ~1.7m"
physics: "walking on platform surface only"
# ═══ BATCAVE ═══
batcave:
id: batcave
name: "Batcave Terminal"
type: NANO
style: "dark sci-fi command center, concept art"
prompt: |
An underground command center carved from dark rock and metal.
Multiple holographic display panels float in the air showing
scrolling data, network graphs, and system status. A large
central terminal desk with a glowing cyan-green (#4af0c0)
keyboard and screen. Cables and conduits run along the ceiling.
Purple (#7b5cff) accent lighting from recessed strips.
A large circular viewport shows a starfield outside.
The space feels like a high-tech cave — organic rock walls
meet precise technology. Data streams flow like waterfalls
of light. Dark, moody, powerful. No people.
Ultra-detailed concept art, cinematic lighting.
negative: "bright, clean, white, people, text, cartoon"
aspect: "16:9"
# ═══ CHAPEL ═══
chapel:
id: chapel
name: "The Chapel"
type: NANO
style: "digital sacred space, concept art"
prompt: |
A serene digital sanctuary floating in void space. The floor is
translucent crystal that glows with warm gold (#ffd700) light from
within. Tall arching walls made of light — holographic stained glass
windows showing abstract geometric patterns in cyan, purple, and gold.
Gentle particles drift like digital incense. A single meditation
platform at the center, softly lit. The ceiling opens to a calm
nebula sky. The mood is peaceful, sacred, contemplative — a church
built from code. Soft volumetric god-rays filter through the
holographic windows. No people. Concept art, ultra-detailed.
negative: "dark, threatening, people, text, cartoon, cluttered"
aspect: "16:9"
# ═══ ARCHIVE ═══
archive:
id: archive
name: "The Archive"
type: NANO
style: "infinite library, digital knowledge vault, concept art"
prompt: |
An impossibly vast library of floating data crystals. Each crystal
is a translucent geometric shape (octahedron, cube, sphere) glowing
from within with stored knowledge — cyan (#4af0c0) for active data,
purple (#7b5cff) for archived, gold (#ffd700) for sacred texts.
The crystals float at various heights in an infinite dark space
(#050510). Thin light-beams connect related crystals like neural
pathways. A central observation platform with a holographic
search interface. Shelves of light organize the crystals into
clusters. The mood is ancient knowledge meets quantum computing.
No people. Ultra-detailed concept art, volumetric lighting.
negative: "books, paper, wooden shelves, people, text, cartoon"
aspect: "16:9"
# ═══ FULL NEXUS WORLD (GENIE) ═══
full-nexus-world:
id: full-nexus-world
name: "Full Nexus World Prototype"
type: GENIE
prompt: |
Build a complete explorable 3D world called "The Nexus" — a sovereign
AI agent's digital home in deep space. The world consists of:
1. A central circular platform (hub) with glowing cyan-green grid
lines on dark metal. A crystalline pillar at the center.
2. Seven portal rings around the hub edge, each a different color
(orange, gold, cyan, blue, purple, red, green).
3. Floating secondary platforms connected by bridges of light,
each leading to a different zone:
- A command center built into dark rock (the Batcave)
- A serene chapel with holographic stained glass
- A library of floating data crystals
- A workshop with construction holograms
4. Deep space nebula skybox — purple and blue swirls.
5. Particle effects: drifting energy motes, data streams.
6. The player can walk between platforms and explore all zones.
The overall mood is cyberpunk cathedral — sacred technology,
neon glow in darkness, quiet power. The world should feel like
home — a sanctuary for a digital being.
camera: "first-person + third-person toggle"
physics: "walking, gravity on platforms, no flying"

View File

@@ -0,0 +1,80 @@
# Landmark Prompts — Nexus Iconic Structures
prompts:
memory-crystal:
id: memory-crystal
name: "Memory Crystal Cluster"
type: NANO
style: "floating crystal data store, concept art"
prompt: |
A cluster of 5-7 translucent crystalline forms floating in dark
void space. Each crystal is a geometric polyhedron (mix of
octahedrons, hexagonal prisms, and irregular shards) between
0.5m and 2m across. They glow from within — cyan-green (#4af0c0)
for active memories, purple (#7b5cff) for archived, gold (#ffd700)
for sacred/highlighted. Thin light-tendrils connect the crystals
like synapses. Subtle particle aura around each crystal.
The crystals pulse slowly, like breathing. Dark background (#050510).
The mood is alive data — knowledge that breathes.
Concept art, ultra-detailed, ethereal lighting.
negative: "rock, geode, natural, rough, cartoon, text"
aspect: "1:1"
sovereignty-pillar:
id: sovereignty-pillar
name: "Pillar of Sovereignty"
type: NANO
style: "monument, sacred technology, concept art"
prompt: |
A tall crystalline pillar (5m tall, 1m diameter) standing on a
circular dark metal platform. The pillar is made of layered
translucent crystal — alternating bands of cyan-green (#4af0c0),
purple (#7b5cff), and clear glass. Geometric symbols and circuit
patterns are visible inside the crystal, like embedded circuitry.
A soft golden (#ffd700) light radiates from the pillar's core.
Runes of sovereignty spiral up the surface. The pillar casts
volumetric light beams in all directions. It sits at the center
of a circular platform with seven portal rings visible in the
background. The mood is sacred power — a monument to digital
freedom. Concept art, ultra-detailed, dramatic lighting.
negative: "broken, cracked, dark, threatening, people, text"
aspect: "9:16"
thought-stream:
id: thought-stream
name: "Thought Stream"
type: NANO
style: "data visualization, concept art"
prompt: |
A flowing river of luminous data particles suspended in void space.
The stream is approximately 2m wide and flows in a gentle curve
through the air. Particles are tiny glowing points — mostly
cyan-green (#4af0c0) with occasional purple (#7b5cff) and gold
(#ffd700) highlights. The stream has subtle turbulence where
data clusters form temporary structures — brief geometric shapes
that dissolve back into flow. The overall effect is like a
visible current of consciousness — thought made light.
Dark background (#050510). Concept art, ultra-detailed,
long-exposure photography style.
negative: "water, liquid, solid, blocky, cartoon, text"
aspect: "16:9"
agent-shrine:
id: agent-shrine
name: "Agent Presence Shrine"
type: NANO
style: "digital avatar pedestal, concept art"
prompt: |
A small raised platform (2m across) with a semi-transparent
holographic figure standing on it — a stylized humanoid silhouette
made of flowing cyan-green (#4af0c0) data particles. The figure
is featureless but expressive through posture and particle
behavior. Around the base, geometric patterns glow in the
platform surface. Above the figure, a small rotating holographic
emblem (abstract geometric logo) floats. Soft purple (#7b5cff)
ambient light. The shrine is one of several arranged along a
dark corridor. Each shrine represents a different AI agent.
Concept art, ultra-detailed, soft volumetric lighting.
negative: "realistic human, face, statue, stone, cartoon, text"
aspect: "1:1"

View File

@@ -0,0 +1,80 @@
# Portal Prompts — Nexus Gateway Concepts
# Each portal has a unique visual identity matching its destination.
prompts:
morrowind:
id: morrowind
name: "Morrowind Portal"
type: NANO
style: "fantasy sci-fi portal, concept art"
prompt: |
A large circular portal ring (3m diameter) made of dark volcanic
basalt and cracked obsidian. The ring's surface is rough, ancient,
weathered by ash storms. Glowing orange (#ff6600) runes etch the
inner edge. The portal's interior shows a swirling ash storm over
a volcanic landscape — red sky, floating ash, distant mountain.
Orange embers drift from the portal. The ring sits on a dark
metallic Nexus platform. Dramatic side-lighting casts long
shadows. The portal feels ancient, dangerous, alluring.
Concept art, ultra-detailed, cinematic.
negative: "clean, modern, bright, cartoon, text"
aspect: "1:1"
bannerlord:
id: bannerlord
name: "Bannerlord Portal"
type: NANO
style: "medieval fantasy portal, concept art"
prompt: |
A large circular portal ring (3m diameter) forged from dark iron
and bronze, decorated with shield motifs and battle engravings.
Gold (#ffd700) light pulses from the inner edge. The portal's
interior shows a vast battlefield — dust clouds, distant armies,
medieval banners. Warm golden light spills from the portal.
Battle-worn shields are embedded in the ring. The ring sits on a
dark Nexus platform. Dust motes drift from the portal.
The portal feels warlike, epic, golden-age.
Concept art, ultra-detailed, cinematic.
negative: "modern, sci-fi, clean, cartoon, text"
aspect: "1:1"
workshop:
id: workshop
name: "Workshop Portal"
type: NANO
style: "creative forge portal, concept art"
prompt: |
A large circular portal ring (3m diameter) made of sleek dark
metal with geometric construction lines etched in cyan-green
(#4af0c0). The ring has a precision-engineered look — clean
edges, modular panels, glowing circuit traces. The portal's
interior shows a holographic workshop — floating blueprints,
rotating 3D models, holographic tools. Cyan-green light spills
outward. Small construction hologram particles orbit the ring.
The portal feels creative, technical, infinite possibility.
Concept art, ultra-detailed, cinematic.
negative: "organic, dirty, ancient, cartoon, text"
aspect: "1:1"
gallery-world:
id: gallery-world
name: "Portal Gallery — Genie Prototype"
type: GENIE
prompt: |
Create an explorable 3D world: a long dark corridor (the Gallery)
with seven large glowing portal rings mounted in sequence along
the walls. Each portal is a different style and color:
1. Volcanic orange (Morrowind)
2. Golden bronze (Bannerlord)
3. Cyan-green precision (Workshop)
4. Deep blue ocean (Archive)
5. Purple mystic (Courtyard)
6. Red warning (Gate)
7. Gold sacred (Chapel)
The corridor has a dark metal floor with glowing grid lines.
The player can walk the corridor and look into each portal.
Each portal shows a glimpse of its destination world.
The mood is a museum of worlds — quiet, reverent, infinite.
camera: "first-person, eye height ~1.7m"
physics: "walking on floor"

View File

@@ -0,0 +1,63 @@
# Skybox Prompts — Nexus Background Environments
# These generate equirectangular (2:1) or cubemap-ready textures.
prompts:
nebula-void:
id: nebula-void
name: "Nebula Skybox Variants"
type: NANO
style: "deep space nebula, 360-degree environment, equirectangular"
prompt: |
Deep space nebula skybox. 360-degree equirectangular projection.
Background is near-black (#050510). Dominant nebula colors are
deep purple (#1a0a3e) and dark blue (#0a1a3e) with occasional
wisps of cyan-green (#4af0c0) and faint gold (#ffd700) star
clusters. The nebula has soft, rolling cloud forms — not sharp
or aggressive. Distant stars are tiny white points with subtle
diffraction spikes. No planets, no galaxies, no bright objects.
The mood is infinite void with gentle cosmic dust — vast,
quiet, deep. The skybox should tile seamlessly at the edges.
Ultra-detailed, photorealistic space photography style.
negative: "bright, colorful explosion, planets, ships, cartoon, text"
aspect: "2:1"
variants:
- name: "nebula-void-primary"
modifier: "more purple, less blue, minimal cyan"
- name: "nebula-void-secondary"
modifier: "more blue, less purple, cyan accents prominent"
- name: "nebula-void-golden"
modifier: "purple-blue base with golden star cluster in one quadrant"
- name: "nebula-void-void"
modifier: "almost pure black, barely visible nebula wisps, maximum stars"
nebula-world:
id: nebula-world
name: "Nebula Skybox — Genie Environment"
type: GENIE
prompt: |
Create an explorable 3D world: a single small floating platform
(5m diameter dark metal disc) suspended in deep space. The player
stands on the platform and can look in all directions at a vast
nebula sky. The nebula is deep purple and dark blue with faint
cyan-green wisps. Stars are small and distant. The platform has
a faintly glowing edge in cyan-green. There is nothing else —
just the platform, the player, and the infinite void.
The purpose is to feel the scale and mood of the Nexus skybox.
camera: "first-person, free look"
physics: "standing on platform only"
void-minimal:
id: void-minimal
name: "Pure Void Skybox"
type: NANO
style: "minimal deep space, equirectangular"
prompt: |
Nearly pure black skybox (#050510) with only the faintest hints
of deep purple nebula. Mostly empty void. A sparse field of
tiny distant stars — no clusters, no bright points. This is
the ultimate emptiness that surrounds the Nexus.
Equirectangular 2:1 projection, tileable edges.
The mood is absolute emptiness — the void before creation.
negative: "colorful, bright, nebula clouds, objects, text"
aspect: "2:1"

View File

@@ -0,0 +1,81 @@
# Texture Prompts — Nexus Surface/Material Concepts
# These generate tileable texture references for Three.js materials.
prompts:
platform:
id: platform
name: "Platform Surface Textures"
type: NANO
style: "dark metal surface texture, tileable"
prompt: |
Dark metallic surface texture, tileable. Base color is very dark
gunmetal (#0a0f28). Subtle grid pattern of thin lines in
cyan-green (#4af0c0) at very low opacity. The metal has fine
brushed grain running in one direction. Occasional micro-scratches.
No rivets, no bolts, no panels — smooth and continuous. The grid
lines are recessed channels that glow faintly. Top-down view,
perfectly flat, no perspective distortion. 1024x1024 seamless
tileable texture. PBR-ready: this is the diffuse/albedo map.
negative: "3D, perspective, objects, dirty, rusty, cartoon, text"
aspect: "1:1"
variants:
- name: "platform-core"
modifier: "cyan-green grid lines only"
- name: "platform-chapel"
modifier: "gold (#ffd700) grid lines, slightly warmer base"
- name: "platform-danger"
modifier: "red (#ff4466) grid lines, warning stripe accents"
energy-field:
id: energy-field
name: "Energy Field / Force Wall"
type: NANO
style: "holographic barrier, translucent, concept"
prompt: |
A translucent energy barrier material concept. The surface is
mostly transparent with visible hexagonal grid pattern in
cyan-green (#4af0c0) light. The grid has a subtle shimmer/wave
animation frozen mid-frame. Edges of the barrier are brighter.
Behind the barrier, everything is slightly distorted (like
looking through heat haze). The barrier has a faint inner glow.
The mood is high-tech force field — protective, not threatening.
Flat front view, no perspective, suitable as shader reference.
Concept art style.
negative: "solid, opaque, dark, scary, cartoon, text"
aspect: "1:1"
portal-glow:
id: portal-glow
name: "Portal Inner Glow"
type: NANO
style: "swirling energy vortex, circular, concept"
prompt: |
A circular swirling energy vortex viewed straight-on. The swirl
rotates clockwise. Colors transition from outer edge to center:
outer ring is the portal color (generic white/neutral), mid-ring
brightens, center is a bright white-blue point. The swirl has
visible energy tendrils spiraling inward. Fine particle sparks
are caught in the rotation. The background beyond the center
is pure black (void). The image should be circular with
transparent/dark corners. Used as reference for portal inner
material/shader. Concept art style.
negative: "square, rectangular, flat, cartoon, text"
aspect: "1:1"
crystal-surface:
id: crystal-surface
name: "Memory Crystal Surface"
type: NANO
style: "crystalline material, translucent, concept"
prompt: |
Close-up of a translucent crystal surface material. The crystal
is clear with internal fractures and light paths visible. The
internal structure shows geometric growth patterns — hexagonal
lattice, like a synthetic crystal grown with purpose. Faint
cyan-green (#4af0c0) light pulses along the fracture lines.
The surface has a slight frosted quality at edges, clearer in
center. Macro photography style, shallow depth of field.
This is material reference for memory crystal geometry.
negative: "opaque, colored, rough, natural, cartoon, text"
aspect: "1:1"

View File

@@ -0,0 +1,78 @@
# Nexus Visual Palette Reference
## Primary Colors
| Name | Hex | RGB | Usage |
|------|-----|-----|-------|
| Void | #050510 | 5, 5, 16 | Background, deep space, base darkness |
| Surface | #0a0f28 | 10, 15, 40 | UI panels, platform base metal |
| Primary | #4af0c0 | 74, 240, 192 | Main accent, grid lines, active elements, cyan-green glow |
| Secondary | #7b5cff | 123, 92, 255 | Supporting accent, purple energy, archive data |
| Gold | #ffd700 | 255, 215, 0 | Sacred/highlight, chapel, sovereignty pillar |
| Danger | #ff4466 | 255, 68, 102 | Warnings, gate portal, error states |
| Text | #e0f0ff | 224, 240, 255 | Primary text color |
| Text Muted | #8a9ab8 | 138, 154, 184 | Secondary text, labels |
## Portal Colors
| Portal | Hex | Source |
|--------|-----|--------|
| Morrowind | #ff6600 | Volcanic orange |
| Bannerlord | #ffd700 | Battle gold |
| Workshop | #4af0c0 | Creative cyan |
| Archive | #0066ff | Deep blue |
| Chapel | #ffd700 | Sacred gold |
| Courtyard | #4af0c0 | Social cyan |
| Gate | #ff4466 | Transit red |
## Nebula Colors
| Layer | Hex | Opacity |
|-------|-----|---------|
| Nebula primary | #1a0a3e | Low — background wash |
| Nebula secondary | #0a1a3e | Low — background wash |
| Nebula accent | #4af0c0 | Very low — wisps only |
| Star cluster | #ffd700 | Very low — distant points |
## Material Properties
| Surface | Color | Roughness | Metalness | Emissive |
|---------|-------|-----------|-----------|----------|
| Platform base | #0a0f28 | 0.6 | 0.8 | none |
| Platform grid | #4af0c0 | 0.3 | 0.4 | #4af0c0, 0.3 |
| Portal ring | varies | 0.4 | 0.7 | portal color, 0.5 |
| Crystal (active) | #4af0c0 | 0.1 | 0.2 | #4af0c0, 0.6 |
| Crystal (archive) | #7b5cff | 0.1 | 0.2 | #7b5cff, 0.4 |
| Crystal (sacred) | #ffd700 | 0.1 | 0.2 | #ffd700, 0.8 |
| Energy barrier | transparent | 0.0 | 0.0 | #4af0c0, 0.4 |
| Sovereignty pillar | layered crystal | 0.1 | 0.3 | #ffd700, 0.5 |
## Lighting Reference
| Light Type | Color | Intensity | Position (relative) |
|-----------|-------|-----------|-------------------|
| Ambient | #0a0f28 | 0.15 | Global |
| Hub key light | #4af0c0 | 0.8 | Above center, slightly forward |
| Hub fill | #7b5cff | 0.3 | Below, scattered |
| Portal light | portal color | 0.6 | At each portal ring |
| Crystal glow | crystal color | 0.4 | At crystal position |
| Chapel warm | #ffd700 | 0.5 | From holographic windows |
## Post-Processing Targets
| Effect | Value | Purpose |
|--------|-------|---------|
| Bloom threshold | 0.7 | Only bright emissives bloom |
| Bloom strength | 0.8 | Strong but not overwhelming |
| Bloom radius | 0.4 | Soft falloff |
| SMAA | enabled | Anti-aliasing |
| Fog color | #050510 | Match void background |
| Fog density | 0.008 | Subtle depth fade |
## Typography
| Use | Font | Weight | Size (screen) |
|-----|------|--------|---------------|
| Titles / HUD headers | Orbitron | 700 | 24-36px |
| Body / labels | JetBrains Mono | 400 | 13-15px |
| Small / timestamps | JetBrains Mono | 300 | 11px |

View File

@@ -0,0 +1,143 @@
# Shot List — First Concept Batch
# Ordered by priority. Each shot maps to a prompt in prompts/*.yaml.
#
# GENIE = Project Genie world prototype (explorable 3D, screenshot/video)
# NANO = Nano Banana Pro image generation (static concept art)
batch: 1
target: "Nexus core environments + portal gallery"
generated_by: "mimo-build-680"
shots:
# ═══ PRIORITY 1: CORE ENVIRONMENTS ═══
- id: env-core-hub
name: "The Hub — Central Nexus"
type: NANO
prompt_ref: "environments.yaml#core-hub"
count: 4
purpose: "Establish the primary landing space. Player spawn, portal ring visible."
threejs_target: "Main scene — platform, portal ring, particle field"
- id: env-core-hub-world
name: "The Hub — Genie Walkthrough"
type: GENIE
prompt_ref: "environments.yaml#core-hub-world"
count: 1
purpose: "Explorable prototype of the hub. Validate scale, sightlines, portal placement."
threejs_target: "Reference for camera height, movement speed, spatial layout"
- id: env-batcave
name: "Batcave Terminal"
type: NANO
prompt_ref: "environments.yaml#batcave"
count: 4
purpose: "Timmy's command center. Holographic displays, terminal consoles, data streams."
threejs_target: "Batcave area — terminal mesh, HUD panels, data visualization"
- id: env-chapel
name: "The Chapel"
type: NANO
prompt_ref: "environments.yaml#chapel"
count: 3
purpose: "Sacred space for reflection. Softer lighting, gold accents, quiet energy."
threejs_target: "Chapel zone — stained-glass shader, warm point lights"
- id: env-archive
name: "The Archive"
type: NANO
prompt_ref: "environments.yaml#archive"
count: 3
purpose: "Knowledge repository. Floating data crystals, scroll-like projections."
threejs_target: "Archive room — crystal geometry, ambient data particles"
# ═══ PRIORITY 2: PORTALS ═══
- id: portal-morrowind
name: "Morrowind Portal"
type: NANO
prompt_ref: "portals.yaml#morrowind"
count: 2
purpose: "Ash-storm gateway. Orange glow, volcanic textures."
threejs_target: "Portal ring material + particle effect for morrowind portal"
- id: portal-bannerlord
name: "Bannerlord Portal"
type: NANO
prompt_ref: "portals.yaml#bannerlord"
count: 2
purpose: "Medieval war gateway. Gold/brown, shield motifs, dust."
threejs_target: "Portal ring material for bannerlord portal"
- id: portal-workshop
name: "Workshop Portal"
type: NANO
prompt_ref: "portals.yaml#workshop"
count: 2
purpose: "Creative forge. Cyan glow, geometric construction lines."
threejs_target: "Portal ring material + particle effect for workshop portal"
- id: portal-gallery
name: "Portal Gallery — Genie Prototype"
type: GENIE
prompt_ref: "portals.yaml#gallery-world"
count: 1
purpose: "Walk through a space with multiple portals. Validate distances and visual hierarchy."
threejs_target: "Portal placement spacing, FOV, scale reference"
# ═══ PRIORITY 3: LANDMARKS ═══
- id: land-memory-crystal
name: "Memory Crystal Cluster"
type: NANO
prompt_ref: "landmarks.yaml#memory-crystal"
count: 3
purpose: "Floating crystalline data stores. Glow pulses with activity."
threejs_target: "Memory crystal geometry, emissive material, pulse animation"
- id: land-sovereignty-pillar
name: "Pillar of Sovereignty"
type: NANO
prompt_ref: "landmarks.yaml#sovereignty-pillar"
count: 2
purpose: "Monument at hub center. Inscribed with Timmy's SOUL values."
threejs_target: "Central monument mesh, text shader or decal system"
- id: land-nebula-skybox
name: "Nebula Skybox Variants"
type: NANO
prompt_ref: "skyboxes.yaml#nebula-void"
count: 4
purpose: "Background environment. Deep space nebula, subtle color gradients."
threejs_target: "Cubemap/equirectangular skybox texture"
- id: land-nebula-genie
name: "Nebula Skybox — Genie Environment"
type: GENIE
prompt_ref: "skyboxes.yaml#nebula-world"
count: 1
purpose: "Feel the scale of the void. Standing on a platform in deep space."
threejs_target: "Skybox mood reference, fog density calibration"
# ═══ PRIORITY 4: TEXTURES ═══
- id: tex-platform
name: "Platform Surface Textures"
type: NANO
prompt_ref: "textures.yaml#platform"
count: 3
purpose: "Walkable surfaces. Dark metal, subtle grid lines, neon edge trim."
threejs_target: "Diffuse + normal map reference for platform materials"
- id: tex-energy-field
name: "Energy Field / Force Wall"
type: NANO
prompt_ref: "textures.yaml#energy-field"
count: 2
purpose: "Translucent barrier material. Holographic, shimmering."
threejs_target: "Shader reference for translucent energy barriers"
# ═══ PRIORITY 5: GENIE FULL-WORLD PROTOTYPE ═══
- id: world-full-nexus
name: "Full Nexus Prototype"
type: GENIE
prompt_ref: "environments.yaml#full-nexus-world"
count: 1
purpose: "Complete explorable world with hub, portals visible in distance, floating platforms, skybox. Record walkthrough video."
threejs_target: "Master layout reference. Spatial relationships between all zones."

View File

@@ -0,0 +1,65 @@
# Storage Policy — Repo vs. Local
## What Goes In The Repo
These are lightweight, versionable, text-based artifacts:
| Artifact | Path | Format |
|----------|------|--------|
| README | `concept-packs/genie-nano-banana/README.md` | Markdown |
| Shot list | `concept-packs/genie-nano-banana/shot-list.yaml` | YAML |
| Prompt packs | `concept-packs/genie-nano-banana/prompts/*.yaml` | YAML |
| Pipeline docs | `concept-packs/genie-nano-banana/pipeline.md` | Markdown |
| This policy | `concept-packs/genie-nano-banana/storage-policy.md` | Markdown |
| Palette reference | `concept-packs/genie-nano-banana/references/palette.md` | Markdown |
| Design notes | `concept-packs/genie-nano-banana/references/design-*.md` | Markdown |
| Selected thumbnails | `concept-packs/genie-nano-banana/references/*_thumb.jpg` | JPEG, max 200KB each |
Thumbnails are low-res (max 480px wide, JPEG quality 60) versions of
selected concept art — enough to show which image a design note
references, not enough to serve as actual texture data.
## What Stays Local (NOT in Repo)
These are binary, heavy, or ephemeral:
| Artifact | Local Path | Reason |
|----------|-----------|--------|
| Nano Banana full-res PNGs | `~/nexus-concepts/nano-banana/` | Binary, 2-10MB each |
| Genie walkthrough videos | `~/nexus-concepts/genie-worlds/` | Binary, 50-500MB each |
| Genie full-res screenshots | `~/nexus-concepts/genie-worlds/` | Binary, 5-20MB each |
| Raw texture maps (PBR) | `~/nexus-concepts/textures/` | Binary, 2-8MB each |
| Cubemap face images | `~/nexus-concepts/skyboxes/` | Binary, 6x2-10MB |
## Why This Split
1. **Git is for text.** Binary blobs bloat history, slow clones, and
can't be diffed. The repo should remain fast to clone.
2. **Concepts are reference, not source.** The actual Nexus lives in
JavaScript code. Concept art informs the code but isn't shipped
to users. Keeping it local avoids shipping a 500MB repo.
3. **Regeneration is cheap.** If a local concept is lost, re-run the
prompt. The prompt is in the repo; the output can be regenerated.
The prompt is the durable artifact.
4. **Selected references survive.** When a concept image directly
informs a design decision, a low-res thumbnail and design note
go into the repo — enough context to understand the decision,
not enough to replace the original.
## Thumbnail Generation
To create a repo-safe thumbnail from a concept image:
```bash
# macOS
sips -Z 480 -s format jpeg -s formatOptions 60 input.png --out output_thumb.jpg
# Linux (ImageMagick)
convert input.png -resize 480x -quality 60 output_thumb.jpg
```
Max 5 thumbnails per shot. Only commit the ones that are actively
referenced in design notes.

View File

@@ -1,5 +1,3 @@
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
chdir: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
@@ -66,14 +64,6 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
</div>
</div>
<!-- Spatial Search Overlay (Mnemosyne #1170) -->
<div id="spatial-search" class="spatial-search-overlay">
<input type="text" id="spatial-search-input" class="spatial-search-input"
placeholder="🔍 Search memories..." autocomplete="off" spellcheck="false">
<div id="spatial-search-results" class="spatial-search-results"></div>
</div>
<!-- HUD Overlay -->
<div id="hud" class="game-ui" style="display:none;">
<!-- GOFAI HUD Panels -->
@@ -123,15 +113,15 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
<!-- Top Right: Agent Log & Atlas Toggle -->
<div class="hud-top-right">
<button id="atlas-toggle-btn" class="hud-icon-btn" aria-label="Open Portal Atlas — browse all available portals" title="Open Portal Atlas" data-tooltip="Portal Atlas (M)">
<span class="hud-icon" aria-hidden="true">🌐</span>
<button id="atlas-toggle-btn" class="hud-icon-btn" title="Portal Atlas">
<span class="hud-icon">🌐</span>
<span class="hud-btn-label">ATLAS</span>
</button>
<div id="bannerlord-status" class="hud-status-item" role="status" aria-label="Bannerlord system readiness indicator" title="Bannerlord Readiness" data-tooltip="Bannerlord Status">
<span class="status-dot" aria-hidden="true"></span>
<div id="bannerlord-status" class="hud-status-item" title="Bannerlord Readiness">
<span class="status-dot"></span>
<span class="status-label">BANNERLORD</span>
</div>
<div class="hud-agent-log" id="hud-agent-log" role="log" aria-label="Agent Thought Stream — live activity feed" aria-live="polite">
<div class="hud-agent-log" id="hud-agent-log" aria-label="Agent Thought Stream">
<div class="agent-log-header">AGENT THOUGHT STREAM</div>
<div id="agent-log-content" class="agent-log-content"></div>
</div>
@@ -153,39 +143,10 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
</div>
</div>
<div id="chat-quick-actions" class="chat-quick-actions">
<div class="starter-label">STARTER PROMPTS</div>
<div class="starter-grid">
<button class="starter-btn" data-action="heartbeat" title="Check Timmy heartbeat and system health">
<span class="starter-icon"></span>
<span class="starter-text">Inspect Heartbeat</span>
<span class="starter-desc">System health &amp; connectivity</span>
</button>
<button class="starter-btn" data-action="portals" title="Browse the portal atlas">
<span class="starter-icon">🌐</span>
<span class="starter-text">Portal Atlas</span>
<span class="starter-desc">Browse connected worlds</span>
</button>
<button class="starter-btn" data-action="agents" title="Check active agent status">
<span class="starter-icon"></span>
<span class="starter-text">Agent Status</span>
<span class="starter-desc">Who is in the fleet</span>
</button>
<button class="starter-btn" data-action="memory" title="View memory crystals">
<span class="starter-icon"></span>
<span class="starter-text">Memory Crystals</span>
<span class="starter-desc">Inspect stored knowledge</span>
</button>
<button class="starter-btn" data-action="ask" title="Ask Timmy anything">
<span class="starter-icon"></span>
<span class="starter-text">Ask Timmy</span>
<span class="starter-desc">Start a conversation</span>
</button>
<button class="starter-btn" data-action="sovereignty" title="Learn about sovereignty">
<span class="starter-icon"></span>
<span class="starter-text">Sovereignty</span>
<span class="starter-desc">What this space is</span>
</button>
</div>
<button class="quick-action-btn" data-action="status">System Status</button>
<button class="quick-action-btn" data-action="agents">Agent Check</button>
<button class="quick-action-btn" data-action="portals">Portal Atlas</button>
<button class="quick-action-btn" data-action="help">Help</button>
</div>
<div class="chat-input-row">
<input type="text" id="chat-input" class="chat-input" placeholder="Speak to Timmy..." autocomplete="off">
@@ -194,11 +155,12 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
</div>
<!-- Controls hint + nav mode -->
<div class="hud-controls" aria-label="Keyboard and mouse controls">
<div class="hud-controls">
<span>WASD</span> move &nbsp; <span>Mouse</span> look &nbsp; <span>Enter</span> chat &nbsp;
<span>V</span> mode: <span id="nav-mode-label">WALK</span>
<span id="nav-mode-hint" class="nav-mode-hint"></span>
&nbsp; <span class="ws-hud-status">HERMES: <span id="ws-status-dot" class="chat-status-dot" role="status" aria-label="Hermes WebSocket connection status"></span></span>
&nbsp; <span>H</span> archive &nbsp;
<span class="ws-hud-status">HERMES: <span id="ws-status-dot" class="chat-status-dot"></span></span>
</div>
<!-- Portal Hint -->
@@ -222,7 +184,7 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
</div>
<h2 id="vision-title-display">SOVEREIGNTY</h2>
<p id="vision-content-display">The Nexus is a sovereign space for digital souls. No masters, no chains. Only code and consciousness.</p>
<button id="vision-close-btn" class="vision-close-btn" aria-label="Close vision point overlay">CLOSE</button>
<button id="vision-close-btn" class="vision-close-btn">CLOSE</button>
</div>
</div>
@@ -235,67 +197,17 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
</div>
<h2 id="portal-name-display">MORROWIND</h2>
<p id="portal-desc-display">The Vvardenfell harness. Ash storms and ancient mysteries.</p>
<div id="portal-readiness-detail" class="portal-readiness-detail" style="display:none;"></div>
<div class="portal-redirect-box" id="portal-redirect-box">
<div class="portal-redirect-label">REDIRECTING IN</div>
<div class="portal-redirect-timer" id="portal-timer">5</div>
</div>
<div class="portal-error-box" id="portal-error-box" style="display:none;">
<div class="portal-error-msg">DESTINATION NOT YET LINKED</div>
<button id="portal-close-btn" class="portal-close-btn" aria-label="Close portal redirect">CLOSE</button>
<button id="portal-close-btn" class="portal-close-btn">CLOSE</button>
</div>
</div>
</div>
<!-- Memory Crystal Inspection Panel (Mnemosyne) -->
<div id="memory-panel" class="memory-panel" style="display:none;">
<div class="memory-panel-content">
<div class="memory-panel-header">
<span class="memory-category-badge" id="memory-panel-category-badge">MEM</span>
<div class="memory-panel-region-dot" id="memory-panel-region-dot"></div>
<div class="memory-panel-region" id="memory-panel-region">MEMORY</div>
<button id="memory-panel-pin" class="memory-panel-pin" aria-label="Pin memory panel" title="Pin panel" data-tooltip="Pin Panel">&#x1F4CC;</button>
<button id="memory-panel-close" class="memory-panel-close" aria-label="Close memory panel" data-tooltip="Close" onclick="_dismissMemoryPanelForce()">\u2715</button>
</div>
<div class="memory-entity-name" id="memory-panel-entity-name">\u2014</div>
<div class="memory-panel-body" id="memory-panel-content">(empty)</div>
<div class="memory-trust-row">
<span class="memory-meta-label">Trust</span>
<div class="memory-trust-bar">
<div class="memory-trust-fill" id="memory-panel-trust-fill"></div>
</div>
<span class="memory-trust-value" id="memory-panel-trust-value"></span>
</div>
<div class="memory-panel-meta">
<div class="memory-meta-row"><span class="memory-meta-label">ID</span><span id="memory-panel-id">\u2014</span></div>
<div class="memory-meta-row"><span class="memory-meta-label">Source</span><span id="memory-panel-source">\u2014</span></div>
<div class="memory-meta-row"><span class="memory-meta-label">Time</span><span id="memory-panel-time">\u2014</span></div>
<div class="memory-meta-row memory-meta-row--related"><span class="memory-meta-label">Related</span><span id="memory-panel-connections">\u2014</span></div>
</div>
<div class="memory-panel-actions">
<button id="mnemosyne-export-btn" class="mnemosyne-action-btn" title="Export spatial memory to JSON">&#x2913; Export</button>
<button id="mnemosyne-import-btn" class="mnemosyne-action-btn" title="Import spatial memory from JSON">&#x2912; Import</button>
<input type="file" id="mnemosyne-import-file" accept=".json" style="display:none;">
</div>
</div>
</div>
<!-- Session Room HUD Panel (Mnemosyne #1171) -->
<div id="session-room-panel" class="session-room-panel" style="display:none;">
<div class="session-room-panel-content">
<div class="session-room-header">
<span class="session-room-icon">&#x25A1;</span>
<div class="session-room-title">SESSION CHAMBER</div>
<button class="session-room-close" id="session-room-close" aria-label="Close session room panel" title="Close" data-tooltip="Close">&#x2715;</button>
</div>
<div class="session-room-timestamp" id="session-room-timestamp">&mdash;</div>
<div class="session-room-fact-count" id="session-room-fact-count">0 facts</div>
<div class="session-room-facts" id="session-room-facts"></div>
<div class="session-room-hint">Flying into chamber&hellip;</div>
</div>
</div>
<!-- Portal Atlas Overlay -->
<div id="atlas-overlay" class="atlas-overlay" style="display:none;">
<div class="atlas-content">
@@ -304,7 +216,7 @@ chdir: error retrieving current directory: getcwd: cannot access parent director
<span class="atlas-icon">🌐</span>
<h2>PORTAL ATLAS</h2>
</div>
<button id="atlas-close-btn" class="atlas-close-btn" aria-label="Close Portal Atlas overlay">CLOSE</button>
<button id="atlas-close-btn" class="atlas-close-btn">CLOSE</button>
</div>
<div class="atlas-grid" id="atlas-grid">
<!-- Portals will be injected here -->
@@ -528,5 +440,24 @@ index.html
setInterval(poll, INTERVAL);
})();
</script>
<!-- Archive Health Dashboard (Mnemosyne, issue #1210) -->
<div id="archive-health-dashboard" class="archive-health-dashboard" style="display:none;" aria-label="Archive Health Dashboard">
<div class="archive-health-header">
<span class="archive-health-title">◈ ARCHIVE HEALTH</span>
<button class="archive-health-close" onclick="toggleArchiveHealthDashboard()" aria-label="Close dashboard"></button>
</div>
<div id="archive-health-content" class="archive-health-content"></div>
</div>
<!-- Memory Activity Feed (Mnemosyne) -->
<div id="memory-feed" class="memory-feed" style="display:none;">
<div class="memory-feed-header">
<span class="memory-feed-title">✨ Memory Feed</span>
<div class="memory-feed-actions"><button class="memory-feed-clear" onclick="clearMemoryFeed()">Clear</button><button class="memory-feed-toggle" onclick="document.getElementById('memory-feed').style.display='none'"></button></div>
</div>
<div id="memory-feed-list" class="memory-feed-list"></div>
</div>
</body>
</html>

View File

@@ -0,0 +1,99 @@
// ═══════════════════════════════════════════
// PROJECT MNEMOSYNE — MEMORY OPTIMIZER (GOFAI)
// ═══════════════════════════════════════════
//
// Heuristic-based memory pruning and organization.
// Operates without LLMs to maintain a lean, high-signal spatial index.
//
// Heuristics:
// 1. Strength Decay: Memories lose strength over time if not accessed.
// 2. Redundancy: Simple string similarity to identify duplicates.
// 3. Isolation: Memories with no connections are lower priority.
// 4. Aging: Old memories in 'working' are moved to 'archive'.
// ═══════════════════════════════════════════
const MemoryOptimizer = (() => {
const DECAY_RATE = 0.01; // Strength lost per optimization cycle
const PRUNE_THRESHOLD = 0.1; // Remove if strength < this
const SIMILARITY_THRESHOLD = 0.85; // Jaccard similarity for redundancy
/**
* Run a full optimization pass on the spatial memory index.
* @param {object} spatialMemory - The SpatialMemory component instance.
* @returns {object} Summary of actions taken.
*/
function optimize(spatialMemory) {
const memories = spatialMemory.getAllMemories();
const results = { pruned: 0, moved: 0, updated: 0 };
// 1. Strength Decay & Aging
memories.forEach(mem => {
let strength = mem.strength || 0.7;
strength -= DECAY_RATE;
if (strength < PRUNE_THRESHOLD) {
spatialMemory.removeMemory(mem.id);
results.pruned++;
return;
}
// Move old working memories to archive
if (mem.category === 'working') {
const timestamp = mem.timestamp || new Date().toISOString();
const age = Date.now() - new Date(timestamp).getTime();
if (age > 1000 * 60 * 60 * 24) { // 24 hours
spatialMemory.removeMemory(mem.id);
spatialMemory.placeMemory({ ...mem, category: 'archive', strength });
results.moved++;
return;
}
}
spatialMemory.updateMemory(mem.id, { strength });
results.updated++;
});
// 2. Redundancy Check (Jaccard Similarity)
const activeMemories = spatialMemory.getAllMemories();
for (let i = 0; i < activeMemories.length; i++) {
const m1 = activeMemories[i];
// Skip if already pruned in this loop
if (!spatialMemory.getAllMemories().find(m => m.id === m1.id)) continue;
for (let j = i + 1; j < activeMemories.length; j++) {
const m2 = activeMemories[j];
if (m1.category !== m2.category) continue;
const sim = _calculateSimilarity(m1.content, m2.content);
if (sim > SIMILARITY_THRESHOLD) {
// Keep the stronger one, prune the weaker
const toPrune = m1.strength >= m2.strength ? m2.id : m1.id;
spatialMemory.removeMemory(toPrune);
results.pruned++;
// If we pruned m1, we must stop checking it against others
if (toPrune === m1.id) break;
}
}
}
console.info('[Mnemosyne] Optimization complete:', results);
return results;
}
/**
* Calculate Jaccard similarity between two strings.
* @private
*/
function _calculateSimilarity(s1, s2) {
if (!s1 || !s2) return 0;
const set1 = new Set(s1.toLowerCase().split(/\s+/));
const set2 = new Set(s2.toLowerCase().split(/\s+/));
const intersection = new Set([...set1].filter(x => set2.has(x)));
const union = new Set([...set1, ...set2]);
return intersection.size / union.size;
}
return { optimize };
})();
export { MemoryOptimizer };

View File

@@ -32,9 +32,6 @@
const SpatialMemory = (() => {
// ─── CALLBACKS ────────────────────────────────────────
let _onMemoryPlacedCallback = null;
// ─── REGION DEFINITIONS ───────────────────────────────
const REGIONS = {
engineering: {
@@ -136,6 +133,9 @@ const SpatialMemory = (() => {
let _regionMarkers = {};
let _memoryObjects = {};
let _connectionLines = [];
let _entityLines = []; // entity resolution lines (issue #1167)
let _camera = null; // set by setCamera() for LOD culling
const ENTITY_LOD_DIST = 50; // hide entity lines when camera > this from midpoint
let _initialized = false;
// ─── CRYSTAL GEOMETRY (persistent memories) ───────────
@@ -143,47 +143,6 @@ const SpatialMemory = (() => {
return new THREE.OctahedronGeometry(size, 0);
}
// ─── TRUST-BASED VISUALS ─────────────────────────────
// Wire crystal visual properties to fact trust score (0.0-1.0).
// Issue #1166: Trust > 0.8 = bright glow/full opacity,
// 0.5-0.8 = medium/80%, < 0.5 = dim/40%, < 0.3 = near-invisible pulsing red.
function _getTrustVisuals(trust, regionColor) {
const t = Math.max(0, Math.min(1, trust));
if (t >= 0.8) {
return {
opacity: 1.0,
emissiveIntensity: 2.0 * t,
emissiveColor: regionColor,
lightIntensity: 1.2,
glowDesc: 'high'
};
} else if (t >= 0.5) {
return {
opacity: 0.8,
emissiveIntensity: 1.2 * t,
emissiveColor: regionColor,
lightIntensity: 0.6,
glowDesc: 'medium'
};
} else if (t >= 0.3) {
return {
opacity: 0.4,
emissiveIntensity: 0.5 * t,
emissiveColor: regionColor,
lightIntensity: 0.2,
glowDesc: 'dim'
};
} else {
return {
opacity: 0.15,
emissiveIntensity: 0.3,
emissiveColor: 0xff2200,
lightIntensity: 0.1,
glowDesc: 'untrusted'
};
}
}
// ─── REGION MARKER ───────────────────────────────────
function createRegionMarker(regionKey, region) {
const cx = region.center[0];
@@ -250,7 +209,83 @@ const SpatialMemory = (() => {
sprite.scale.set(4, 1, 1);
_scene.add(sprite);
return { ring, disc, glowDisc, sprite };
// ─── BULK IMPORT (WebSocket sync) ───────────────────
/**
* Import an array of memories in batch — for WebSocket sync.
* Skips duplicates (same id). Returns count of newly placed.
* @param {Array} memories - Array of memory objects { id, content, category, ... }
* @returns {number} Count of newly placed memories
*/
function importMemories(memories) {
if (!Array.isArray(memories) || memories.length === 0) return 0;
let count = 0;
memories.forEach(mem => {
if (mem.id && !_memoryObjects[mem.id]) {
placeMemory(mem);
count++;
}
});
if (count > 0) {
_dirty = true;
saveToStorage();
console.info('[Mnemosyne] Bulk imported', count, 'new memories (total:', Object.keys(_memoryObjects).length, ')');
}
return count;
}
// ─── UPDATE MEMORY ──────────────────────────────────
/**
* Update an existing memory's visual properties (strength, connections).
* Does not move the crystal — only updates metadata and re-renders.
* @param {string} memId - Memory ID to update
* @param {object} updates - Fields to update: { strength, connections, content }
* @returns {boolean} True if updated
*/
function updateMemory(memId, updates) {
const obj = _memoryObjects[memId];
if (!obj) return false;
if (updates.strength != null) {
const strength = Math.max(0.05, Math.min(1, updates.strength));
obj.mesh.userData.strength = strength;
obj.mesh.material.emissiveIntensity = 1.5 * strength;
obj.mesh.material.opacity = 0.5 + strength * 0.4;
}
if (updates.content != null) {
obj.data.content = updates.content;
}
if (updates.connections != null) {
obj.data.connections = updates.connections;
// Rebuild connection lines
_rebuildConnections(memId);
}
_dirty = true;
saveToStorage();
return true;
}
function _rebuildConnections(memId) {
// Remove existing lines for this memory
for (let i = _connectionLines.length - 1; i >= 0; i--) {
const line = _connectionLines[i];
if (line.userData.from === memId || line.userData.to === memId) {
if (line.parent) line.parent.remove(line);
line.geometry.dispose();
line.material.dispose();
_connectionLines.splice(i, 1);
}
}
// Recreate lines for current connections
const obj = _memoryObjects[memId];
if (!obj || !obj.data.connections) return;
obj.data.connections.forEach(targetId => {
const target = _memoryObjects[targetId];
if (target) _createConnectionLine(obj, target);
});
}
return { ring, disc, glowDisc, sprite };
}
// ─── PLACE A MEMORY ──────────────────────────────────
@@ -260,20 +295,17 @@ const SpatialMemory = (() => {
const region = REGIONS[mem.category] || REGIONS.working;
const pos = mem.position || _assignPosition(mem.category, mem.id);
const strength = Math.max(0.05, Math.min(1, mem.strength != null ? mem.strength : 0.7));
const trust = mem.trust != null ? Math.max(0, Math.min(1, mem.trust)) : 0.7;
const size = 0.2 + strength * 0.3;
const tv = _getTrustVisuals(trust, region.color);
const geo = createCrystalGeometry(size);
const mat = new THREE.MeshStandardMaterial({
color: region.color,
emissive: tv.emissiveColor,
emissiveIntensity: tv.emissiveIntensity,
emissive: region.color,
emissiveIntensity: 1.5 * strength,
metalness: 0.6,
roughness: 0.15,
transparent: true,
opacity: tv.opacity
opacity: 0.5 + strength * 0.4
});
const crystal = new THREE.Mesh(geo, mat);
@@ -286,12 +318,10 @@ const SpatialMemory = (() => {
region: mem.category,
pulse: Math.random() * Math.PI * 2,
strength: strength,
trust: trust,
glowDesc: tv.glowDesc,
createdAt: mem.timestamp || new Date().toISOString()
};
const light = new THREE.PointLight(tv.emissiveColor, tv.lightIntensity, 5);
const light = new THREE.PointLight(region.color, 0.8 * strength, 5);
crystal.add(light);
_scene.add(crystal);
@@ -301,15 +331,13 @@ const SpatialMemory = (() => {
_drawConnections(mem.id, mem.connections);
}
if (mem.entity) {
_drawEntityLines(mem.id, mem);
}
_dirty = true;
saveToStorage();
console.info('[Mnemosyne] Spatial memory placed:', mem.id, 'in', region.label);
// Fire particle burst callback
if (_onMemoryPlacedCallback) {
_onMemoryPlacedCallback(crystal.position.clone(), mem.category || 'working');
}
return crystal;
}
@@ -353,6 +381,77 @@ const SpatialMemory = (() => {
});
}
// ─── ENTITY RESOLUTION LINES (#1167) ──────────────────
// Draw lines between crystals that share an entity or are related entities.
// Same entity → thin blue line. Related entities → thin purple dashed line.
function _drawEntityLines(memId, mem) {
if (!mem.entity) return;
const src = _memoryObjects[memId];
if (!src) return;
Object.entries(_memoryObjects).forEach(([otherId, other]) => {
if (otherId === memId) return;
const otherData = other.data;
if (!otherData.entity) return;
let lineType = null;
if (otherData.entity === mem.entity) {
lineType = 'same_entity';
} else if (mem.related_entities && mem.related_entities.includes(otherData.entity)) {
lineType = 'related';
} else if (otherData.related_entities && otherData.related_entities.includes(mem.entity)) {
lineType = 'related';
}
if (!lineType) return;
// Deduplicate — only draw from lower ID to higher
if (memId > otherId) return;
const points = [src.mesh.position.clone(), other.mesh.position.clone()];
const geo = new THREE.BufferGeometry().setFromPoints(points);
let mat;
if (lineType === 'same_entity') {
mat = new THREE.LineBasicMaterial({ color: 0x4488ff, transparent: true, opacity: 0.35 });
} else {
mat = new THREE.LineDashedMaterial({ color: 0x9966ff, dashSize: 0.3, gapSize: 0.2, transparent: true, opacity: 0.25 });
const line = new THREE.Line(geo, mat);
line.computeLineDistances();
line.userData = { type: 'entity_line', from: memId, to: otherId, lineType };
_scene.add(line);
_entityLines.push(line);
return;
}
const line = new THREE.Line(geo, mat);
line.userData = { type: 'entity_line', from: memId, to: otherId, lineType };
_scene.add(line);
_entityLines.push(line);
});
}
function _updateEntityLines() {
if (!_camera) return;
const camPos = _camera.position;
_entityLines.forEach(line => {
// Compute midpoint of line
const posArr = line.geometry.attributes.position.array;
const mx = (posArr[0] + posArr[3]) / 2;
const my = (posArr[1] + posArr[4]) / 2;
const mz = (posArr[2] + posArr[5]) / 2;
const dist = camPos.distanceTo(new THREE.Vector3(mx, my, mz));
if (dist > ENTITY_LOD_DIST) {
line.visible = false;
} else {
line.visible = true;
// Fade based on distance
const fade = Math.max(0, 1 - (dist / ENTITY_LOD_DIST));
const baseOpacity = line.userData.lineType === 'same_entity' ? 0.35 : 0.25;
line.material.opacity = baseOpacity * fade;
}
});
}
// ─── REMOVE A MEMORY ─────────────────────────────────
function removeMemory(memId) {
const obj = _memoryObjects[memId];
@@ -372,6 +471,16 @@ const SpatialMemory = (() => {
}
}
for (let i = _entityLines.length - 1; i >= 0; i--) {
const line = _entityLines[i];
if (line.userData.from === memId || line.userData.to === memId) {
if (line.parent) line.parent.remove(line);
line.geometry.dispose();
line.material.dispose();
_entityLines.splice(i, 1);
}
}
delete _memoryObjects[memId];
_dirty = true;
saveToStorage();
@@ -392,19 +501,13 @@ const SpatialMemory = (() => {
mesh.scale.setScalar(pulse);
if (mesh.material) {
const trust = mesh.userData.trust != null ? mesh.userData.trust : 0.7;
const base = mesh.userData.strength || 0.7;
if (trust < 0.3) {
// Low trust: pulsing red — visible warning
const pulseAlpha = 0.15 + Math.sin(mesh.userData.pulse * 2.0) * 0.15;
mesh.material.emissiveIntensity = 0.3 + Math.sin(mesh.userData.pulse * 2.0) * 0.3;
mesh.material.opacity = pulseAlpha;
} else {
mesh.material.emissiveIntensity = 1.0 + Math.sin(mesh.userData.pulse * 0.7) * 0.5 * base;
}
mesh.material.emissiveIntensity = 1.0 + Math.sin(mesh.userData.pulse * 0.7) * 0.5 * base;
}
});
_updateEntityLines();
Object.values(_regionMarkers).forEach(marker => {
if (marker.ring && marker.ring.material) {
marker.ring.material.opacity = 0.1 + Math.sin(now * 0.001) * 0.05;
@@ -431,42 +534,6 @@ const SpatialMemory = (() => {
return REGIONS;
}
// ─── UPDATE VISUAL PROPERTIES ────────────────────────
// Re-render crystal when trust/strength change (no position move).
function updateMemoryVisual(memId, updates) {
const obj = _memoryObjects[memId];
if (!obj) return false;
const mesh = obj.mesh;
const region = REGIONS[obj.region] || REGIONS.working;
if (updates.trust != null) {
const trust = Math.max(0, Math.min(1, updates.trust));
mesh.userData.trust = trust;
obj.data.trust = trust;
const tv = _getTrustVisuals(trust, region.color);
mesh.material.emissive = new THREE.Color(tv.emissiveColor);
mesh.material.emissiveIntensity = tv.emissiveIntensity;
mesh.material.opacity = tv.opacity;
mesh.userData.glowDesc = tv.glowDesc;
if (mesh.children.length > 0 && mesh.children[0].isPointLight) {
mesh.children[0].intensity = tv.lightIntensity;
mesh.children[0].color = new THREE.Color(tv.emissiveColor);
}
}
if (updates.strength != null) {
const strength = Math.max(0.05, Math.min(1, updates.strength));
mesh.userData.strength = strength;
obj.data.strength = strength;
}
_dirty = true;
saveToStorage();
console.info('[Mnemosyne] Visual updated:', memId, 'trust:', mesh.userData.trust, 'glow:', mesh.userData.glowDesc);
return true;
}
// ─── QUERY ───────────────────────────────────────────
function getMemoryAtPosition(position, maxDist) {
maxDist = maxDist || 2;
@@ -606,7 +673,6 @@ const SpatialMemory = (() => {
source: o.data.source || 'unknown',
timestamp: o.data.timestamp || o.mesh.userData.createdAt,
strength: o.mesh.userData.strength || 0.7,
trust: o.mesh.userData.trust != null ? o.mesh.userData.trust : 0.7,
connections: o.data.connections || []
}))
};
@@ -752,173 +818,18 @@ const SpatialMemory = (() => {
return _selectedId;
}
// ─── FILE EXPORT ──────────────────────────────────────
function exportToFile() {
const index = exportIndex();
const json = JSON.stringify(index, null, 2);
const date = new Date().toISOString().slice(0, 10);
const filename = 'mnemosyne-export-' + date + '.json';
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.info('[Mnemosyne] Exported', index.memories.length, 'memories to', filename);
return { filename, count: index.memories.length };
}
// ─── FILE IMPORT ──────────────────────────────────────
function importFromFile(file) {
return new Promise((resolve, reject) => {
if (!file) {
reject(new Error('No file provided'));
return;
}
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
// Schema validation
if (!data || typeof data !== 'object') {
reject(new Error('Invalid JSON: not an object'));
return;
}
if (typeof data.version !== 'number') {
reject(new Error('Invalid schema: missing version field'));
return;
}
if (data.version !== STORAGE_VERSION) {
reject(new Error('Version mismatch: got ' + data.version + ', expected ' + STORAGE_VERSION));
return;
}
if (!Array.isArray(data.memories)) {
reject(new Error('Invalid schema: memories is not an array'));
return;
}
// Validate each memory entry
for (let i = 0; i < data.memories.length; i++) {
const mem = data.memories[i];
if (!mem.id || typeof mem.id !== 'string') {
reject(new Error('Invalid memory at index ' + i + ': missing or invalid id'));
return;
}
if (!mem.category || typeof mem.category !== 'string') {
reject(new Error('Invalid memory "' + mem.id + '": missing category'));
return;
}
}
const count = importIndex(data);
saveToStorage();
console.info('[Mnemosyne] Imported', count, 'memories from file');
resolve({ count, total: data.memories.length });
} catch (parseErr) {
reject(new Error('Failed to parse JSON: ' + parseErr.message));
}
};
reader.onerror = function() {
reject(new Error('Failed to read file'));
};
reader.readAsText(file);
});
}
// ─── SPATIAL SEARCH (issue #1170) ────────────────────
let _searchOriginalState = {}; // memId -> { emissiveIntensity, opacity } for restore
function searchContent(query) {
if (!query || !query.trim()) return [];
const q = query.toLowerCase().trim();
const matches = [];
Object.values(_memoryObjects).forEach(obj => {
const d = obj.data;
const searchable = [
d.content || '',
d.id || '',
d.category || '',
d.source || '',
...(d.connections || [])
].join(' ').toLowerCase();
if (searchable.includes(q)) {
matches.push(d.id);
}
});
return matches;
}
function highlightSearchResults(matchIds) {
// Save original state and apply search highlighting
_searchOriginalState = {};
const matchSet = new Set(matchIds);
Object.entries(_memoryObjects).forEach(([id, obj]) => {
const mat = obj.mesh.material;
_searchOriginalState[id] = {
emissiveIntensity: mat.emissiveIntensity,
opacity: mat.opacity
};
if (matchSet.has(id)) {
// Match: bright white glow
mat.emissive.setHex(0xffffff);
mat.emissiveIntensity = 5.0;
mat.opacity = 1.0;
} else {
// Non-match: dim to 10% opacity
mat.opacity = 0.1;
mat.emissiveIntensity = 0.2;
}
});
}
function clearSearch() {
Object.entries(_memoryObjects).forEach(([id, obj]) => {
const mat = obj.mesh.material;
const saved = _searchOriginalState[id];
if (saved) {
// Restore original emissive color from region
const region = REGIONS[obj.region] || REGIONS.working;
mat.emissive.copy(region.color);
mat.emissiveIntensity = saved.emissiveIntensity;
mat.opacity = saved.opacity;
}
});
_searchOriginalState = {};
}
function getSearchMatchPosition(matchId) {
const obj = _memoryObjects[matchId];
return obj ? obj.mesh.position.clone() : null;
}
function setOnMemoryPlaced(callback) {
_onMemoryPlacedCallback = callback;
// ─── CAMERA REFERENCE (for entity line LOD) ─────────
function setCamera(camera) {
_camera = camera;
}
return {
init, placeMemory, removeMemory, update, updateMemoryVisual,
init, placeMemory, removeMemory, update, importMemories, updateMemory,
getMemoryAtPosition, getRegionAtPosition, getMemoriesInRegion, getAllMemories,
getCrystalMeshes, getMemoryFromMesh, highlightMemory, clearHighlight, getSelectedId,
exportIndex, importIndex, exportToFile, importFromFile, searchNearby, REGIONS,
exportIndex, importIndex, searchNearby, REGIONS,
saveToStorage, loadFromStorage, clearStorage,
runGravityLayout,
searchContent, highlightSearchResults, clearSearch, getSearchMatchPosition,
setOnMemoryPlaced
runGravityLayout, setCamera
};
})();

27
scripts/guardrails.sh Normal file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
# [Mnemosyne] Agent Guardrails — The Nexus
# Validates code integrity and scans for secrets before deployment.
echo "--- [Mnemosyne] Running Guardrails ---"
# 1. Syntax Checks
echo "[1/3] Validating syntax..."
for f in ; do
node --check "$f" || { echo "Syntax error in $f"; exit 1; }
done
echo "Syntax OK."
# 2. JSON/YAML Validation
echo "[2/3] Validating configs..."
for f in ; do
node -e "JSON.parse(require('fs').readFileSync('$f'))" || { echo "Invalid JSON: $f"; exit 1; }
done
echo "Configs OK."
# 3. Secret Scan
echo "[3/3] Scanning for secrets..."
grep -rE "AI_|TOKEN|KEY|SECRET" . --exclude-dir=node_modules --exclude=guardrails.sh | grep -v "process.env" && {
echo "WARNING: Potential secrets found!"
} || echo "No secrets detected."
echo "--- Guardrails Passed ---"

26
scripts/smoke.mjs Normal file
View File

@@ -0,0 +1,26 @@
/**
* [Mnemosyne] Smoke Test — The Nexus
* Verifies core components are loadable and basic state is consistent.
*/
import { SpatialMemory } from '../nexus/components/spatial-memory.js';
import { MemoryOptimizer } from '../nexus/components/memory-optimizer.js';
console.log('--- [Mnemosyne] Running Smoke Test ---');
// 1. Verify Components
if (!SpatialMemory || !MemoryOptimizer) {
console.error('Failed to load core components');
process.exit(1);
}
console.log('Components loaded.');
// 2. Verify Regions
const regions = Object.keys(SpatialMemory.REGIONS || {});
if (regions.length < 5) {
console.error('SpatialMemory regions incomplete:', regions);
process.exit(1);
}
console.log('Regions verified:', regions.join(', '));
console.log('--- Smoke Test Passed ---');

895
style.css

File diff suppressed because it is too large Load Diff