Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
2,413 changes: 2,413 additions & 0 deletions 3D/app.js

Large diffs are not rendered by default.

1,703 changes: 1,703 additions & 0 deletions 3D/assemble-app.js

Large diffs are not rendered by default.

156 changes: 156 additions & 0 deletions 3D/assemble-style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
html,
body {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
background: #000;
}

body {
display: grid;
place-items: center;
position: relative;
font-family: "Segoe UI", Arial, sans-serif;
}

#simCanvas {
width: min(100vw, calc(100vh * 16 / 9));
height: min(100vh, calc(100vw * 9 / 16));
max-width: 100vw;
max-height: 100vh;
display: block;
background: #000;
}

#cameraVideo {
display: none;
}

.mode-jump {
position: fixed;
top: 18px;
right: 18px;
z-index: 10;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 16px;
border: 1px solid rgba(96, 165, 250, 0.75);
border-radius: 999px;
background: rgba(8, 15, 24, 0.9);
color: #e0f2fe;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.14em;
font-size: 11px;
font-weight: 700;
backdrop-filter: blur(10px);
transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.mode-jump:hover {
background: rgba(30, 58, 138, 0.95);
border-color: rgba(147, 197, 253, 0.95);
color: #ffffff;
}

.tutorial-pop {
position: fixed;
inset: 0;
z-index: 20;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
background: rgba(0, 0, 0, 0.48);
backdrop-filter: blur(4px);
}

.tutorial-pop.is-hidden {
display: none;
}

.tutorial-card {
position: relative;
width: min(460px, 100%);
padding: 22px 22px 18px;
border: 1px solid rgba(96, 165, 250, 0.55);
border-radius: 20px;
background: rgba(6, 12, 20, 0.96);
color: #e5eef8;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
}

.tutorial-kicker {
margin: 0 0 8px;
color: #93c5fd;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.16em;
text-transform: uppercase;
}

.tutorial-card h2 {
margin: 0 0 10px;
color: #fff;
font-size: 28px;
line-height: 1.05;
}

.tutorial-card p {
margin: 0 0 12px;
color: #cbd5e1;
font-size: 14px;
line-height: 1.5;
}

.tutorial-card ul {
margin: 0 0 16px;
padding-left: 18px;
color: #dbe7f5;
font-size: 14px;
line-height: 1.5;
}

.tutorial-card li + li {
margin-top: 8px;
}

.tutorial-close {
position: absolute;
top: 12px;
right: 12px;
width: 34px;
height: 34px;
border: 0;
border-radius: 999px;
background: rgba(30, 41, 59, 0.95);
color: #e2e8f0;
font-size: 20px;
cursor: pointer;
}

.tutorial-close:hover {
background: rgba(51, 65, 85, 0.98);
}

.tutorial-action {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 16px;
border: 1px solid rgba(34, 197, 94, 0.65);
border-radius: 999px;
background: rgba(20, 83, 45, 0.95);
color: #f0fdf4;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
cursor: pointer;
}

.tutorial-action:hover {
background: rgba(22, 101, 52, 1);
}
Comment on lines +58 to +156
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

The tutorial styling is already duplicated across both 3D entry pages.

This block is almost the same as 3D/style.css, so any future fix to the modal or button states will have to be made twice. Consider extracting the shared tutorial/card/button rules into one common stylesheet and leaving only page-specific colors/layout here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@3D/assemble-style.css` around lines 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.

50 changes: 50 additions & 0 deletions 3D/assemble.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Gesture Robot Maze Playground</title>
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<script>
window.__assetVersion = Date.now().toString();
const stylesheet = document.createElement("link");
stylesheet.rel = "stylesheet";
stylesheet.href = `./assemble-style.css?v=${window.__assetVersion}`;
document.head.appendChild(stylesheet);
</script>
</head>
<body>
<div class="tutorial-pop" id="assembly-tutorial" role="dialog" aria-modal="true" aria-labelledby="assembly-tutorial-title">
<div class="tutorial-card">
<button class="tutorial-close" id="assembly-tutorial-close" aria-label="Close tutorial">×</button>
<div class="tutorial-kicker">Quick Start</div>
<h2 id="assembly-tutorial-title">3D Assembly</h2>
<p>Use your right hand to move the robot:</p>
<ul>
<li><strong>1 finger</strong> = move forward</li>
<li><strong>2 fingers</strong> = move backward</li>
<li><strong>3 fingers</strong> = move right</li>
<li><strong>4 fingers</strong> = move left</li>
</ul>
<button class="tutorial-action" id="assembly-tutorial-dismiss">Got It</button>
</div>
</div>
<a href="./index.html" class="mode-jump" aria-label="Move to 3D maze page">Move to Maze</a>
<canvas id="simCanvas" width="1920" height="1080"></canvas>
<video id="cameraVideo" autoplay playsinline muted></video>
<script>
const assemblyTutorial = document.getElementById("assembly-tutorial");
const closeAssemblyTutorial = () => assemblyTutorial.classList.add("is-hidden");
document.getElementById("assembly-tutorial-close").addEventListener("click", closeAssemblyTutorial);
document.getElementById("assembly-tutorial-dismiss").addEventListener("click", closeAssemblyTutorial);
Comment on lines +19 to +41
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The tutorial is marked modal, but it does not behave like one.

aria-modal="true" is set, but focus is never moved into the dialog and the Move to Maze link remains tabbable behind it. Keyboard users can navigate outside the overlay, so the modal semantics are currently misleading. Please move initial focus into the dialog and trap/restore focus when it closes; Escape-to-dismiss would help too.

As per coding guidelines, **/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements), XSS risks from unescaped user content, and proper use of template inheritance.

🧰 Tools
🪛 HTMLHint (1.9.2)

[warning] 21-21: The type attribute must be present on elements.

(button-type-require)


[warning] 31-31: The type attribute must be present on

elements.

(button-type-require)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@3D/assemble.html` around lines 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.

</script>
<script>
const appScript = document.createElement("script");
appScript.defer = true;
appScript.src = `./assemble-app.js?v=${window.__assetVersion}`;
document.body.appendChild(appScript);
</script>
</body>
</html>
57 changes: 57 additions & 0 deletions 3D/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Robot Maze | Alpha One Labs</title>
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<script>
window.__robotViewMode = "maze";
window.__assetVersion = Date.now().toString();
const stylesheet = document.createElement("link");
stylesheet.rel = "stylesheet";
stylesheet.href = `./style.css?v=${window.__assetVersion}`;
document.head.appendChild(stylesheet);
</script>
</head>
<body>
<div class="tutorial-pop" id="maze-tutorial" role="dialog" aria-modal="true" aria-labelledby="maze-tutorial-title">
<div class="tutorial-card">
<button class="tutorial-close" id="maze-tutorial-close" aria-label="Close tutorial">×</button>
<div class="tutorial-kicker">Quick Start</div>
<h2 id="maze-tutorial-title">3D Maze</h2>
<p>Use your right hand to move the robot:</p>
<ul>
<li><strong>1 finger</strong> = move forward</li>
<li><strong>2 fingers</strong> = move backward</li>
<li><strong>3 fingers</strong> = move right</li>
<li><strong>4 fingers</strong> = move left</li>
<li><strong>M</strong> = new maze</li>
</ul>
<button class="tutorial-action" id="maze-tutorial-dismiss">Got It</button>
</div>
</div>
<nav class="route-nav" aria-label="Playground pages">
<a href="../index.html">Main</a>
<a href="../home.html">2D Robotics</a>
<a href="./assemble.html">3D Assembly</a>
<a href="./index.html" class="is-active" aria-current="page">3D Maze</a>
</nav>
<canvas id="simCanvas" width="1920" height="1080"></canvas>
<video id="cameraVideo" autoplay playsinline muted></video>
<script>
const mazeTutorial = document.getElementById("maze-tutorial");
const closeMazeTutorial = () => mazeTutorial.classList.add("is-hidden");
document.getElementById("maze-tutorial-close").addEventListener("click", closeMazeTutorial);
document.getElementById("maze-tutorial-dismiss").addEventListener("click", closeMazeTutorial);
Comment on lines +20 to +48
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

This dialog also needs real modal focus management.

While the tutorial is open, the route nav behind it is still reachable by keyboard. That makes aria-modal="true" incorrect in practice and creates a confusing first-run experience for keyboard and screen-reader users. Please move focus into the dialog on open and keep it there until the user dismisses it.

As per coding guidelines, **/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements), XSS risks from unescaped user content, and proper use of template inheritance.

🧰 Tools
🪛 HTMLHint (1.9.2)

[warning] 22-22: The type attribute must be present on elements.

(button-type-require)


[warning] 33-33: The type attribute must be present on

elements.

(button-type-require)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@3D/index.html` around lines 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".

</script>
<script>
const appScript = document.createElement("script");
appScript.defer = true;
appScript.src = `./app.js?v=${window.__assetVersion}`;
document.body.appendChild(appScript);
</script>
</body>
</html>
Loading
Loading