Conversation
WalkthroughAdds two new browser playgrounds: a 3D first‑person maze simulator and a 2D robot assembly simulator, each with optional MediaPipe hand‑gesture control (camera fallback to keyboard), canvas rendering, simulation logic (movement, pickup/drop, NPCs), UI/toolbox overlays, and graceful startup/shutdown handling. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App as Maze App
participant Camera as Camera/Vision
participant Canvas as Canvas Renderer
participant Sim as Simulation
User->>App: Load page / Grant camera access
App->>Camera: Request MediaPipe & camera stream
alt Gesture Mode
Camera-->>App: Hand landmarks per frame
App->>App: Classify gestures + stability filter
else Keyboard Mode
User->>App: Press W/A/S/D or Space
end
loop Animation Frame
App->>Sim: Apply input -> update robot/NPCs/state
Sim->>Sim: Collision checks, pickups/drops, exit detection
App->>Canvas: Raycast walls + draw sprites/HUD/toolbox
Canvas->>User: Render frame
end
User->>App: Reach exit
App->>Sim: Trigger CLEARED -> reset world after delay
sequenceDiagram
participant User
participant App as Assembly App
participant Camera as Camera/Vision
participant Canvas as Canvas Renderer
participant Sim as Simulation
User->>App: Load page / Grant camera access
App->>Camera: Load MediaPipe & request stream
alt Gesture Mode
Camera->>App: Mirror video feed
Camera-->>App: Hand landmarks per frame
App->>App: Classify gestures, update cursor
else Keyboard Mode
User->>App: Press W/A/S/D, Space, or Q/Escape
end
loop Animation Frame
alt Cursor not on toolbox
App->>Sim: Update robot position/angle
end
App->>Sim: Detect stable fist/pinch -> pickup/drop or equip
App->>Canvas: Draw grid, robot preview, toolbox, camera overlay
Canvas->>User: Render frame
end
User->>App: Select part via pinch or key
App->>Sim: Equip module -> update preview
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@3D/app.js`:
- Around line 179-193: Rename the confusing bgr helper to a clearer name (e.g.,
bgrToRgb or colorFromBgr) and update all usages and related helpers to match
(rename bgrAlpha to bgrToRgba or colorFromBgrAlpha if desired) so the function
intent — converting a BGR array to an RGB(A) CSS string — is explicit; modify
the function declaration for bgr (and bgrAlpha) to the new names and update any
references in the codebase, keeping the colorCache key logic and return format
unchanged.
- Around line 55-68: The MEDIAPIPE_SOURCES array includes an unpinned CDN entry
using "@latest" which risks unexpected breaks; update the fallback entry in
MEDIAPIPE_SOURCES to a specific version (e.g., match "0.10.21" or another chosen
semver like "@0.10" if supported) for both moduleUrl and wasmRoot so all sources
are version-pinned; edit the object that currently contains moduleUrl
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/vision_bundle.mjs"
and its wasmRoot to use the chosen pinned version string, keeping the other two
entries unchanged.
- Around line 2411-2413: The calls resetMazeWorld(), drawBootScreen(), and
init() run immediately at module load and can fail if DOM elements are not yet
available; wrap these calls inside a DOMContentLoaded listener (e.g.,
document.addEventListener('DOMContentLoaded', ...)) so that resetMazeWorld,
drawBootScreen, and init execute only after the DOM is ready, preserving the
current call order and behavior.
- Around line 2106-2122: The final error message in loadVisionModule currently
only shows the first collected error; update the thrown Error to include all
entries from the errors array (e.g., join them with a separator and include a
count) so callers see every CDN failure from MEDIAPIPE_SOURCES; keep existing
behavior of setting activeWasmRoot and rethrowing a descriptive Error that
combines a short summary with the joined errors for easier debugging.
- Around line 74-76: The code assumes DOM elements exist; add null checks after
calling document.getElementById for "simCanvas" and "cameraVideo" to avoid
TypeError when accessing canvas.getContext or using video; for example, verify
that const canvas and const video are non-null, and if either is null call a
clear failure path (throw an Error or log via console.error and return/disable
initialization) and only then call canvas.getContext("2d") to set ctx; reference
the existing symbols canvas, ctx, video and document.getElementById in your fix.
- Line 2060: The empty function drawModeBanner is dead code but still invoked
with a ctx argument elsewhere; either remove the drawModeBanner declaration and
its call site so there's no unused function/call, or if it's intended for future
use, add a clear TODO comment inside drawModeBanner and update its signature to
accept the ctx parameter (or actually use ctx) to match the call site; ensure
you update or remove the caller that currently passes ctx to drawModeBanner
accordingly.
- Around line 35-42: Remove the unused HAND_CONNECTIONS constant declaration
from the file (the const HAND_CONNECTIONS = [...] block) since it is not
referenced anywhere; delete that block and run the linter/tests to confirm
nothing else depends on HAND_CONNECTIONS (search for the symbol to be sure) and
then commit the change.
In `@3D/assemble-app.js`:
- Around line 1666-1684: The keydown handler must ignore auto-repeated events
for one-shot actions (pickup/drop and toolbox cycling): check event.repeat (or
maintain a pressed-key set) and return early for repeats when handling Space or
number keys; specifically, in the window.addEventListener("keydown") handler,
guard the branches that call tryPickup/tryDrop (when checking heldObject and
event.code === "Space") and the toolbox cycling branch that calls
cycleSelectedPart(TOOLBOX_CATEGORIES[...]) (when controlMode === "manual" and
event.key between "1" and "5") so they only run on the initial keydown
(non-repeat). Use event.repeat or a small map keyed by event.code to suppress
repeated firings while still allowing manualKeys tracking to behave correctly.
- Around line 46-60: MEDIAPIPE_SOURCES mixes pinned and mutable versions which
can load an incompatible bundle; update every moduleUrl and wasmRoot entry in
the MEDIAPIPE_SOURCES array to the same explicit version (e.g., replace any
"@latest" entries with "@0.10.21") and also change HAND_LANDMARKER_MODEL_URL to
point to the matching pinned model version rather than "latest" so the bundle
and model remain version-consistent across all CDNs.
In `@3D/assemble-style.css`:
- Around line 58-156: The tutorial CSS is duplicated; extract the shared rules
(.tutorial-pop, .tutorial-card, .tutorial-kicker, .tutorial-card h2,
.tutorial-card p, .tutorial-card ul, .tutorial-card li + li, .tutorial-close,
.tutorial-action and their :hover states) into a single common stylesheet (e.g.,
shared-tutorial.css) and import that from both 3D/style.css and
3D/assemble-style.css, leaving only page-specific overrides (colors, layout
widths, paddings or unique selectors) in each file so future fixes apply once.
In `@3D/assemble.html`:
- Around line 19-41: The dialog with id="assembly-tutorial" declares aria-modal
but doesn't move or trap focus; update the assemblyTutorial initialization to
save document.activeElement before opening, programmatically focus the first
focusable control inside the dialog (e.g., element ids "assembly-tutorial-close"
or "assembly-tutorial-dismiss"), install keyboard handlers to trap Tab/Shift+Tab
within the dialog and to close on Escape by calling closeAssemblyTutorial, and
when closing restore focus to the previously focused element; additionally, make
background content non-tabbable while open (e.g., set inert/aria-hidden or
disable tabbable elements outside the assemblyTutorial) so the "Move to Maze"
link (class "mode-jump") and other controls cannot be focused while the modal is
open.
In `@3D/index.html`:
- Around line 20-48: The dialog with id "maze-tutorial" needs real modal focus
management: when opened, programmatically set focus into the dialog (e.g., to
the button with id "maze-tutorial-dismiss" or the dialog container), save the
previously focused element, add a keydown handler to trap Tab/Shift+Tab within
the dialog (using the dialog's focusable elements) and ignore outside focus
movement, and on close (handlers for "maze-tutorial-close" and
"maze-tutorial-dismiss") restore focus to the saved element and remove the
keydown trap. Also mark the background content as inert/unfocusable while open
(e.g., toggle aria-hidden or inert on the nav.route-nav and main content) so
keyboard/screen‑reader users cannot reach elements behind the modal; ensure
these attributes are removed when the dialog is dismissed. Ensure all changes
target the DOM nodes referenced by mazeTutorial, "maze-tutorial-close", and
"maze-tutorial-dismiss".
In `@index.html`:
- Around line 593-626: The onClick handlers on the anchor elements (the tech-btn
anchors that call document.getElementById('page-transition') and set
window.location.href) unconditionally call preventDefault(), breaking modified
clicks and assistive navigation; modify each onClick to only call
e.preventDefault() when it's an unmodified primary click (e.button === 0 and
!e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey), then run the overlay
activation and timed navigation; also add brief accessibility attributes to the
anchors (e.g., aria-label describing the transition and aria-describedby or
aria-controls pointing to the 'page-transition' overlay) so screen readers
understand the enhanced behavior.
In `@README.md`:
- Around line 141-152: In the "Option 1: Open directly" README section, replace
the incorrect clone and cd commands referencing
alphaonelabs-virtual-robotics-playground with the correct repository (git clone
https://github.com/alphaonelabs/botlab.git and cd botlab) and update the
numbered step "2. Open `index.html`..." to "1. Open `index.html`..." so the
ordered list is sequential (this fixes the wrong repository reference and the
MD029 lint issue); ensure these changes are applied inside the existing code
block in that section.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: eaee2086-071f-41b2-989e-f1855ca8e5aa
⛔ Files ignored due to path filters (1)
.DS_Storeis excluded by!**/.DS_Store
📒 Files selected for processing (9)
3D/app.js3D/assemble-app.js3D/assemble-style.css3D/assemble.html3D/index.html3D/style.cssREADME.mdhome.htmlindex.html
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (6)
3D/app.js (2)
2098-2113: 🧹 Nitpick | 🔵 TrivialConsider reporting all CDN errors for easier debugging
The fallback pattern across multiple CDN sources is a solid reliability strategy. When all sources fail, the error message currently only includes the first error. Aggregating all errors would help users diagnose whether the issue is network-wide, specific to one CDN, or perhaps a CORS/version mismatch.
💡 Enhanced error message
- throw new Error(`Could not load MediaPipe Tasks Vision. ${errors[0] ?? "Unknown error"}`); + throw new Error(`Could not load MediaPipe Tasks Vision from ${errors.length} source(s):\n${errors.join("\n")}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@3D/app.js` around lines 2098 - 2113, In loadVisionModule, aggregate and include all collected CDN errors from the errors array (built while iterating MEDIAPIPE_SOURCES) in the final thrown Error instead of only errors[0]; update the final throw to join/format the errors array into a single descriptive message (e.g., join with "; " and include context like "Could not load MediaPipe Tasks Vision:"), so the thrown Error contains full details for all attempted moduleUrl failures.
2402-2404: 🧹 Nitpick | 🔵 TrivialConsider DOMContentLoaded guard for initialization
Since this script is loaded dynamically at the end of
<body>, the DOM should be ready when these functions execute. However, adding aDOMContentLoadedcheck provides a defensive safety net against edge cases (e.g., if the loading strategy changes in the future or the script is ever moved to<head>).🛡️ Safer initialization pattern
-resetMazeWorld(); -drawBootScreen(); -init(); +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", () => { + resetMazeWorld(); + drawBootScreen(); + init(); + }); +} else { + resetMazeWorld(); + drawBootScreen(); + init(); +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@3D/app.js` around lines 2402 - 2404, Wrap the startup calls resetMazeWorld(), drawBootScreen(), and init() in a DOMContentLoaded safety guard: add a document.addEventListener('DOMContentLoaded', ...) that invokes those three functions, and for robustness check document.readyState !== 'loading' to call them immediately if the DOM is already ready; update the initialization location where resetMazeWorld, drawBootScreen, and init are currently called so they only run via that guard.index.html (1)
596-635: 🧹 Nitpick | 🔵 TrivialClick guards implemented correctly—consider adding ARIA labels for screen reader clarity
Great work adding the modifier key guards (
e.button !== 0 || e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) to preserve native link behavior for power users. The implementation correctly allows Cmd/Ctrl+Click to open in a new tab.However, to fully address accessibility, consider adding brief
aria-labelattributes to clarify the enhanced transition behavior for screen reader users. This helps convey that clicking triggers an animated transition before navigation.♿ Suggested accessibility improvement
- <a href="3D/assemble.html" className="tech-btn" style={{ letterSpacing: '0.14em' }} onClick={(e) => { + <a href="3D/assemble.html" className="tech-btn" style={{ letterSpacing: '0.14em' }} aria-label="Assemble a robot in 3D with animated transition" onClick={(e) => {Apply similarly to the
3D/index.htmllink.As per coding guidelines,
**/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@index.html` around lines 596 - 635, Add concise ARIA labels to the two anchor elements with className "tech-btn" (the links pointing to '3D/assemble.html' and '3D/index.html') to explain the animated transition-before-navigation behavior to screen readers; update the anchor for '3D/assemble.html' and the anchor for '3D/index.html' to include an aria-label like "Opens 3D assembler with animated transition" and "Opens 3D maze with animated transition" respectively (keeping existing onClick logic and guards intact and still referencing the 'page-transition' overlay).README.md (1)
145-152: 🧹 Nitpick | 🔵 TrivialMinor Markdown lint issue: ordered list numbering
The ordered list uses "1." followed by "2." on line 152, but markdownlint MD029 expects consistent "1/1/1" prefix style. This is a small formatting nit that doesn't affect readability but may cause lint warnings in CI.
📝 Suggested fix
1. Clone the repository: ```bash git clone https://github.com/alphaonelabs/botlab.git cd botlab-2. Open
index.htmlin a modern browser.
+1. Openindex.htmlin a modern browser.</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@README.mdaround lines 145 - 152, Change the ordered list to use a
consistent "1." prefix style to satisfy markdownlint MD029: replace the second
list item "2. Openindex.htmlin a modern browser." with "1. Openindex.html
in a modern browser." so both steps use the repeated "1." numbering (the list
block containing "Clone the repository:" and the line "Openindex.htmlin a
modern browser.").</details> </blockquote></details> <details> <summary>3D/index.html (1)</summary><blockquote> `24-38`: _🧹 Nitpick_ | _🔵 Trivial_ **Modal focus management implemented—add `type="button"` to buttons** The focus trapping and Escape-to-close behavior mirrors the assembly page implementation, maintaining consistency across the 3D experiences. The `aria-labelledby` correctly references the tutorial title for screen readers. Like the assembly page, please add `type="button"` to the button elements for completeness. <details> <summary>🔧 Add type attribute to buttons</summary> ```diff - <button class="tutorial-close" id="maze-tutorial-close" aria-label="Close tutorial">×</button> + <button type="button" class="tutorial-close" id="maze-tutorial-close" aria-label="Close tutorial">×</button>- <button class="tutorial-action" id="maze-tutorial-dismiss">Got It</button> + <button type="button" class="tutorial-action" id="maze-tutorial-dismiss">Got It</button>As per coding guidelines,
**/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@3D/index.html` around lines 24 - 38, The two buttons in the tutorial modal (elements with id "maze-tutorial-close" / class "tutorial-close" and id "maze-tutorial-dismiss" / class "tutorial-action") need an explicit type attribute to avoid default form-submit behavior; update each <button> to include type="button" (e.g., set type="button" on the button with id="maze-tutorial-close" and on the button with id="maze-tutorial-dismiss").3D/assemble.html (1)
23-37: 🧹 Nitpick | 🔵 TrivialExcellent modal accessibility implementation—add
type="button"to buttonsThe tutorial modal now includes proper focus trapping, Escape-to-close, and focus restoration to the navigation link after dismissal. This is a solid implementation that addresses previous accessibility concerns about
aria-modal="true"semantics.One small improvement: the
<button>elements should includetype="button"to explicitly prevent any unintended form submission behavior (even though there's no form here, it's a good defensive practice).🔧 Add type attribute to buttons
- <button class="tutorial-close" id="assembly-tutorial-close" aria-label="Close tutorial">×</button> + <button type="button" class="tutorial-close" id="assembly-tutorial-close" aria-label="Close tutorial">×</button>- <button class="tutorial-action" id="assembly-tutorial-dismiss">Got It</button> + <button type="button" class="tutorial-action" id="assembly-tutorial-dismiss">Got It</button>As per coding guidelines,
**/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@3D/assemble.html` around lines 23 - 37, Add explicit type="button" attributes to the two buttons in the modal to prevent accidental form submission: update the <button> with id "assembly-tutorial-close" (class "tutorial-close") and the <button> with id "assembly-tutorial-dismiss" (class "tutorial-action") to include type="button". Ensure both button elements are modified so they explicitly declare their type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@3D/assemble.html`:
- Around line 91-96: The assignment appScript.defer = true is a no-op for
dynamically created scripts; remove that line and either leave the element to
load async (just create with src `./assemble-app.js?v=${window.__assetVersion}`
and append via document.createElement / document.body.appendChild) or, if you
need defer-like guaranteed in-order execution, set appScript.async = false
before appending and optionally attach an onload handler to control post-load
behavior for `assemble-app.js`. Ensure references to appScript, the src
`assemble-app.js?v=${window.__assetVersion}`, document.createElement and
document.body.appendChild are updated accordingly.
---
Duplicate comments:
In `@3D/app.js`:
- Around line 2098-2113: In loadVisionModule, aggregate and include all
collected CDN errors from the errors array (built while iterating
MEDIAPIPE_SOURCES) in the final thrown Error instead of only errors[0]; update
the final throw to join/format the errors array into a single descriptive
message (e.g., join with "; " and include context like "Could not load MediaPipe
Tasks Vision:"), so the thrown Error contains full details for all attempted
moduleUrl failures.
- Around line 2402-2404: Wrap the startup calls resetMazeWorld(),
drawBootScreen(), and init() in a DOMContentLoaded safety guard: add a
document.addEventListener('DOMContentLoaded', ...) that invokes those three
functions, and for robustness check document.readyState !== 'loading' to call
them immediately if the DOM is already ready; update the initialization location
where resetMazeWorld, drawBootScreen, and init are currently called so they only
run via that guard.
In `@3D/assemble.html`:
- Around line 23-37: Add explicit type="button" attributes to the two buttons in
the modal to prevent accidental form submission: update the <button> with id
"assembly-tutorial-close" (class "tutorial-close") and the <button> with id
"assembly-tutorial-dismiss" (class "tutorial-action") to include type="button".
Ensure both button elements are modified so they explicitly declare their type.
In `@3D/index.html`:
- Around line 24-38: The two buttons in the tutorial modal (elements with id
"maze-tutorial-close" / class "tutorial-close" and id "maze-tutorial-dismiss" /
class "tutorial-action") need an explicit type attribute to avoid default
form-submit behavior; update each <button> to include type="button" (e.g., set
type="button" on the button with id="maze-tutorial-close" and on the button with
id="maze-tutorial-dismiss").
In `@index.html`:
- Around line 596-635: Add concise ARIA labels to the two anchor elements with
className "tech-btn" (the links pointing to '3D/assemble.html' and
'3D/index.html') to explain the animated transition-before-navigation behavior
to screen readers; update the anchor for '3D/assemble.html' and the anchor for
'3D/index.html' to include an aria-label like "Opens 3D assembler with animated
transition" and "Opens 3D maze with animated transition" respectively (keeping
existing onClick logic and guards intact and still referencing the
'page-transition' overlay).
In `@README.md`:
- Around line 145-152: Change the ordered list to use a consistent "1." prefix
style to satisfy markdownlint MD029: replace the second list item "2. Open
`index.html` in a modern browser." with "1. Open `index.html` in a modern
browser." so both steps use the repeated "1." numbering (the list block
containing "Clone the repository:" and the line "Open `index.html` in a modern
browser.").
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: e3feaadb-63a5-4b9d-8964-ad085c83c65e
📒 Files selected for processing (8)
3D/app.js3D/assemble-style.css3D/assemble.html3D/index.html3D/style.css3D/tutorial.cssREADME.mdindex.html
There was a problem hiding this comment.
Pull request overview
Adds a new 3D robotics experience to the existing browser-based robotics playground, expanding navigation from the landing page and 2D simulator into 3D robot assembly and a 3D maze challenge.
Changes:
- Update landing page and 2D simulator UI to link to new 3D Assembly and 3D Maze pages.
- Introduce standalone 3D pages (HTML/CSS) with an onboarding tutorial overlay and shared navigation.
- Add new 3D simulation logic: gesture/manual control assembly experience and a procedural 3D maze simulator.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| index.html | Updates branding and adds new navigation buttons into the 3D experiences. |
| home.html | Adds quick links from the 2D toolbox panel into 3D Assembly and 3D Maze. |
| README.md | Rewrites docs to describe the multi-entry playground and new 3D routes. |
| 3D/tutorial.css | Adds reusable styling for the tutorial modal overlay. |
| 3D/style.css | Adds base styling and route navigation styling for the 3D maze page. |
| 3D/index.html | Adds the 3D maze entry page with tutorial modal and route nav. |
| 3D/assemble.html | Adds the 3D assembly entry page with tutorial modal and a “Move to Maze” link. |
| 3D/assemble-style.css | Adds base styling and a mode-jump link style for the assembly page. |
| 3D/assemble-app.js | Implements the standalone 3D assembly simulation (gesture + manual fallback). |
| 3D/app.js | Implements the 3D maze simulation with procedural generation and gesture/manual controls. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The 3D Maze app is an interactive web application that allows users to explore and navigate a virtual maze rendered in three dimensions. Users can move through the maze, experience immersive graphics, and challenge themselves to find the exit. The app is designed for both entertainment and educational purposes, showcasing 3D rendering, user controls, and real-time interaction within a browser environment.
Summary
This PR introduces two new 3D interactive experiences to the Botlab robotics playground, expanding the project from a single 2D simulator to a comprehensive three-experience suite. Both new experiences support optional MediaPipe hand-gesture control with graceful keyboard fallback.
New Experiences Added
3D Assembly Simulator (
3D/assemble.html+3D/assemble-app.js)3D Maze Challenge (
3D/index.html+3D/app.js)Technical Integration
Gesture Recognition Architecture
UI & Navigation
index.html) updated with new tech-btn links to 3D experiences (with page transition overlay)home.html) expanded with 3D experience navigation links3D/tutorial.css) with accessible, dismissible modal overlays3D/style.css,3D/assemble-style.css) with responsive canvas sizing and navigation UIDocumentation & Discoverability
Implementation Scale
Approximately 4,100+ new lines of code, primarily simulation logic and rendering:
User Experience Impact