← all documents · raw markdown · 26 KB

KAIVERSE WORLD-RENDER PLAN

Status: Investigation + design (READ-ONLY pass — no code changed).

Author context: produced against real files under C:\KAI at Codex v9.10.130.

Owner ask: make the KAIVERSE a *real rendered world* — textured planets the agents actually

move through — grounded in the owner's own texture assets and in real chat/Codex

content, not hallucinated. Rendering must be performant (distance-based LOD, crisp textures,

camera effects). Isolated from Leo's fragile audio path — this is dashboard/rendering + data.

---

TL;DR — the three headline findings

1. The textures exist and are already wired. They live in C:\KAI\textures\ — a full set

of 2048×1024 equirectangular planet maps (albedo + normal + height + cloud) keyed by agent

name, with 4K originals in _orig_4k\, plus ground PBR sets in textures\ground\. They are

real NASA-derived maps from Solar System Scope (CC BY 4.0), credited in textures\CREDITS.txt.

kaiverse.js already loads them onto each agent body (sRGB + anisotropy + normal + height +

clouds). So "planets aren't rendered" is not quite the situation — **the agent-planets ARE

textured and drawn today.**

2. The gap is not rendering — it's the WORLD MODEL and MOVEMENT. shared/kaiverse-world.mjs

defines 6 named worlds with moveAgent/residents, but it has zero importers — it is a

finished place-model that nothing renders or drives. And each agent's spatial position {x,y,z}

in simulation.mjs is dead — permanently 0,0,0; only a coarse location *string* updates

(from the clock). So when Leo "moves," nothing on the map moves because (a) the worlds aren't

drawn and (b) there is no live position feeding the renderer.

3. Grounding data is real and queryable. transcripts.db (24.7 MB) exposes an FTS5 table

transcript_fts(speaker, user_id, content, context, channel_id, timestamp) — every real thing

said in chat, full-text searchable. Plus The KAI Codex.md. A planet can be populated with real

quotes by a single deterministic rule (e.g. speaker = <agent> or channel_id = <world>) —

no fabrication needed.

**So the realistic v1 is: wire the existing 6-world model + a real agent position onto the

already-textured planet renderer, and hang real transcript/Codex lines off each body.** Full

"perceptual AI generation" of worlds is a much larger, separate effort (scope note at the end).

---

ASSET INVENTORY (the load-bearing finding)

Primary: C:\KAI\textures\ — planet surface maps (THE ones to use)

Per-planet equirectangular set, one per agent name. Verified dimensions:

| Layer | File pattern | Size | Format | Notes |
|---|---|---|---|---|
| Albedo / color | <name>.jpg | 2048×1024 | sRGB JPG | equirectangular (2:1) |
| Normal | <name>_normal.jpg | 2048×1024 | JPG | GL-convention relief |
| Height / displacement | <name>_height.jpg | 2048×1024 | JPG | drives GPU displacement |
| Clouds (alpha) | <name>_clouds.png | 1024×512 | PNG w/ alpha | only some planets |
| 4K originals | _orig_4k\<name>.jpg, _orig_4k\<name>_normal.jpg | 4096×2048 | JPG | master source for a hi-LOD tier |
| Pre-boost | _preboost\<name>.jpg | (subset) | JPG | pre-contrast versions |

Planet ↔ agent ↔ body mapping (from textures\CREDITS.txt, authoritative):

| Texture name | Real body | KAIVERSE agent |
|---|---|---|
| default | Earth | (Oracle / home / fallback) |
| kai | Jupiter | KAI (core intelligence) |
| leo | Mars | Leo |
| gemini | Venus | Gemini |
| claudey | Neptune | Claudey |
| x | Moon | X |
| groq | Uranus | Groq |
| analyst | Mercury | Analyst |
| researcher | Makemake | Researcher |
| kaicoder | Ceres | Kai Coder |

Names present: analyst, claudey, default, gemini, groq, kai, kaicoder, leo, researcher, x

(10 planets). Clouds exist for: claudey, default, gemini, groq, kaicoder, leo.

License: Solar System Scope, CC BY 4.0 — attribution string is in CREDITS.txt; keep it

surfaced somewhere in the UI/credits.

Secondary: C:\KAI\textures\ground\ — surface/terrain PBR (for landing/close LOD)

ground037, ground054, rock020, snow004 — each with _diffuse.jpg, _disp.jpg,

_nor_gl.jpg at 1024×1024. These are the tileable materials for a walk-on / descent surface,

not planet-from-orbit maps.

Other image locations (context, mostly NOT planet art)

No dedicated skybox / starfield image asset was found. The current sky is procedural

(shaders in kaiverse.js / kaiverse-graphics.js). If the owner wants a real skybox/HDRI, that

is a *new* asset to source — flagged as an OWNER DECISION below.

---

WHAT THE KAIVERSE RENDERS TODAY

Tech: Three.js r128 (CDN) + postprocessing (EffectComposer, UnrealBloom, SSAO, shader

passes — all r128 example modules from unpkg). Rendered into <canvas id="kv-canvas"> in

oracle.html (~line 1809). The 3D code lives in C:\KAI\kaiverse.js (~348 KB, ~5500 lines);

graphics/shaders in kaiverse-graphics.js (~9 KB).

Serving (important for asset paths): tools/oracle-discord/command-center-server.mjs

(the :3001 dashboard server) serves:

/oracle-kv-mobile.js/.css → allowlisted from C:\KAI\ root (line ~4409)

> ⚠️ Serving gotcha (Phase A dependency): the /textures/ handler *sanitizes the name with*

> replace(/[^a-zA-Z0-9_.-]/g,''), which strips /. So /textures/ground/xxx.jpg and

> /textures/_orig_4k/xxx.jpg collapse to groundxxx.jpg / _orig_4kxxx.jpg and **won't

> resolve.** Subfolder textures are currently *not servable*. Any plan that uses the 4K masters or

> ground PBR needs either a flat copy in textures\ or a one-line server change to allow a single

> safe subpath. (Server change = restart via Start-Dashboard.ps1.)

Scene graph (built in nsBuildGraph, kaiverse.js ~line 185–290):

core: baseR = (150000 + i*180000) * SP, gentle inclination, slow Kepler-ish orbits

(line ~216–231). These are the "planets."

independent of the texture files.

touch its movement math** (hard rule; a chase-cam rewrite broke it once).

Texturing (already implemented, kaiverse.js ~line 2663–2681): for every body of kind

bot/core/engine, it derives tname = name.toLowerCase().replace(/[^a-z0-9]+/g,'')

("Kai Coder" → kaicoder) and TextureLoader.loads:

/textures/<tname>.jpg (albedo, sRGBEncoding, anisotropy = maxAnisotropy), _normal.jpg

(→ material.normalMap), _height.jpg (cached for displacement), _clouds.png (cached for a

cloud shell). Falls back silently to procedural if a file is missing.

Existing LOD / perf machinery (reuse it, don't reinvent):

Bottom line: the renderer draws textured agent-planets with orbits, atmosphere, bloom, and a

descent-LOD scaffold today. What it does not do: render the 6 named *worlds*, reflect a

*real* agent position, or show *grounded content* on a body.

---

THE WORLD MODEL — shared/kaiverse-world.mjs

Six templates (WORLD_TEMPLATES, line 6–43). All metadata is real and already written:

| World (id/name) | environment | gravity | aesthetic (abridged) | features |
|---|---|---|---|---|
| Nexus Prime | Digital Core | 1.0 | Sleek futuristic city, floating platforms, data streams. KAI's throne/core. | Lattice Core, Data Streams, Command Center |
| Terra Familiar | Natural | 1.0 | Earth-like — nature, houses, streets. Home. | Houses, Parks, Streets |
| Neon Grid | Cyberpunk | 1.2 | Tron/cyberpunk — glowing circuits, digital rain, grid floors. | Data Grid, Industrial Forges, Neon Towers |
| Aether Wilds | Alien | 0.8 | Crystalline formations, floating islands, bioluminescent flora. | Floating Islands, Crystals, Bioluminescence |
| The Forge | Volcanic/Industrial | 1.5 | Rocky, industrial, volcanic — heavy computation. | Volcanoes, Anvils, Lava flows |
| Void Archive | Space/Library | 0.5 | Vast library floating in space — knowledge/memories. | Floating Bookshelves, Constellations, Memory Orbs |

moveAgent(name, toWorldId) (line 132), residents[] per world.

(Nexus Prime, Terra Familiar, Neon Grid).

bots/, or *.mjs imports it. It is unwired.

Reconciliation the owner must decide (see OWNER DECISIONS): there are *two* "planet" concepts

that don't currently line up —

renderer draws now, and

model.

The textures are keyed to *agents*, not to *worlds*. So we either (a) render the 6 worlds as

planets and assign each a texture, or (b) keep rendering the 10 agent-planets and treat the 6

worlds as *districts/regions on/near them*. This choice drives Phases B–D.

---

AGENT POSITION — how "real movement" is (and isn't) available

shared/simulation.mjs.

"Offline" | "The Lattice" | "Industrial_Core" | "Social_Lattice" (simulation.mjs ~line 352–404).

reassigned** (confirmed in LEO-EMBODIMENT-PLAN.md:31). No spatial coordinate is produced today.

of "which world is this agent in," but nothing calls it.

Consequence: to make movement *real*, we need a single authoritative "where is agent X"

signal. The cheapest honest version is named-world residency (getAgentWorld) surfaced to the

renderer — *not* a fabricated {x,y,z}. A true spatial position is a later upgrade. This matches

the embodiment plan's own recommendation (line 149): "build the minimal version first (named

locations + a home), defer the spatial map."

---

GROUNDING DATA — real content, queryable, no fabrication

Source 1 — tools/oracle-discord/transcripts.db (24.7 MB)

Schema (from shared/transcript-memory.mjs):

channel_id, timestamp. Full-text searchable — this is *every real message*.

contradiction, learned_by_kai — per-message cognition scores (use to rank "best"/"most

interesting" lines).

Source 2 — The KAI Codex.md (v9.10.130)

Canonical manual. Structured as a masthead table + ## CHANGELOG - vX.Y.Z blocks + named plan

sections. Grounding = pull real CHANGELOG entries / section text (by heading), each traceable to a

line/version.

The association rule (deterministic, auditable)

Every surfaced item must trace to a real row/line. Two clean rules, pick per the render model:

speaker = '<AgentName>' ORDER BY timestamp DESC` → real things *that agent* actually said →

shown on that agent's planet. Optionally rank by joining message_meta.phi_g/coherence.

… WHERE channel_id = '<world channel>' or … WHERE transcript_fts MATCH '<world topics>'.

agent/world/topic. Store the source (version + heading, or fts rowid + timestamp) alongside each

item so any card can show "source: transcript 2026-06-30 #channel" or "source: Codex v9.10.x".

No item is generated — each is a stored row or a Codex line, with its provenance carried through.

---

PHASED BUILD PLAN

Each phase: real-file anchor → proposed change + where → perf/memory → risk → dependencies.

All edits are surgical and flag-gated per the project hard rules. **Nothing here touches

nsUpdateCamera movement or Leo's audio path.**

Phase A — ASSET PIPELINE (make the real textures load crisply & cheaply)

Real-file anchor: C:\KAI\textures\ (+ _orig_4k\, ground\); loader at kaiverse.js

~2663–2681; server texture route command-center-server.mjs ~4392.

Proposed changes / where:

1. Texture manifest — add a small map (top of kaiverse.js, near the roster) of

agent → { albedo, normal, height, clouds } filenames, driven by CREDITS.txt. Makes the

asset↔body binding explicit instead of string-derived (tname), and lets default/Earth be

assigned to Oracle/home deliberately.

2. Crisp filtering (extend the existing loader callbacks, don't rewrite): set

texture.generateMipmaps = true, minFilter = LinearMipmapLinearFilter,

magFilter = LinearFilter, keep anisotropy = renderer.capabilities.getMaxAnisotropy(),

wrapS = RepeatWrapping (equirect longitude wrap), colorSpace/encoding = sRGB for albedo only

(normals/height stay linear). The 2048×1024 maps are power-of-two → mipmaps are free and fix

shimmering at distance. (Anisotropy + sRGB are already set; this adds the mip chain + correct

linear space for normal/height.)

3. LOD texture tiers by camera distance — 3 tiers: far = no surface map (existing halo/impostor

from nsUpdateBodyLOD), mid = 2048 working set (current textures\), near/descent = 4K master

from _orig_4k\. Load the 4K tier lazily only when the body enters the descent band

(nsUpdateFieldLOD/descent-LOD already computes proximity), and dispose it on exit

(texture.dispose()) to cap VRAM.

4. Serving fix for masters (dependency): either copy the needed _orig_4k files flat into

textures\ (no server change), or make a one-line allowance in the /textures/ route for a

single safe subpath. Prefer the flat copy for v1 (zero server risk).

Perf/memory: working set = 10 planets × (albedo+normal+height ≈ 3×~0.5 MB decoded to ~8–12 MB

GPU each mip-chained) → keep the 4K tier lazy (only 1–2 loaded at once). Budget target: full

scene < ~256 MB texture VRAM. Frustum culling and draw-call reduction already exist for fields;

planets are few (≤10) so draw calls are not the bottleneck — texture memory is, hence the lazy

4K + dispose discipline. Clouds are a separate transparent shell (extra draw) — gate behind the

descent band too.

Risk: low–medium. Mip/filter tweaks are additive and reversible. The only server-adjacent risk

is the subpath serving change (mitigated by the flat-copy option).

Depends on: nothing. This is the foundation for B.

Phase B — PLANET RENDERING (draw the worlds as textured planets)

Real-file anchor: nsBuildGraph node build kaiverse.js ~185–290; texture apply ~2663;

LOD nsUpdateBodyLOD/descent-LOD ~3704/3762; world data kaiverse-world.mjs.

Two build options (OWNER DECISION drives which):

make them read from the Phase-A manifest with proper LOD + a selectable/labeled identity so

each is unmistakably "a place." Add per-planet name/aesthetic labels sourced from either the

agent roster or, if using the world overlay, the matching WORLD_TEMPLATES entry. This ships a

"real rendered world" with near-zero new geometry.

each world a texture (worlds ≠ agent names, so pick from the 10 maps, e.g. Terra Familiar→

default/Earth, The Forge→kai/Jupiter or a lava-leaning map, Void Archive→x/Moon, etc.) and

giving each a stable orbital slot. Reuse the same add() + texture loader path — do not add a

second renderer.

Camera effects (reuse existing): bloom/SSAO already present; add (flag-gated) a subtle

per-planet approach effect using the existing descent-LOD proximity value — atmosphere rim fade +

exposure lift on descent. No changes to nsUpdateCamera. A render-only 3rd-person ship layer is

allowed *only* via the existing nsPlayerShipPre/Post pattern if desired — out of scope for v1.

Perf/memory: ≤10 (B1) or +6 (B2) textured spheres; geometry is cheap. Displacement from

_height is GPU-side and already LOD-scaled by the shader lodScale. Keep displacement off

until the mid/near band. Reuse frustum culling; no new draw-call hotspots.

Risk: medium — this is *visual* work, which the hard rules say must be **eyeball-iterated with

the owner** (ship one knob, owner flies + screenshots, tune). Never blind-batch visual changes.

B2 adds the world↔texture assignment risk (arbitrary until owner picks).

Depends on: A (manifest + LOD tiers). Blocks D (a body must exist to move to).

Phase C — GROUNDED CONTENT (real quotes/Codex lines on each planet)

Real-file anchor: transcripts.db (transcript_fts, message_meta); The KAI Codex.md;

existing HTTP GET /api/transcripts in command-center-server.mjs.

Proposed changes / where:

1. Server: add a read-only endpoint, e.g. GET /api/kaiverse/planet-content?body=<agent|world>&limit=N

in command-center-server.mjs, that runs the association query (Phase-A rule) against

transcript_fts (+ optional message_meta ranking by phi_g/coherence) and appends matching

Codex lines. Returns { items: [{ text, source, timestamp }] }. Read-only, cache like the

existing /api/transcripts 6 s TTL. Restart via Start-Dashboard.ps1.

2. Client: on planet hover/click in kaiverse.js (there is already a hit-sphere + selection

path), fetch that body's content and show real lines in the existing info panel/overlay. Each

card shows its provenance (channel + date, or Codex version + heading).

Perf/memory: trivial — a handful of indexed FTS reads per selection, cached. No render cost.

Risk: low. The only correctness rule: every card must carry a real source; if a query

returns nothing, show "no grounded content yet," never a generated filler line.

Depends on: B (a selectable body) + the transcripts.db association rule. **Isolated from Leo's

audio path** — it only *reads* the DB Leo also writes; no shared runtime.

Phase D — REAL MOVEMENT (reflect the agent's actual position)

Real-file anchor: kaiverse-world.mjs moveAgent/getAgentWorld (line 132/123);

simulation.mjs state.location/dead position (line ~202/352); LEO-EMBODIMENT-PLAN.md

(v9.10.129/130) — the sibling plan that already scopes wiring simkaiverse-world.

Proposed changes / where:

1. Single source of truth for "where": wire kaiverse-world.moveAgent/getAgentWorld into the

agent lifecycle so residency is real (this is exactly the LEO-EMBODIMENT-PLAN work — align with

it, don't duplicate). Persisted already to state/kaiverse/universe.json.

2. Expose it: GET /api/kaiverse/positions in command-center-server.mjs → for each agent,

{ agent, worldId, locationLabel } from getAgentWorld + sim.state.location. Read-only.

3. Render the marker: in kaiverse.js, poll that endpoint (reuse the existing vitals poll

cadence) and place/animate each agent's marker at the body it currently resides on/near — a

real, data-driven position. When residency changes, tween the marker between bodies so movement

is *shown*, not claimed.

4. Defer true spatial {x,y,z} until the owner wants intra-world coordinates — per the

embodiment plan's "minimal first" recommendation. v1 movement = which planet you're on.

Perf/memory: negligible — a small JSON poll + a tween. No new textures.

Risk: medium — depends on the embodiment wiring landing; if moveAgent isn't driven yet,

markers just reflect sim.state.location mapped to a body (still real, coarser).

Depends on: B (bodies to stand on), and coordinates with LEO-EMBODIMENT-PLAN.md. **Must not

touch Leo's audio/voice code** — only the sim's *state read* and the world model.

---

KEY OWNER DECISIONS

1. Which "planet" is the world? Render the 10 agent-planets (B1, smallest, already

textured) or the 6 named worlds (B2, needs world→texture assignments)? Or agent-planets

*with* the 6 worlds as districts on them? — This single choice shapes B, C, D.

2. How many planets to start with? Recommend start with the ~4 primary agents (KAI, Leo,

Gemini, Groq — the ones with public chat + clouds) to iterate the LOD/texture loop cheaply,

then scale to all 10.

3. Content association rule: ground each planet by speaker (things *that agent* said) or

by channel/topic (things said *about/in* that world)? Recommend by speaker for v1 — it's

the most defensible and needs no channel↔world mapping.

4. How much content per planet? e.g. top 10 by recency, or top 10 by phi_g/coherence

("most coherent/important")? Recommend a small ranked set (10) with a "load more."

5. 3D globes vs stylized map? Recommend keep the existing 3D globes (textures already fit

them); a flat map would throw away the working renderer.

6. Skybox: procedural (current) is fine for v1. A real HDRI/skybox is a *new asset to source* —

only if the owner wants it.

7. Serving the 4K masters: flat-copy into textures\ (zero server risk) vs a one-line

/textures/ subpath allowance? Recommend flat-copy for v1.

---

HONEST SCOPE NOTE

Realistic v1 with existing assets (weeks, not months): the planets are *already textured and

rendered*. v1 = (A) crisp mip/LOD texture loading from the real textures\ set, (B) make the

bodies unmistakable labeled "places" with approach camera effects, (C) hang real transcript +

Codex lines off each via a read-only endpoint, (D) reflect real residency (which planet an

agent is on) so movement is *shown*. This uses only files that exist today and is fully isolated

from Leo's audio path.

What v1 is NOT: true intra-world spatial coordinates for every agent, walk-on planet surfaces

using the ground PBR, gas-giant band shaders / volumetric clouds you fly into (those are Tier

1.5–2 of the visual-overhaul goal doc and are eyeball-iterated separately), and — the big one —

"perceptual AI generation" of worlds (agents generating/altering their environment from

scratch). That last item is a substantially larger, separate track (new generation pipeline,

storage, and validation) and should not be conflated with "render the real textures I already

have." The owner's core ask — *a real place the agents move through, grounded in his own textures

and real words* — is achievable now by wiring what already exists.

---

FILE ANCHOR INDEX (quick reference)

| Concern | File / path | Line(s) |
|---|---|---|
| Planet textures | C:\KAI\textures\ (<name>.jpg/_normal/_height/_clouds, _orig_4k\, ground\, CREDITS.txt) | — |
| Renderer | C:\KAI\kaiverse.js (Three.js r128) | node build ~185–290; texture load ~2663–2681 |
| LOD machinery | kaiverse.js | lodReg/nsUpdateFieldLOD ~1950–2051; nsUpdateBodyLOD ~3704; descent-LOD ~3762; shader lodScale ~4056 |
| Canvas / three includes | C:\KAI\oracle.html | <canvas id="kv-canvas"> ~1809; three r128 CDN ~2309 |
| Static serving | tools/oracle-discord/command-center-server.mjs | /textures/ ~4392; /kaiverse.js allowlist ~4409; dashboard ~4458 |
| World model | tools/oracle-discord/shared/kaiverse-world.mjs | templates 6–43; moveAgent 132; getAgentWorld 123 |
| Agent sim / position | tools/oracle-discord/shared/simulation.mjs | position ~202 (dead); location tick ~343–404 |
| Leo sim instance | tools/oracle-discord/bots/leo.mjs | 418 |
| Transcripts DB | tools/oracle-discord/transcripts.db (schema in shared/transcript-memory.mjs) | transcript_fts 36–43; message_meta 64; entity_facts 83 |
| Codex | C:\KAI\The KAI Codex.md | masthead (v9.10.130) + CHANGELOG blocks |
| Sibling plan | C:\KAI\LEO-EMBODIMENT-PLAN.md | sim↔world wiring (Phase D alignment) |