From ea3c40fffa54f2dc04849464f88015fd893cca62 Mon Sep 17 00:00:00 2001 From: ActArtech <123718991+ActArtech@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:33:58 +0400 Subject: [PATCH] docs(hagia-sophia): file empty-viewport postmortem, geometric modeling standard, and learning-version workflow Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- wiki/empty-viewport-postmortem.md | 51 ++++++++++++++ wiki/hagia-sophia-modeling-standard.md | 95 ++++++++++++++++++++++++++ wiki/learning-versions.md | 60 ++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 wiki/empty-viewport-postmortem.md create mode 100644 wiki/hagia-sophia-modeling-standard.md create mode 100644 wiki/learning-versions.md diff --git a/wiki/empty-viewport-postmortem.md b/wiki/empty-viewport-postmortem.md new file mode 100644 index 0000000000..61b74c268b --- /dev/null +++ b/wiki/empty-viewport-postmortem.md @@ -0,0 +1,51 @@ +# Postmortem: Scene loads but viewport appears empty (2D and 3D) + +**Date:** 2026-09-03 +**Environment:** `apps/editor` standalone app, Next.js 16.2.9 (Turbopack), dev server on :3002, Windows +**Scene:** `bbca88920109` ("hagia-sophia-ground-floor", 104 nodes — site → building → level → 101 `hagia-sophia:*` plugin nodes) + +## Symptom + +Scene list shows the scene with the correct node count, editor chrome renders (catalog, tabs, level badge), zero console errors — but the viewport shows only the orange site outline and ground plate. No geometry in 2D or 3D. Affected **both** the Hagia Sophia scene and simpler scenes (e.g. garden-house), though less visibly. + +Three independent bugs stacked on top of each other produced this. All three had to be fixed before the model appeared. + +--- + +## Bug 1 — Camera auto-framing was accidentally deleted + +- **File:** `packages/editor/src/components/editor/index.tsx` +- **Introduced by:** commit `e688792c` "Refactor first-person and spawn selection handling" (Apr 29) — removed both the `useAutoFrame` import and the `useAutoFrame()` call. +- **Effect:** nothing emitted `camera-controls:fit-scene` when a scene loaded, so the camera stayed at the hardcoded first-load default `setLookAt(20, 20, 20, ...)` (`custom-camera-controls.tsx`). For any building larger than ~20 m the camera sits inside the footprint → "empty" view with zero errors. +- **Fix:** re-added the import and the `useAutoFrame()` call in the Editor component. + +## Bug 2 — Level-follow effect clobbered the framing right after it ran + +- **File:** `packages/editor/src/components/editor/custom-camera-controls.tsx` (level-follow effect) +- **Effect (proven with temporary `[cam-debug]` logs in the dev log):** on load the sequence was: auto-frame emit → `fit-scene` handled → camera framed correctly → *then* the level-follow effect ran for the first time (`currentLevelId: null → 'level_…'`) with `firstLoadWas: true` and executed `setLookAt(20,20,20,0,0,0)` + `moveTo(0, 0, 0)` — teleporting the camera back inside the building. On slow (direct URL) loads a later scene re-apply re-framed and masked the bug; on fast (client-side navigation from `/scenes`) loads nothing did. +- **Fix:** the first-load default pose now only applies when the scene store is empty (scene-less editor), and `moveTo` on level change only fires on a *real* level switch (`previousLevelId !== null && previousLevelId !== currentLevelId`) — the initial `null → level` transition is skipped. +- **Hardening:** added a last-word re-frame effect in `index.tsx` that emits `camera-controls:fit-scene` once the viewer signals scene-ready, so any load-driven camera effect that runs after auto-frame cannot win. + +## Bug 3 — Scene's `installedPlugins` list excluded the Hagia Sophia plugin (the actual "nothing renders" cause) + +- **Mechanism:** the scene graph stores an explicit `installedPlugins` array. `NodeRenderer` (`packages/viewer/src/components/renderers/node-renderer.tsx`) calls `isNodeKindEnabled(node.type, installedPlugins)` (`packages/core/src/registry/registry.ts`) and returns `null` for kinds whose plugin id is not in the list — in **both 2D and 3D**. This scene's list was `["pascal:trees", "pascal:streetscape"]` with no `"pascal:hagia-sophia"`, so all 101 hs-\* nodes rendered nothing despite `visible: true` and intact geometry definitions. +- **Why the list was stale:** `applySceneGraphToEditor` (`packages/editor/src/lib/scene.ts`) uses a scene's `installedPlugins` verbatim when present (`hasExplicitPluginInstallState: true`); default-installed plugins never apply. The list was frozen at an early save before the HS plugin existed, and explicitly-installed lists never pick up plugins added later. +- **Fix (data, not code):** added `"pascal:hagia-sophia"` to the scene's `installedPlugins` via `PUT /api/scenes/bbca88920109` (scene now v12, all 104 nodes intact). Verified headless: dome + colonnade render. + +--- + +## Verification + +Headless (patchright) fresh loads and the real user flow (`/scenes` → open scene): camera frames the colonnade, dome geometry visible in 3D. Confirmed by the user locally after hard refresh. + +## Known issues discovered on the way (unfixed) + +1. **`PUT /api/scenes/:id` returns 500 but commits.** Response: `{error: "internal_error", message: "cannot commit - no transaction is active"}` — yet each PUT bumps the version and persists. The failure is in a secondary transaction after the main save (likely the SSE event append) in `packages/mcp/src/storage/sqlite-scene-store.ts`. Editor autosaves go through the same endpoint: data lands, but users see spurious save errors. **Note:** the storage layer is under active refactor (sqljs/SQL.js driver work in the working tree) — validate against that branch first. +2. **Design flaw — plugin install state freezes.** Defaults are frozen into each scene as explicit state, so any plugin added *after* a scene was created never applies to it. Every pre-existing scene has this problem. Needs a migration (add newly-registered always-on plugins to existing scenes) or a policy change (fall back to registry defaults when the scene's list predates a plugin). +3. **Dev-global probes unreliable via `page.evaluate`** on this app (`window.__pascalCameraControls`, `window.__pascalNodeRegistry` read as undefined even when the setting code provably runs). Trust `[browser]`-prefixed dev-log lines and screenshots over in-page evaluate probes when debugging this app headlessly. + +## Files changed (code fixes, uncommitted at time of writing) + +- `packages/editor/src/components/editor/index.tsx` — restore `useAutoFrame` import + call; viewer-ready re-frame effect. +- `packages/editor/src/components/editor/custom-camera-controls.tsx` — level-follow clobber fix; dev-global gate removed (`process.env` is not statically replaced in source-aliased workspace packages under Turbopack, so the gate threw client-side). +- Scene data: `bbca88920109.installedPlugins += "pascal:hagia-sophia"`. diff --git a/wiki/hagia-sophia-modeling-standard.md b/wiki/hagia-sophia-modeling-standard.md new file mode 100644 index 0000000000..dc9b6245a4 --- /dev/null +++ b/wiki/hagia-sophia-modeling-standard.md @@ -0,0 +1,95 @@ +# Hagia Sophia — Geometric Modeling Standard (Symmetria Spec) + +**Status:** Project modeling standard for the `plugin-hagia-sophia` reconstruction +**Applies to:** `packages/editor`, `packages/mcp` (scene tools), `plugin-hagia-sophia` +**Companion doc:** [learning-versions.md](./learning-versions.md) — how each version of the model is produced and documented +**Postmortem for the session that produced this standard:** [empty-viewport-postmortem.md](./empty-viewport-postmortem.md) + +--- + +## 0. Scope and historicity + +This document defines the **parametric design spec used by this project's reconstruction** — it is the convention contributors must follow so every version of the model is built the same way. + +Claims fall into two classes and are labeled accordingly throughout: + +- **[H]** Historical (mainstream scholarship): construction 532–537 CE; architects Anthemius of Tralles and Isidore of Miletus; great dome ≈ 31 m diameter; nave arcades in six divisions per side; imperial monograms of Justinian and Theodora as marble roundels. +- **[S] Spec convention** (this project's design system, not established historical fact): the monogram-diameter module, the 6 → 10 → 16 → 60 → 360 number progression, the π-bearing latitude reference, the Lyra/Vega celestial mapping, and the 123.6° entrance heading. These govern **how we generate the model**, not what we claim about the building. + +--- + +## 1. Design philosophy: symmetria + +Every element is an integer multiple of one module, so the whole model is generated from a single number [S]. In the parametric pipeline this is enforced literally: no dimension may appear in code that is not `n × D` for an integer `n` from the approved set `{6, 10, 16, 36, 60, 360}`. + +## 2. The module: monogram diameter `D` + +- **[H]** The imperial monograms of Justinian and Theodora (carved in marble within white marble rings) are the symbolic reference. +- **[S]** Their diameter `D` is the fundamental unit of the reconstruction. +- **Derived scale:** the great dome ≈ 31 m [H] is 60 units [S] → **D ≈ 0.517 m**. All scene coordinates are meters computed from this. +- **Open question (flagged, unresolved):** 360 D for the entrance→apse nave length gives ≈ 186 m, which exceeds the historical footprint. Either the multiplier applies to a different span (nave *width* system, full nave + atrium) or the count is not a length. Do not silently "fix" this — versions must record their interpretation in the version doc. + +## 3. Modular scaling table + +| Multiplier | Dimension in units | Element | +|---|---|---| +| ×1 | 1.0 | Monogram diameter — primary reference circle | +| ×6 | 6.0 | Column capital height | +| ×6 | 6.0 | Queen's circle (Theodora's position) diameter | +| ×16 | 16.0 | Coronation central disc diameter | +| ×36 | 36.0 (6×6) | Emperor's entrance height | +| ×60 | ≈31 m | Great dome diameter (also the divine/star unit ×10 reference) | +| ×360 | — | Nave length, imperial entrance → apse (**unresolved**, see §2) | + +**Number progression:** 6 → 10 → 16 → 60 → 360 [S]. Ratios 6:10, 10:16, 16:60, 60:360. Pythagorean rationale: 6 perfect (1+2+3 = 6, 1×2×3 = 6); 10 tetractys/divine; 16 = 4² material completion; 60 = 6 × 10; 360 full circle. + +## 4. Circle network + +1. **Primary [H/S]:** monogram roundels — marble with white ring banding; above the imperial entrance, at Theodora's honor position, at the coronation site. +2. **Secondary [H/S]:** the great dome (~31 m) with its white fenestration ring; six arcade openings per nave side; six groups of six columns. +3. **Tertiary [S]:** ceremonial floor discs — 16 banded (white marble band) + 16 unbanded; coronation central disc (16 D); queen's circle (6 D). + +All circular geometry is generated from radius and π; each circle's C/d is exactly π by construction, and tolerance checks below verify the built model honours that. + +## 5. Coordinate system for the model + +- **Origin:** the imperial entrance threshold. +- **+X** = east (along the 28.9800° E longitude axis) [S]; **+Z** = north (toward 41.0085° N, the π-bearing latitude reference) [S]; **+Y** = up. +- **Entrance heading:** 123.6° clockwise from true north defines the nave axis [S]. Convert to the editor's Y-rotation convention when placing oriented kinds. +- **Grid unit:** `D ≈ 0.517 m`. Snap positions to multiples of D/2 where subdivision is needed. + +## 6. Mapping to pascal node kinds + +| Element | Kind | Status | +|---|---|---| +| Columns (6 groups × 6) | `hagia-sophia:column` | exists (colonnade scenes) | +| Arches / arcades | `hagia-sophia:arch` | exists | +| Great dome + semi-domes | `hagia-sophia:dome` | exists | +| Pendentives | `hagia-sophia:pendentive` | exists | +| Piers | `hagia-sophia:pier` | exists | +| Floor discs (32) | `hagia-sophia:disc` (variant: banded/unbanded) | **proposed** | +| Monogram roundels (wall) | `hagia-sophia:medallion` | **proposed** | + +Geometry-only kinds (per `wiki/architecture/node-definitions.md`): `def.geometry` + `GeometrySystem` own the mount; no custom renderer/system/tool unless interaction demands it. + +## 7. Model validation checklist (per version) + +These are **checks on the generated model** (headless screenshots + scene queries via MCP), reproducible in CI or a verify script: + +1. All multiples are integer multiples of D (spot-check capital heights = 6 D, queen's circle = 6 D, coronation disc = 16 D, entrance height = 36 D). +2. Every circular kind's geometry uses radius×π paths (no polygonal approximations above 0.5% chord error). +3. Counts match the spec: 6 groups of 6 columns; 6 arcade divisions per side; 16 + 16 floor discs. +4. Mirror symmetry about the nave axis: paired element positions differ by < 1% of span. +5. Entrance heading applied: nave axis at 123.6° from north (compare against site outline). +6. Version doc records any interpretation decisions (esp. the ×360 tension in §2). + +## 8. Glossary + +| Term | Meaning | +|---|---| +| Symmetria | Balance/harmony of all elements through numerical ratios [S] | +| `D` | Monogram diameter — the module (≈ 0.517 m derived) [S] | +| Tetractys | Pythagorean 1-2-3-4-10 divine number [S] | +| Vega / Lyra | Celestial counterpart to the entrance / aligned constellation [S] | +| Ring Nebula (M57) | Ringed celestial object paralleling the circle motif [S] | +| Banded disc | Floor disc with white marble ring (one of 16) [S] | diff --git a/wiki/learning-versions.md b/wiki/learning-versions.md new file mode 100644 index 0000000000..a395fe4767 --- /dev/null +++ b/wiki/learning-versions.md @@ -0,0 +1,60 @@ +# Learning Versions — Workflow + +**Purpose:** make the Hagia Sophia reconstruction a documented, open-source learning journey. Every iteration of the model is a **version**: a scene snapshot produced through the Pascal MCP, plus a wiki page explaining what changed, why, and what was learned. PRs stack so each step is reviewable in isolation. + +**Spec:** [hagia-sophia-modeling-standard.md](./hagia-sophia-modeling-standard.md) +**Postmortem:** [empty-viewport-postmortem.md](./empty-viewport-postmortem.md) + +--- + +## 1. What a learning version is + +| Artifact | Where | +|---|---| +| Scene snapshot (versioned save) | scene store, via Pascal MCP | +| Geometry export | `export-json` output archived in `wiki/versions/assets/` (optional) | +| Screenshot | `wiki/versions/assets/.png` | +| Version page | `wiki/versions/.md` | +| Code changes | one PR in the stack (if code changed) | + +## 2. Workflow (via the Pascal MCP) + +The MCP server (`packages/mcp`, stdio or HTTP transport) exposes the scene tools used below. Every version is created **through the MCP**, never by editing the DB directly: + +1. `list-scenes` — locate the working scene (e.g. `hagia-sophia-ground-floor`). +2. `get-scene` / `scene-query` / `find-nodes` — read current graph state. +3. `apply-patch` / `place-item` / `create-level` / geometry kinds — make the iteration's change. +4. `save-scene` — persist; the store bumps the scene version (this is the version marker). +5. Verify headless (fresh load of the scene URL, screenshot) — record console errors as evidence of a clean run. +6. Write `wiki/versions/.md`: goal, graph delta (nodes added/changed with counts), spec sections exercised, interpretation decisions (§2/§7 of the standard), screenshot reference, MCP commands used. +7. If code changed to enable the version, that change lands as its own PR in the stack; the version page links the PR. + +**Naming:** `hs-v-` (e.g. `hs-v1-massing`, `hs-v2-colonnade`, `hs-v3-dome`). Scene save metadata records the same label in the scene name suffix. + +## 3. PR stack + +Each PR builds on the previous branch; merge order = stack order. No PR mixes docs + code unless the code exists only to serve the doc. + +| # | Branch | Type | Contents | +|---|---|---|---| +| 1 | `docs/hs-standard` | docs | postmortem + modeling standard + this workflow doc | +| 2 | `fix/camera-framing` | fix | restore `useAutoFrame`; level-follow clobber fix; viewer-ready re-frame | +| 3 | `fix/scene-put-transaction` | fix(mcp) | PUT `/api/scenes/:id` 500-but-commits (secondary transaction) | +| 4 | `fix/installed-plugins-migration` | feat(editor) | stale `installedPlugins` fallback/migration for pre-existing scenes | +| 5+ | `feat/hs-` | feat(plugin) | kinds/features needed by learning versions (e.g. `hagia-sophia:disc`, `hagia-sophia:medallion`) | + +## 4. Version log + +| Version | Scene version | Goal | Doc | +|---|---|---|---| +| (baseline) | bbca88920109 v12 | colonnade + dome mass, renders correctly | — | +| hs-v1-massing | planned | site + level + massing boxes to spec grid | _pending_ | +| hs-v2-colonnade | — | 6 groups × 6 columns on module | _pending_ | +| hs-v3-dome | — | dome + pendentives on 60-unit ring | _pending_ | + +## 5. Rules for contributors + +- One version = one purpose = one doc page. No "misc improvements" versions. +- Every dimension in a version traces to the standard's scaling table; anything else is flagged in the version doc, not hidden. +- Never edit scene data outside the MCP tools (the API path silently 500s post-commit until the transaction fix lands — see postmortem §1). +- Screenshots are evidence: include the viewport after a clean fresh load, with console error count. \ No newline at end of file