gitworld / src /world-architect.js
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/gitworld
6281708 verified
Raw
History Blame Contribute Delete
23.9 kB
import {
clamp,
clone,
EVENT_TYPES,
makeEvent
} from './shared.js';
export const WALKABLE_BOUNDS = Object.freeze({ minX: 70, maxX: 1530, minY: 90, maxY: 850 });
export const DISTRICTS = Object.freeze([
{
id: 'src',
name: 'SRC DISTRICT',
path: '/src',
title: 'Central Kernel Tower',
glyph: '⌘',
accent: '#62f2d2',
x: 565,
y: 230,
width: 255,
height: 220,
summary: 'The living source tree: modules, kernel code, and the repository entry point.',
stat: '42 files · 213 commits',
files: [
{ id: 'main-rs', name: 'main.rs', kind: 'Rust', size: '8.4 KB', detail: 'Repository bootstrap and agent scheduler.', code: 'fn main() {\n let world = GitWorld::spawn();\n world.walk();\n}' },
{ id: 'kernel-cu', name: 'kernel.cu', kind: 'CUDA', size: '24.1 KB', detail: 'The compute floor is under construction.', code: '__global__ void kernel_step(Agent agent) {\n agent.advance();\n}' },
{ id: 'lib-rs', name: 'lib.rs', kind: 'Rust', size: '12.7 KB', detail: 'Shared repository primitives and event contracts.', code: 'pub mod events;\npub mod districts;\npub mod builders;' },
{ id: 'mod-rs', name: 'mod.rs', kind: 'Rust', size: '2.1 KB', detail: 'District module registry.', code: 'pub const DISTRICTS: &[&str] = &[\n "src", "tests", "docs"\n];' }
]
},
{
id: 'tests',
name: 'TEST DISTRICT',
path: '/tests',
title: 'Test Factory',
glyph: '✓',
accent: '#91e85e',
x: 230,
y: 370,
width: 235,
height: 185,
summary: 'Inspection robots verify each build before the city opens another street.',
stat: '142 passing · 0 failing',
files: [
{ id: 'world-test', name: 'world.test.js', kind: 'Test', size: '9.7 KB', detail: 'Deterministic movement and event checks.', code: 'assert.equal(world.tick, 12);\nassert.equal(events.length, 4);' },
{ id: 'contracts-test', name: 'contracts.test.js', kind: 'Test', size: '6.2 KB', detail: 'Shared UI/world event contract checks.', code: 'assert.ok(EVENT_TYPES.PLAYER_MOVE);\nassert.ok(EVENT_TYPES.BUILD_COMPLETED);' },
{ id: 'fixtures', name: 'fixtures/', kind: 'Directory', size: '18 items', detail: 'Small simulated repository fixtures.', code: 'fixture("pax-coder");' }
]
},
{
id: 'docs',
name: 'DOCS LIBRARY',
path: '/docs',
title: 'Documentation Library',
glyph: '▤',
accent: '#ffcf68',
x: 1085,
y: 245,
width: 240,
height: 205,
summary: 'A warm archive of architecture decisions, guides, and the city map legend.',
stat: '18 guides · 96% coverage',
files: [
{ id: 'architecture', name: 'architecture.md', kind: 'Markdown', size: '14.2 KB', detail: 'The frontend event-driven architecture.', code: '# GitWorld architecture\nInput -> simulation -> state -> HUD' },
{ id: 'contributing', name: 'contributing.md', kind: 'Markdown', size: '4.8 KB', detail: 'How builders add a district.', code: '1. Choose a street\n2. Add a contract\n3. Run the inspectors' },
{ id: 'readme', name: 'README.md', kind: 'Markdown', size: '8.3 KB', detail: 'The repository welcome sign.', code: '# pax-coder\nA simulated repository world.' }
]
},
{
id: 'issues',
name: 'ISSUE QUESTS',
path: '/issues',
title: 'Issue Quest Board',
glyph: '!',
accent: '#ff9f58',
x: 865,
y: 470,
width: 215,
height: 160,
summary: 'Open issues become quests with markers, owners, and a clear next action.',
stat: '3 open quests · 1 in progress',
files: [
{ id: 'issue-201', name: '#201 bug in proof', kind: 'Issue', size: 'open', detail: 'Reproduce the proof boundary on the kernel floor.', code: 'status: open\nowner: proof-agent' },
{ id: 'issue-202', name: '#202 add test', kind: 'Issue', size: 'open', detail: 'Add a regression test for agent movement.', code: 'status: open\nowner: test-agent' },
{ id: 'issue-203', name: '#203 docs update', kind: 'Issue', size: 'queued', detail: 'Document the deploy launch sequence.', code: 'status: queued\nowner: doc-agent' }
]
},
{
id: 'prs',
name: 'PR GATE',
path: '/pulls',
title: 'Pull Request Gate',
glyph: '↔',
accent: '#d37cff',
x: 600,
y: 475,
width: 210,
height: 180,
summary: 'A glowing merge door: review the change before opening the next branch road.',
stat: '2 open · review required',
files: [
{ id: 'pr-88', name: '#88 merge kernel fix', kind: 'Pull request', size: 'review', detail: 'Two approvals still needed before merge.', code: 'checks: passing\nreviews: 1 / 3' },
{ id: 'pr-91', name: '#91 docs refresh', kind: 'Pull request', size: 'ready', detail: 'Ready to merge after the documentation quest.', code: 'checks: passing\nreviews: 3 / 3' }
]
},
{
id: 'actions',
name: 'ACTIONS FACTORY',
path: '/.github',
title: 'Automation Center',
glyph: '⚙',
accent: '#66a9ff',
x: 1250,
y: 485,
width: 235,
height: 195,
summary: 'CI factories turn commits into tested artifacts and light the deploy runway.',
stat: 'BUILD #812 · passing',
files: [
{ id: 'ci-yml', name: 'ci.yml', kind: 'Actions', size: '5.2 KB', detail: 'Build, test, and artifact inspection pipeline.', code: 'jobs:\n build:\n test:\n deploy:' },
{ id: 'pages-yml', name: 'pages.yml', kind: 'Actions', size: '2.4 KB', detail: 'Static Pages deployment path.', code: 'deploy-pages: enabled' },
{ id: 'release', name: 'release.yml', kind: 'Actions', size: '3.0 KB', detail: 'Packages the next city snapshot.', code: 'tag: v0.8.2' }
]
}
]);
const INITIAL_AGENTS = [
{ id: 'world-architect', name: 'WORLD ARCHITECT', role: 'World geometry', task: 'Building /src district', status: 'BUILDING', progress: 78, color: '#62f2d2' },
{ id: 'repository-builder', name: 'REPOSITORY BUILDER', role: 'Repository mapping', task: 'Mapping 42 files', status: 'MAPPING', progress: 64, color: '#ffcf68' },
{ id: 'reality-integrator', name: 'REALITY/UI INTEGRATOR', role: 'Interaction layer', task: 'Connecting terminal', status: 'WIRING', progress: 52, color: '#d37cff' }
];
const INITIAL_EVENTS = [
{ id: 'seed-1', type: EVENT_TYPES.COMMIT, tick: 0, at: '00:00:00', detail: { message: '8f3a9c1 Fix kernel bounds', districtId: 'src' } },
{ id: 'seed-2', type: EVENT_TYPES.AGENT_PROGRESS, tick: 0, at: '00:00:00', detail: { message: 'WORLD ARCHITECT placed a new tower window.', agentId: 'world-architect' } },
{ id: 'seed-3', type: EVENT_TYPES.TEST_COMPLETED, tick: 0, at: '00:00:00', detail: { message: '142 inspectors passed the street check.', districtId: 'tests' } }
];
const SIMULATION_SEQUENCE = [
{ type: EVENT_TYPES.AGENT_PROGRESS, detail: { agentId: 'world-architect', message: 'WORLD ARCHITECT raised the /src tower scaffold.' } },
{ type: EVENT_TYPES.AGENT_PROGRESS, detail: { agentId: 'repository-builder', message: 'REPOSITORY BUILDER mapped kernel.cu into the compute floor.' } },
{ type: EVENT_TYPES.CONSTRUCTION, detail: { districtId: 'src', amount: 0.03, message: 'A new source window flickers online.' } },
{ type: EVENT_TYPES.TEST_STARTED, detail: { districtId: 'tests', message: 'Inspection robots started a deterministic street sweep.' } },
{ type: EVENT_TYPES.TEST_COMPLETED, detail: { districtId: 'tests', message: '142 tests passed. The test district lights turn green.' } },
{ type: EVENT_TYPES.BUILD_STARTED, detail: { districtId: 'actions', message: 'BUILD #813 started in the automation factory.' } },
{ type: EVENT_TYPES.AGENT_PROGRESS, detail: { agentId: 'reality-integrator', message: 'REALITY/UI INTEGRATOR wired a contextual inspect panel.' } },
{ type: EVENT_TYPES.BUILD_COMPLETED, detail: { districtId: 'actions', message: 'BUILD #813 completed and artifacts are staged.' } },
{ type: EVENT_TYPES.COMMIT, detail: { districtId: 'src', message: '2h4d7e2 Add proof sketch' } },
{ type: EVENT_TYPES.ISSUE, detail: { districtId: 'issues', message: '#202 quest marker activated: add test' } },
{ type: EVENT_TYPES.PULL_REQUEST, detail: { districtId: 'prs', message: '#91 merge gate is ready for review.' } },
{ type: EVENT_TYPES.DEPLOYMENT_STARTED, detail: { districtId: 'actions', message: 'Deploy rocket is fueling on the Pages runway.' } },
{ type: EVENT_TYPES.DEPLOYMENT_COMPLETED, detail: { districtId: 'actions', message: 'Static city snapshot deployed to the local launch pad.' } }
];
export function createWorldState(seed = 20260828) {
return {
seed,
tick: 0,
repository: {
owner: 'SNAPKITTYWEST',
name: 'pax-coder',
branch: 'main',
visibility: 'Public',
simulated: true,
stars: 213,
forks: 45,
languages: ['Rust', 'CUDA', 'Markdown'],
build: 'PASSING',
tests: '142 PASS',
deployment: 'STAGED',
commits: [
{ id: '8f3a9c1', hash: '8f3a9c1', message: 'Fix kernel bounds', author: 'AhmadParr' },
{ id: '2h4d7e2', hash: '2h4d7e2', message: 'Add proof sketch', author: 'proof-agent' },
{ id: '9ac1bd9', hash: '9ac1bd9', message: 'Update docs', author: 'doc-agent' },
{ id: '7d0c812', hash: '7d0c812', message: 'Wire agent event bus', author: 'world-architect' }
],
issues: [
{ id: '201', title: '#201 Bug in proof', detail: 'Reproduce the proof boundary on the kernel floor.', status: 'OPEN' },
{ id: '202', title: '#202 Add test', detail: 'Add a regression test for agent movement.', status: 'OPEN' },
{ id: '203', title: '#203 Docs update', detail: 'Document the deploy launch sequence.', status: 'QUEUED' }
],
pullRequests: [
{ id: '88', title: '#88 Merge kernel fix', detail: 'Two approvals still needed before merge.', status: 'REVIEW' },
{ id: '91', title: '#91 Docs refresh', detail: 'Ready to merge after the documentation quest.', status: 'READY' }
]
},
districts: clone(DISTRICTS),
agents: clone(INITIAL_AGENTS),
events: clone(INITIAL_EVENTS),
construction: { src: 0.78, tests: 1, docs: 0.96, issues: 0.7, prs: 0.82, actions: 0.88 },
player: { x: 800, y: 735, speed: 18, facing: 'north', step: 0 },
selectedDistrictId: 'src',
selectedFileId: 'main-rs',
selectedCollection: 'files',
selectedRecord: null,
activeTool: 'terminal',
activePanel: 'world',
terminal: { open: false, lines: ['$ local shell connected', '$ type `help` for commands'], command: '' },
feedback: 'Walk toward a district or click a glowing building.',
unlocked: false,
view: 'city'
};
}
function pushEvent(state, event) {
state.events = [event, ...state.events].slice(0, 14);
}
function findDistrict(state, districtId) {
return state.districts.find((district) => district.id === districtId) || state.districts[0];
}
function selectedFile(state) {
const district = findDistrict(state, state.selectedDistrictId);
return district.files.find((file) => file.id === state.selectedFileId) || district.files[0];
}
function circlesOverlap(x, y, district, margin = 28) {
const left = district.x - margin;
const right = district.x + district.width + margin;
const top = district.y - margin;
const bottom = district.y + district.height + margin;
return x >= left && x <= right && y >= top && y <= bottom;
}
export function getNearbyDistrict(state, range = 185) {
let nearest = null;
let distance = Number.POSITIVE_INFINITY;
for (const district of state.districts) {
const centerX = district.x + district.width / 2;
const centerY = district.y + district.height / 2;
const nextDistance = Math.hypot(state.player.x - centerX, state.player.y - centerY);
if (nextDistance < distance) {
nearest = district;
distance = nextDistance;
}
}
return { district: nearest, distance, inRange: distance <= range };
}
export function worldReducer(previous, event) {
const state = clone(previous);
switch (event.type) {
case EVENT_TYPES.PLAYER_MOVE: {
const dx = Number(event.dx) || 0;
const dy = Number(event.dy) || 0;
const magnitude = Math.hypot(dx, dy) || 1;
const nextX = clamp(state.player.x + (dx / magnitude) * state.player.speed, WALKABLE_BOUNDS.minX, WALKABLE_BOUNDS.maxX);
const nextY = clamp(state.player.y + (dy / magnitude) * state.player.speed, WALKABLE_BOUNDS.minY, WALKABLE_BOUNDS.maxY);
if (!state.districts.some((district) => circlesOverlap(nextX, nextY, district))) {
state.player.x = nextX;
state.player.y = nextY;
state.player.step = (state.player.step + 1) % 4;
}
state.player.facing = Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? 'east' : 'west') : (dy > 0 ? 'south' : 'north');
return state;
}
case EVENT_TYPES.SELECT_DISTRICT: {
const district = findDistrict(state, event.districtId);
state.selectedDistrictId = district.id;
state.selectedFileId = district.files[0]?.id || null;
state.feedback = `${district.name} selected. Press Enter or E to inspect.`;
return state;
}
case EVENT_TYPES.SELECT_FILE:
state.selectedFileId = event.fileId;
state.activePanel = 'file';
state.feedback = `Inspecting ${selectedFile(state).name}`;
return state;
case EVENT_TYPES.SELECT_COLLECTION:
state.selectedCollection = event.collection;
state.activePanel = 'collection';
return state;
case EVENT_TYPES.SELECT_RECORD:
state.selectedRecord = { type: event.recordType, id: event.recordId };
state.activePanel = 'record';
return state;
case EVENT_TYPES.OPEN_INSPECTOR:
state.activePanel = 'inspector';
state.feedback = `Inspecting ${findDistrict(state, state.selectedDistrictId).path}`;
return state;
case EVENT_TYPES.CLOSE_INSPECTOR:
state.activePanel = 'world';
return state;
case EVENT_TYPES.ENTER_DISTRICT: {
const district = findDistrict(state, event.districtId || state.selectedDistrictId);
state.selectedDistrictId = district.id;
state.selectedFileId = district.files[0]?.id || null;
state.activePanel = 'inspector';
state.view = 'district';
state.feedback = `Entered ${district.path}. Code is physical here.`;
pushEvent(state, makeEvent(EVENT_TYPES.ENTER_DISTRICT, state.tick, { message: `Player entered ${district.path}.`, districtId: district.id }));
return state;
}
case EVENT_TYPES.OPEN_TERMINAL:
state.terminal.open = true;
state.activeTool = 'terminal';
state.activePanel = 'terminal';
state.feedback = 'Terminal phone online. Commands are simulated locally.';
return state;
case EVENT_TYPES.CLOSE_TERMINAL:
state.terminal.open = false;
if (state.activePanel === 'terminal') state.activePanel = 'world';
return state;
case EVENT_TYPES.RUN_COMMAND: {
const command = String(event.command || '').trim().toLowerCase();
if (!command) return state;
state.terminal.command = command;
state.terminal.lines = [...state.terminal.lines, ...event.lines].slice(-28);
state.feedback = 'Ran `' + command + '` in the simulated terminal.';
pushEvent(state, makeEvent(EVENT_TYPES.USE_TOOL, state.tick, { message: `Terminal ran ${command}.`, toolId: 'terminal' }));
return state;
}
case EVENT_TYPES.USE_TOOL: {
state.activeTool = event.toolId;
if (event.toolId === 'terminal') state.terminal.open = true;
if (event.toolId === 'git') { state.selectedCollection = 'commits'; state.activePanel = 'collection'; }
if (event.toolId === 'docker') { state.selectedCollection = 'build'; state.activePanel = 'collection'; }
if (event.toolId === 'code') state.activePanel = 'file';
if (event.toolId === 'ssh') { state.unlocked = true; state.activePanel = 'inspector'; }
if (event.toolId === 'database') { state.selectedCollection = 'files'; state.activePanel = 'collection'; }
if (event.toolId === 'deploy') { state.repository.deployment = 'LAUNCHING'; state.selectedCollection = 'build'; state.activePanel = 'collection'; }
state.feedback = event.message || `Equipped ${event.toolId}.`;
pushEvent(state, makeEvent(EVENT_TYPES.USE_TOOL, state.tick, { message: state.feedback, toolId: event.toolId }));
return state;
}
case EVENT_TYPES.TICK:
state.tick += 1;
return state;
case EVENT_TYPES.AGENT_PROGRESS: {
const agent = state.agents.find((candidate) => candidate.id === event.detail.agentId);
if (agent) agent.progress = Math.min(100, agent.progress + 2);
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
}
case EVENT_TYPES.CONSTRUCTION: {
const districtId = event.detail.districtId;
state.construction[districtId] = clamp((state.construction[districtId] || 0) + (event.detail.amount || 0), 0, 1);
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
}
case EVENT_TYPES.BUILD_STARTED:
state.repository.build = 'RUNNING';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.BUILD_COMPLETED:
state.repository.build = 'PASSING';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.TEST_STARTED:
state.repository.tests = 'RUNNING';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.TEST_COMPLETED:
state.repository.tests = '142 PASS';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.DEPLOYMENT_STARTED:
state.repository.deployment = 'LAUNCHING';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.DEPLOYMENT_COMPLETED:
state.repository.deployment = 'STAGED';
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
case EVENT_TYPES.COMMIT:
case EVENT_TYPES.ISSUE:
case EVENT_TYPES.PULL_REQUEST:
pushEvent(state, makeEvent(event.type, state.tick, event.detail));
state.feedback = event.detail.message;
return state;
default:
return state;
}
}
export function advanceWorldState(state) {
const ticked = worldReducer(state, { type: EVENT_TYPES.TICK });
const plan = SIMULATION_SEQUENCE[(ticked.tick - 1) % SIMULATION_SEQUENCE.length];
const event = makeEvent(plan.type, ticked.tick, plan.detail);
return { state: worldReducer(ticked, event), event };
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }[character]));
}
function windowBlocks(count, color) {
return Array.from({ length: count }, (_, index) => `<i class="building-window" style="--window-index:${index};--window-color:${color}"></i>`).join('');
}
export function renderWorld(viewport, state, onBuildingSelect) {
const viewportWidth = viewport.clientWidth || 960;
const viewportHeight = viewport.clientHeight || 680;
const centerX = viewportWidth / 2;
const centerY = viewportHeight * 0.56;
const translateX = centerX - state.player.x * 0.88;
const translateY = centerY - state.player.y * 0.88;
const buildingMarkup = state.districts.map((district) => {
const selected = district.id === state.selectedDistrictId ? ' is-selected' : '';
const progress = Math.round((state.construction[district.id] || 0) * 100);
return `<button class="world-building building-${district.id}${selected}" data-district-id="${district.id}" aria-label="Inspect ${escapeHtml(district.name)}" style="--building-x:${district.x}px;--building-y:${district.y}px;--building-w:${district.width}px;--building-h:${district.height}px;--district-accent:${district.accent};--construction:${progress}%">
<span class="building-cap"></span>
<span class="building-facade">${windowBlocks(district.id === 'src' ? 20 : 12, district.accent)}</span>
<span class="building-sign"><b>${escapeHtml(district.glyph)}</b>${escapeHtml(district.name)}</span>
<span class="building-status">${progress}% BUILT</span>
<span class="building-floor"></span>
</button>`;
}).join('');
viewport.innerHTML = `<div class="world-canvas" style="transform:translate(${translateX}px,${translateY}px) scale(.88)">
<div class="distant-skyline" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
<div class="moon-orb" aria-hidden="true"></div>
<div class="world-ground" aria-label="Walkable GitWorld repository city">
<div class="ground-grid"></div>
<div class="road road-main"><span>MAIN</span></div>
<div class="road road-cross"><span>HISTORY</span></div>
<div class="road road-branch"><span>BRANCH / ALT</span></div>
<div class="plaza"><span>SPAWN PLAZA</span></div>
${buildingMarkup}
<div class="construction-crane crane-one" aria-hidden="true"><i></i><b></b><em></em></div>
<div class="construction-crane crane-two" aria-hidden="true"><i></i><b></b><em></em></div>
<div class="agent-bot bot-a" aria-label="Simulated world architect builder"><i></i><b></b></div>
<div class="agent-bot bot-b" aria-label="Simulated repository builder"><i></i><b></b></div>
<div class="quest-marker">!</div>
<div class="pr-gate"><span>PULL REQUEST</span><b>OPEN GATE</b></div>
<div class="player-avatar" data-facing="${state.player.facing}" aria-label="AhmadParr avatar" style="left:${state.player.x}px;top:${state.player.y}px">
<span class="avatar-shadow"></span><span class="avatar-legs"><i></i><i></i></span><span class="avatar-body"><i class="avatar-pack"></i></span><span class="avatar-head"></span>
</div>
<div class="world-sign repo-sign"><small>SIMULATED REPOSITORY</small><strong>SNAPKITTYWEST</strong><b>/ pax-coder</b><em>★ 213 · ⑂ 45 · ◉ PUBLIC</em></div>
<div class="world-sign build-sign"><small>BUILD AGENTS</small><strong>3 ACTIVE</strong><b>WATCH THE CREW WORK</b></div>
</div>
</div>`;
viewport.querySelectorAll('[data-district-id]').forEach((building) => {
building.addEventListener('click', () => onBuildingSelect(building.dataset.districtId));
});
}
export function renderMinimap(root, state) {
const districts = state.districts.map((district) => `<button class="minimap-district" data-district-id="${district.id}" aria-label="Map ${escapeHtml(district.name)}" style="left:${district.x / 16}px;top:${district.y / 9.2}px;background:${district.accent}"></button>`).join('');
root.innerHTML = `<div class="minimap-grid" aria-label="GitWorld district map"><div class="map-road map-road-a"></div><div class="map-road map-road-b"></div>${districts}<span class="map-player" style="left:${state.player.x / 16}px;top:${state.player.y / 9.2}px"></span></div><div class="map-caption"><span>LIVE MAP</span><b>${state.selectedDistrictId.toUpperCase()}</b></div>`;
}