# WebGL 3D UI Specification And Implementation Plan This document captures the agreed direction for the WebGL book UI. Later decisions override earlier ones. The purpose is to stop visual regressions and make future implementation work testable against an explicit contract. ## Current Goal Build a beautiful, readable, extensible WebGL book interface for the interactive fiction UI. The current stable milestone is the integrated 3D game UI at `http://localhost:3001/`: an open procedural book lying on a polished wooden table, lit by flickering candles, with game content typeset directly into texture-space canvases and applied to the actual top surfaces of the paper stacks. The product goal is a procedural book UI that supports virtual scrolling, animated page flips, dynamic page stacks, and content backfilling across spreads. ## Current Implementation Snapshot This section records the current state after the procedural book integration work. - The active integrated scene is loaded through the game at `http://localhost:3001/`. - `public/webgl-book-lab.html` remains a reference/prototype file, not the primary implementation target. - The current test server is expected to be the single Node process listening on port `3001`. - The procedural book model lives in `public/js/procedural-book-model.js`. - The WebGL lab integration lives in `public/js/webgl-book-lab.js`. - The old fixed-box book has been removed from the lab scene. - The new procedural book is generated from fixed page dimensions, a calculated spine arc, cover panels, hinge panels, page-stack spline lines, stack bodies, and animated flipping page geometry. - Book page count is clamped to 40-500 pages. - Page count changes in 10-page bundle increments. - Each visible bundle line represents 10 pages. - Reading progress controls the left/right split of page bundles along the spine arc. - The spine grows with page count and pushes the covers outward; the covers do not shrink to pay for spine growth. - `PAGE_SPLINE_LENGTH` must match `PAGE_WIDTH`. - Cover width is derived from page width plus cover overhang. - The spine bottom is aligned to the table plane with only a tiny render clearance. - The book navigation controls are the bottom media-style navigation controls: return to beginning, flip backward, page-position scrollbar, flip forward, and go to end. - Slow page flips and fast 10-page transitions are implemented. - Fast transitions run overlapping flip animations before shifting the book by one bundle. - The readable page content belongs on the visible top cap of the paper stacks. - No separate floating reading-surface overlay should be added on top of the stack cap. - Extreme progress states must use the same top-cap/material topology as normal stack states. - Synthetic hair/support pages used for empty-side extremes must not receive page content if they are not the actual readable stack top. - The spine arc and cloth spine must not receive page-content textures. - Page-content textures are high-resolution canvas textures with hardcover-style margins. - The current page canvases are deliberately smoother than the old noisy page texture. - The animated flipping page uses its own clean paper material (`flipPageSurface`) instead of the resting page material, so motion does not reveal stationary paper grain, stack-line textures, content textures, or construction patterns. - Page-stack side lines are generated as textures, not as free-standing line meshes. - Stack side textures should have consistent orientation and line count on all visible stack sides. - Cover, hinge, spine base, and cover edge materials use leather-style materials with procedural leather color and normal maps. - Cloth spine head/end-bands are real small raised meshes with their own woven red/ivory texture material, not painted stripes on the spine cloth shader. - The book, table, candles, and flipping pages have `castShadow` and `receiveShadow` disabled. - Three.js/OpenGL primitive shadows must stay disabled. - Candle shadows are implemented in the custom table/book shader path, not through Three.js shadow maps. - Scene SSAO is present as a postprocessing pass. The procedural book, head/end-bands, and flip page are normal scene participants unless a mesh is explicitly added to `aoExcludedObjects`; flames and glow sprites remain excluded. - The table reflection path remains active and should include the book and candles. - The custom book material shader includes a small local indirect/bounce-light term for book surfaces. This is not emissive; it is multiplied by material albedo so paper, leather, and head/end-band colors remain distinct while shadowed side faces stay readable. - Temporary screenshots and generated debug images are not product assets unless explicitly promoted. ## Current Page-Flow Architecture The 3D book pipeline is module-owned. No page content should be generated by ad hoc scene code. - `ui-display-handler` owns the live 3D prepare -> optional page flip -> activate sequence for story text. - `sentence-queue` may prepare future page presentations during lookahead using the same pagination and texture renderer modules. - `book-pagination` owns page/spread construction, page metadata, widows/orphans/hyphenation decisions, image placement decisions, and explicit blank/title/body page records. - `book-texture-renderer` owns drawing final page canvases, reveal-region coordinates, reveal timing metadata, and publishing explicit `webgl-book:page-texture-records`. - `webgl-page-cache` owns persistent page canvases, memory canvases, prepared reveal plans, prepared GPU textures, resident VRAM textures, blank page texture, and visible texture bindings. - `webgl-book-lab` owns the Three.js scene, materials, geometry, pointer projection, page flip meshes, and consuming page texture records. It must not become a second page cache. Problem states must be surfaced instead of hidden: - A missing persistent page canvas during prewarm is a `db-cache-miss`. - A missing source or required back texture before a page flip is a `flip-source-texture-missing` or `flip-back-texture-missing`. - These problem states must appear in `webglPageCacheProblems` and must not be silently fixed by borrowing unrelated visible stack textures. ## Event Surface The preferred 3D book content path is direct module calls through `ui-display-handler` for live playback and `sentence-queue` for lookahead preparation. The following events remain formal integration events and must keep their meaning stable while they exist: - `webgl-book:page-texture-records` publishes explicit page texture records from `book-texture-renderer` to the WebGL scene. - `webgl-book:page-reveal-start` starts shader reveal timing for the prepared block. - `webgl-book:page-reveal-fast-forward` accelerates reveal timing without replacing the page pipeline. - `webgl-book:reveal-committed` reports that a page-side reveal completed; if `pageFlipAfterReveal` is true, the WebGL scene may arm a page flip. - `webgl-book:request-page-flip` requests a physical page flip through the WebGL scene. - `webgl-book:page-flip-started`, `webgl-book:page-flip-near-end`, and `webgl-book:page-flip-finished` describe the physical flip lifecycle. Deprecated or forbidden event contracts: - `webgl-book:page-canvases` is obsolete. New code must use `webgl-book:page-texture-records`. - `preloadOnly` and `allowFutureUnrendered` are obsolete boolean flags. New code must use explicit `phase` and `visibility` values. ## Non-Negotiable Workflow Rules - Do not continue visual coding without a concrete plan for the current sprint. - Before tuning a visual feature, first prove it is active. - Debug views must prove the feature in isolation. - Composite views must prove the feature affects the final image. - If a feature is broken or inactive, do not treat it as an intensity/tuning problem. - Do not replace a working feature while implementing a new one unless the replacement is proven better in debug and composite views. - Do not commit untested visual changes. - Commit stable major changes before starting a new topic. - Do not leave orphaned dev servers, Node processes, Playwright processes, or browser automation processes. - Do not regenerate expensive textures in memory during page load once the design asset is stable. Generate them once, save them to disk, and load static assets. - Do not use fake visual shortcuts once a shader or proper rendering path has been agreed. - Do not introduce fallback visual cheats when the agreed task fails. If the real technique is not working, stop, document the failure, and investigate the real technique. - Do not let a fallback or diagnostic layer become part of the final composite unless it is explicitly approved as a permanent art-direction layer. - When screenshot capture fails, fix the capture/test tooling before continuing visual iteration. - Do not enable `renderer.shadowMap.enabled`. - Do not set any mesh `castShadow` or `receiveShadow` flag to `true`. - Do not use Three.js primitive shadow maps as a fallback for candle shadows. - Candle shadows must remain a custom shader responsibility. ## Repository And Branch Rules - Work is on branch `webgl`. - Do not stage or commit unrelated `.env` changes. - Temporary screenshots are not product assets and should not be committed unless explicitly requested. - Generated static visual assets may be committed when they are part of the scene contract. - Documentation changes must use `apply_patch`. ## Scene Structure The final UI module must remain compatible with the rest of the project, but its rendered layout changes from a flat static page into a layered 3D interface. Required structure: - One WebGL canvas as the main scene. - One top menu line over the canvas. - One modal overview layer over the canvas. - Existing modal behavior must remain compatible with the rest of the app. - The 3D book pages must display the actual app content as dynamic textures, not overlays placed above the model. During visual development: - Use an independent standalone page for the 3D scene. - The standalone page must not be burdened by the app loader, modal system, or unrelated runtime while the visual design is being finalized. - The standalone scene must remain modular enough to later integrate back into the actual app shell. ## Book Requirements ### Current Milestone - The book is procedural unless a suitable real model is found and integrated correctly. - The book must look like a real open book, not a thin folio. - The book must lie flat and straight on the table. - The lower book edge should run parallel to the screen edge in the default reading camera. - The camera angle must be shallow enough for readability, not steep overhead. - The book must show the two current app pages as dynamic page textures. - The page aspect ratio and content must mirror the original book display as closely as possible. - The right page must not be mirrored or rotated incorrectly. - Text must be crisp enough for reading. - Page texture resolution must be high enough that the projected text remains crisp at intended camera distances. - The old UI/html creation module must be kept for reference while the new module replaces it. - The open book is made from named parts: - Spine: the central cloth/red arc and supporting center area. - Hinge: the angled transition from spine top height to cover/table height. - Cover: the main leather cover panel that supports each page stack. - Cover overhang: the small cover border extending beyond the paper stack. - The hinge width is the width required to descend from spine-top height to spine-bottom/table height at the chosen 45 degree hinge angle. - The cover starts at spine-top height near the hinge and descends until its outer edge touches the table. - The cover must extend under the page stack by the same overhang along book width as along book depth. - The paper stack must have closed bottom geometry where needed; it must not reveal empty inside faces from below. - The paper stack top is the readable content surface. - At progress `0.00`, `0.03`, `0.07`, and other extreme values, the surface topology and material assignment must remain consistent. - The right page must not become a different material or broken cap merely because the left side has no full stack yet. ### Later Product Goal The book should become a dynamic procedural object: - Both left and right pages are used for content. - Virtual scrolling drives page content. - The last two spreads are backfilled with virtual content. - Page flips animate between spreads. - When the user scrolls far through history, multiple quick page animations can occur. - The left stack height grows as reading progresses. - The right stack height shrinks or remains tied to the remaining book thickness. - Page stack thickness must visibly change as a progress marker. - The right side begins as the thicker unread portion. - The left side grows from a few pages toward parity with the right stack. - Individual pages can animate between stacks. - The architecture must allow page geometry, page textures, stack heights, and flip animation to be controlled separately. ## Page Texture Requirements - Page content must be rendered into textures applied to the actual page geometry. - No separate reading-surface overlay on top of the book model. - The visible top cap of the paper stack is the page display surface. - Do not add a coincident floating page mesh over the stack cap to display content; that creates z-fighting risk and violates the intended architecture. - If the page content is wrong at an extreme progress state, fix the stack-cap topology or material assignment, not by adding a second page surface. - The left page texture must contain the full left page of the old layout. - The right page texture must contain the dynamic typeset text from the original module. - Text and lines must respect the original page proportions. - Texture capture/generation must not silently crop the content. - The page texture pipeline must support future virtualized content. - Page content should use typical hardcover novel margins: - Larger inner/gutter margin. - Smaller outer margin. - Comfortable top margin. - Larger bottom margin. - The DOM/canvas source used for page content must have the same aspect ratio and orientation as the physical page surface. - Page textures must be smooth enough that projected content does not reveal unwanted construction lines, stack lines, or noisy paper grain. - Neutral paper texture and content-page texture should have compatible filtering, mipmapping, and anisotropy. - Spine arc, hinge, cloth, and support-strip materials must not accidentally receive page-content texture. - The animated flipping page must use a clean paper material separate from resting/content pages. It should keep scene lighting, custom book shadows, and local bounce light, but should not use the procedural paper color/normal pattern that can create visible moving grain or shader artifacts. ### Text Sharpness Notes - Current visible page content is rasterized into high-resolution canvas textures (`pageTextureWidth = 3200`) and then sampled on curved/angled 3D geometry. - Browser canvas text antialiasing, mipmap selection, linear filtering, anisotropy, page curvature, postprocessing, and viewing distance all affect perceived sharpness. This is not just a Windows font-rendering issue. - A single raster page texture cannot be perfectly sharp from every distance. Increasing the canvas to 4096 or 8192 can improve close views but costs memory and still depends on mipmap/filter behavior. - SDF means signed distance field: glyph edges are encoded as distances in a texture and reconstructed in the shader, allowing cleaner scalable edges than ordinary raster text. - MSDF means multi-channel signed distance field: edge distances are encoded across color channels, preserving corners and serifs better than single-channel SDF. MSDF is the better future path if page typography must stay crisp across camera distances. - SDF/MSDF text would require a separate text layout/rendering path or an MSDF font atlas. It should not be mixed into this sprint unless the raster canvas approach is proven insufficient. ## Camera Requirements Default reading camera: - The book lower edge is parallel to the screen edge. - The angle is slightly oblique, natural, and less steep than an overhead view. - The camera is close enough to make good use of the canvas. - The pages remain readable. - Candles remain visible as scene context without stealing focus. Interactive camera controls: - Mouse controls angle/orbit. - WASD moves the camera target through the scene. - Mouse wheel zooms. - Controls must not make the book drift or animate annoyingly when idle. ## Table Requirements - The table surface is polished dark wood. - It must reflect the book, candles, flames, and environment. - Reflection must be physically plausible for a flat polished surface. - Reflections must not be offset in a way that breaks the mirror illusion. - Table wood remains visible; reflection strength must not drown it out. - The table uses a subtle normal map to avoid perfect mirror flatness. - The normal map must be subtle, not a large wobble or warped surface. - Dust and fingerprint/grease maps are separate concepts: - Dust is tiny particles that slightly catch specular light. - Grease/fingerprints are smears that affect reflectivity/roughness. - Dust must not look like breadcrumbs, paint, or a color overlay. - Grease/fingerprint marks must be filled, small relative to the table, and plausible. - Fingerprints should suppress dust where fingers wiped the surface. - Dust and grease must influence reflection/specular behavior, not merely base color. - Static disk assets should be used for stable table maps. ## Environment Reflection Requirements - The generated room/environment image is a spherical/equirectangular reflection map. - It must be sampled as a 360 degree environment, not projected like a plane. - The spherical orientation must be correct: floorboards or room features must not appear in nonsensical directions. - The environment reflection applies to the table surface only unless explicitly intended elsewhere. - It must not incorrectly reflect on the book cover. - The environment map can contribute to candlelit ambient tone, but it must not become fake visible room geometry unless explicitly designed. ## Candle Requirements There are three candles on the table. Placement: - Candles are asymmetrically placed. - Candles have different heights. - One candle is upper left. - One candle is upper right. - One candle is lower right. - Candles must sit on the table, not float or sink. - Candle flames must sit on the wicks, not inside the wax body. Geometry: - Candle bodies are cylindrical, not cut-off cones. - Wicks are visible and correctly positioned. - Flames use two-layer teardrop geometry: - Hot white/yellow core. - Transparent orange outer flame. Flame shader: - Animated noise/displacement. - Alpha falloff. - Gradient from blue/dark wick base to yellow core to orange tip. - Subtle flame movement drives light motion and shadow motion. Wax shader: - Semi-translucent wax. - Simulated subsurface scattering. - Stronger light-dependent backscatter near the flame. - Soft glow through the upper wax body. - The wax material should be flame-aware. - Candle reflection should preserve the wax look as much as possible in the mirror render. ## Lighting Requirements - There is no window or other white external light source. - Candles are the only direct light sources. - The scene can include low warm ambient light representing candlelight reflected by room walls. - Candle point lights must be positioned at the animated flame positions in 3D space. - Lights should move subtly with the flames. - Each candle light must affect all relevant objects unless deliberately excluded for a documented reason. - The lighting on the book must be attributable to the candle lights and ambient candle bounce. - No unexplained fake light patches. ## Shadow Requirements This project does not use Three.js/OpenGL primitive shadow maps for the book, table, or candles. Shadows are owned by the custom shader pipeline. Required behavior: - Candle cast shadows must exist in the final composite. - All three candle bodies must cast visible shadows. - All three candle light/flame positions must participate. - The book must cast shadows onto the table from all three candles. - The paper stacks, visible page tops, covers, hinges, spine, candles, wax bodies, and table must use the custom shader lighting/shadow path where relevant. - The candle shadows must respect wax translucency conceptually: wax transmission should soften/reduce the shadow rather than creating hard opaque cylinder shadows. - Shadows should be soft and believable, not hard-edged cones or arbitrary blobs. - Shadows must move subtly with the animated flame/light positions. - Contact AO is not a substitute for candle cast shadows. - Reflections are not a substitute for candle cast shadows. - SSAO is not a substitute for candle cast shadows. - Candle shadows must not be weakened, removed, or repurposed while working on SSAO. - `renderer.shadowMap.enabled` must stay `false`. - `castShadow` and `receiveShadow` must stay `false` on scene meshes. Debug proof: - `tableDebug=shadow` must clearly show shadow contribution from all three candles. - The shadow debug must show all three candle bodies casting shadows from the relevant flame/light positions. - The final composite must visibly include those shadows. - If the debug view shows shadows but the composite does not, the feature is not complete. Implementation note: - `tableDebug=shadow` must remain dedicated to candle cast-shadow proof. - If SSAO conflicts with custom candle shadows or page readability, SSAO loses until it is redesigned. ## Ambient Occlusion Requirements AO must be separated conceptually from cast shadows. Required behavior: - AO darkens tight contact and crevice regions. - Candle bottoms should have local contact occlusion. - The book/table contact should have local occlusion. - AO should not appear as broad painted darkness. - AO should not treat flames or glow sprites as solid occluders. - The book should be an equal participant in AO computations. - Candle contact AO must come from the real AO solution, not from a hand-authored fallback masquerading as AO. - Analytic contact darkening is not accepted as the solution for AO. - The fallback analytic contact/shadow layer must be removed completely before continuing SSAO work. Current status: - Scene-level SSAO has been added as a Three.js `SSAOPass`. - Flames and glow sprites are excluded from AO. - The procedural book and animated flip page are currently excluded from AO because the previous AO interaction made the book look inset/incorrect and excluded the top page from the effect. - `tableDebug=ao` proves the pass is wired, but the current AO result is not the accepted final AO design. - AO work is paused until the book material/topology integration is stable. Debug proof: - `tableDebug=ao` should show scene-level SSAO. - `tableDebug=contact` is deprecated with the analytic fallback. If retained temporarily during cleanup, it must be labeled as deprecated diagnostic output and must not affect the final composite. - `tableDebug=shadow` must show cast shadows only. - Debug views must be unambiguous. - The final composite must show the intended contribution. SSAO investigation requirements: 1. Establish what the chosen SSAO/GTAO/HBAO implementation is supposed to compute. 2. Identify its required inputs: depth, normals, camera projection, radius, scale, falloff, render target size, and pass order. 3. Verify that the scene actually provides those inputs correctly. 4. Verify that the AO pass sees the table, book, and candle wax bodies. 5. Verify that flames and glow sprites are excluded from occlusion. 6. Determine why the current `SSAOPass` output is nearly white and visually weak. 7. Fix the root cause before tuning intensity. 8. Prove the fixed AO in `tableDebug=ao`. 9. Prove the fixed AO in the normal composite. 10. Only then decide whether Three.js `SSAOPass` is sufficient or whether a custom GTAO/HBAO-style pass is needed. Known SSAO failure hypotheses to test: - AO radius may be wrong for the scene scale. - The pass may lack useful normal data for the current materials/geometries. - The table, book, or candles may be positioned or scaled such that the depth differences are too small for the current AO parameters. - Postprocessing pass order or output mode may dilute the AO before it reaches the final image. - Tone mapping/exposure may wash out AO. - The table shader and reflection composite may overwrite or hide AO contribution. - Flame/glow exclusion may be correct, but wax/book/table inclusion must be verified. - The debug output may be too low contrast to judge without a calibrated visualization. ## Reflection Requirements Table reflections: - Use a real planar reflection camera/mirror render path. - The reflection must include book, candles, wax bodies, wicks, flames, and environment contribution where appropriate. - Reflected flames should be smaller/warmer and partly occluded by reflected wax bodies. - Reflections must be crisp enough for the scene quality target. - Reflection render target resolution should favor quality over performance. - Anti-aliasing or higher render target resolution should be used if reflections look jagged. Modern reflection note: - A manual mirrored camera is acceptable only if alignment is correct. - A proper oblique reflection matrix/clip plane may be preferred for robust modern planar reflection. - If reflection alignment regresses, investigate the reflection camera/projection math first. ## Anti-Aliasing And Image Quality - Image quality is prioritized over performance for this scene. - The target hardware assumption is strong enough for three candles and high-quality shader work. - The scene should use high-quality anti-aliasing for the main render and reflection render. - Text on pages must remain crisp. - Shader and render target choices must avoid visible jaggedness, especially after adding SSAO or postprocessing. - If postprocessing causes aliasing, fix the pass order/resolution rather than accepting degradation. ## Debug Views The standalone scene should support debug query modes: - `tableDebug=shadow`: candle cast-shadow contribution. - `tableDebug=ao`: scene-level SSAO. - `tableDebug=normal`: table normal map. - `tableDebug=dust`: dust map/effect. - `tableDebug=grease`: grease/fingerprint map/effect. - `tableDebug=room`: environment reflection contribution. - `tableDebug=scene`: planar scene reflection. - `tableDebug=mask`: table reflection mask. Deprecated: - `tableDebug=contact`: removed/deprecated. It must not return as a final-composite fallback. Debug views must be visually meaningful. A debug view that is too subtle to interpret is not useful proof. ## Testing And Verification Requirements Before reporting a visual feature as complete: 1. Run static/regression checks. 2. Run the build. 3. Capture a debug screenshot proving the feature exists in isolation. 4. Capture a normal composite screenshot proving it affects the final image. 5. Inspect the screenshots visually. 6. Check that no rogue browser/Node/Playwright processes were left behind. 7. Report honestly what is proven and what remains weak. Screenshot tooling: - Use the in-app browser tool when available. - If using Playwright, use one browser instance and close it in `finally`. - Use bounded timeouts. - If screenshot readback stalls, fix the capture method before continuing visual iteration. - Do not start multiple servers or leave orphaned processes. ## Implementation Plan ### Phase 0: Stabilize Current Work State 1. Stop all scene code changes. 2. Keep this specification as the governing document. 3. Do not commit any visual change until the current regression is fixed and tested. 4. Preserve unrelated `.env` changes unstaged. 5. Remove or ignore temporary screenshot files unless needed for explicit review. ### Phase 1: Procedural Book Integration Goal: replace the old fixed-box book in `webgl-book-lab.html` with the procedural book model while preserving candle lighting, table reflection, and shader-owned shadows. Steps: 1. Import `createProceduralBookModel` into the WebGL lab. 2. Place the procedural book so the spine bottom touches the table plane with minimal render clearance. 3. Add top-bar controls for progress, page count, backward, forward, fast backward, and fast forward. 4. Keep all book parts participating in custom candle shader lighting. 5. Keep all Three.js primitive shadow flags disabled. 6. Preserve table reflection and candle rendering. 7. Ensure the right page/top cap is present at all progress values. 8. Ensure the readable page content projects onto the stack top cap. 9. Ensure spine arc/support/cloth materials do not receive page content. 10. Run checks and build. Acceptance criteria: - The old book is gone from the lab scene. - The procedural book is visible, correctly placed on the table, and controllable. - Top page content appears on the actual stack top, not on a hovering overlay. - Extreme progress values render with the same topology/material rules as normal values. - No OpenGL shadow flags are enabled. ### Phase 2: Procedural Book Geometry And Solver Goal: keep the book shape physically plausible and stable across progress/page-count values. Steps: 1. Keep page width, page depth, and page spline length consistent. 2. Use deterministic line generation for page splines. 3. Keep fixed segment lengths whose sum equals page width. 4. Use shorter page-line segments near the spine and longer segments toward the page edge. 5. Make every line follow the closest legal underlying layer: - First layer follows spine/hinge/cover profile and may touch it. - Later layers follow the paper line below and keep one bundle spacing. 6. Keep the spine arc spacing proportional to page bundle count. 7. Keep the spine as small as needed for 40 pages and as large as needed up to the capped maximum. 8. Keep page count capped at 500 pages. 9. Keep cover width independent of spine growth. 10. Ensure stack bodies have closed sides, bottom where needed, and correct top cap normals. Acceptance criteria: - Left and right cover lengths remain the same even when stack sizes differ. - Page widths remain the same on thick and thin stacks. - No final line segment runs backward. - The top caps face outward/upward and light correctly. - The first and last page states remain valid. - No stack body exposes an unintended hollow interior. ### Phase 3: Page Content And Materials Goal: make the book read as a real leather-bound book with readable page content. Steps: 1. Generate page canvas textures at the correct page aspect ratio. 2. Use hardcover-style margins. 3. Keep page content on stack top caps. 4. Keep neutral paper and content page textures smooth and consistently filtered. 5. Generate stack side lines as textures. 6. Keep stack side texture orientation consistent across front, back, left, and right sides. 7. Use procedural leather color and normal maps for cover, hinge, spine base, and cover edge. 8. Round the edge impression of cover panels without introducing open faces. 9. Use a dedicated clean paper material for animated flipping pages. 10. Verify cover, hinge, spine base, cover edge, paper side, paper top, flip page, head/end-band, and cloth spine material groups. Acceptance criteria: - Page content is readable and correctly oriented. - Stack side lines are not free-standing meshes. - Stack side lines meet at corners without visible mismatch. - The visible page surface is smooth and does not reveal construction-line artifacts. - The animated flipping page remains clean during motion and does not show resting-page paper grain, page-content texture, or stack-side line patterns. - Leather parts look like real cover geometry, not flat orange planes. - Cloth spine remains visually distinct from leather cover parts. - Head/end-bands read as small woven bookbinding details and participate in mirror, SSAO, custom book shadows, and local bounce lighting. ### Phase 4: True SSAO Revisit Goal: understand, fix, and complete real scene-level SSAO. Steps: 1. Read the Three.js `SSAOPass` behavior and document what data it uses. 2. Verify pass order, render target resolution, camera near/far values, and depth/normal availability. 3. Create a calibrated `tableDebug=ao` view that makes AO contribution readable. 4. Verify that table, book, and candle wax bodies participate. 5. Verify that flames and glow sprites do not participate as occluders. 6. Tune scene scale/radius/falloff only after the pass is proven active. 7. If Three.js `SSAOPass` cannot produce the required effect, replace it with a better GTAO/HBAO-style implementation. 8. Prove AO in debug. 9. Prove AO in final composite. 10. Add regression checks that prevent analytic contact fallback from being reintroduced. Acceptance criteria: - Candle bases show local AO from the real AO pass. - Book/table contact shows local AO from the real AO pass. - The book, table, and candles are equal scene participants. - Scene AO contributes visible crevice/contact depth without becoming broad dirt or painted shadow. - AO does not replace cast shadows. - No fallback contact darkening remains in the final composite. ### Phase 5: Reflection And Compositing Cleanup Goal: make the table reflection physically coherent. Steps: 1. Confirm planar reflection camera alignment. 2. Evaluate oblique clip-plane reflection if current mirror math remains fragile. 3. Ensure book, candle bodies, wicks, and flames are all reflected. 4. Ensure candle body reflection can occlude reflected flame glare. 5. Ensure environment reflection is correctly oriented and table-only. 6. Tune dust and grease as roughness/specular modifiers only. 7. Prove each contribution in debug and final composite. Acceptance criteria: - Reflections align with real object positions. - Candle bodies are visible in reflections. - Flame reflection does not appear as an impossible unoccluded blob. - Table wood remains visible. ### Phase 6: Integration Back Into App Shell Goal: connect the standalone scene back to the real app. Steps: 1. Keep the standalone lab page for visual regression. 2. Replace the current UI/html creation module with the WebGL module. 3. Keep the old module for reference. 4. Add one top menu line over the canvas. 5. Add modal overview layer over the canvas. 6. Keep compatibility with existing app state, modals, and dynamic text. Acceptance criteria: - Existing app behavior still works. - Canvas scene renders the book UI. - Top menu and modal overview are available. - Dynamic text appears on actual page textures. ### Phase 7: Procedural Page System Goal: implement the future virtual-scrolling book. Steps: 1. Build procedural page stack geometry. 2. Add controllable page flip animation. 3. Add independent left/right page texture assignment. 4. Connect virtual scroll position to page/spread state. 5. Backfill recent spreads from virtual content. 6. Animate stack thickness changes during navigation. 7. Support fast multi-page transitions when jumping through history. Acceptance criteria: - Page stacks visibly represent progress. - Page flips are controllable and stop at the intended spread. - Both pages show dynamic content. - Virtual scrolling and page animation feel like one system. ## Current Known Problems - The current extreme-progress rendering still needs user screenshot validation after the latest stack-cap material and cap-winding fixes. - The page-content texture must not appear on the spine arc or synthetic support strip. - At `0.00` and very early progress, the side with no real stack must still render with the same topology/material rules as later states. - The current content page surface should stay smooth; construction lines from stack textures must not appear on readable content. - Leather material quality is still provisional and may need further art-direction tuning. - Scene-level SSAO is not accepted as final and is currently not allowed to drive book appearance. - The table reflection path is active and should not be disabled to hide book/cover problems. - Two pathless Windows Node processes may resist termination with access denied; they are not the `:3001` server. ## Next Immediate Task Validate the latest procedural-book integration visually in the running `:3001` lab scene, especially the extreme progress states. The next visual work should focus on the book material/topology issues in this order: 1. Confirm that content appears only on the intended stack-top page surfaces. 2. Confirm that spine arc, hinge, cloth, and support strips do not receive page-content texture. 3. Confirm that the right stack has a valid top cap even when the left side has no full stack. 4. Confirm that readable page surfaces are smooth and not showing construction-line artifacts. 5. Continue cover/hinge/spine leather material refinement only after the page-top topology is stable. 6. Keep `:3001` as the single current test server. 7. Keep OpenGL primitive shadows disabled.