Skip to content

Commit 4fd83a7

Browse files
author
DavidQ
committed
Add Advanced 3D Samples batch 2 (1612-1614)
1 parent ce4872e commit 4fd83a7

16 files changed

Lines changed: 852 additions & 5 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
MODEL: GPT-5.3-codex
22
REASONING: high
3-
COMMAND: Implement samples 1609-1611 as described, integrate into samples/index.html, ensure runnable, package to <project folder>/tmp/BUILD_PR_LEVEL_17_25_ADVANCED_3D_SAMPLES_BATCH_1.zip
3+
COMMAND: Implement samples 1612-1614, integrate into index, package to <project folder>/tmp/BUILD_PR_LEVEL_17_26_ADVANCED_3D_SAMPLES_BATCH_2.zip

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Add Advanced 3D Samples batch 1 (1609-1611)
1+
Add Advanced 3D Samples batch 2 (1612-1614)
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
- [ ] all 3 samples load
2-
- [ ] no console errors
3-
- [ ] visible functionality per sample
1+
- [ ] samples load
2+
- [ ] no errors
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# BUILD_PR_LEVEL_17_26_ADVANCED_3D_SAMPLES_BATCH_2
2+
3+
Implement:
4+
- samples/1612-stress-test
5+
- samples/1613-input-lab
6+
- samples/1614-camera-modes
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PLAN_PR_LEVEL_17_26_ADVANCED_3D_SAMPLES_BATCH_2
2+
3+
Purpose:
4+
Continue Advanced 3D Samples.
5+
6+
Scope:
7+
- 1612 Stress Test
8+
- 1613 Input Lab
9+
- 1614 Camera Modes Lab

samples/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ <h2>Phase 16 - 3D Capability Track</h2>
484484
<a class="live" href="./phase-16/1609/index.html" title="Showcases dynamic light movement and wireframe shading changes across a compact 3D set." data-tags="camera3d, lighting3d, render3d, scene, themetokens" data-primary="lighting-demo">Sample 1609 - Lighting Demo</a>
485485
<a class="live" href="./phase-16/1610/index.html" title="Renders one shared world in both a 2D tactical map and a 3D perspective viewport." data-tags="camera3d, hybrid2d3d, render3d, scene, themetokens" data-primary="hybrid-2d-3d">Sample 1610 - Hybrid 2D/3D World</a>
486486
<a class="live" href="./phase-16/1611/index.html" title="Demonstrates client prediction, delayed authority updates, and replica sync in a 3D lane." data-tags="camera3d, multiplayer3d, networking, sync, scene, themetokens" data-primary="multiplayer-sync">Sample 1611 - Multiplayer Sync Demo</a>
487+
<a class="live" href="./phase-16/1612/index.html" title="Renders a dense 1,000-object 3D wireframe field to stress visibility and frame throughput." data-tags="camera3d, stress3d, render3d, scene, themetokens" data-primary="stress-test">Sample 1612 - Stress Test (1,000 Objects)</a>
488+
<a class="live" href="./phase-16/1613/index.html" title="Explores movement, sprint, crouch, and jump input diagnostics in a controlled 3D lane." data-tags="camera3d, input3d, movement3d, scene, themetokens" data-primary="input-lab">Sample 1613 - Input Lab</a>
489+
<a class="live" href="./phase-16/1614/index.html" title="Compares follow, wide, and overhead camera modes around a moving target path." data-tags="camera3d, camera-modes, render3d, scene, themetokens" data-primary="camera-modes-lab">Sample 1614 - Camera Modes Lab</a>
487490
</div>
488491
</section>
489492
</div>
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
Toolbox Aid
3+
David Quesenberry
4+
04/16/2026
5+
StressTest3DScene.js
6+
*/
7+
import { Scene } from '/src/engine/scene/index.js';
8+
import { Theme, ThemeTokens } from '/src/engine/theme/index.js';
9+
import { drawFrame, drawPanel } from '/src/engine/debug/index.js';
10+
import {
11+
applyPhase16CameraMode,
12+
createPhase16ViewState,
13+
createProjectionViewport,
14+
drawDepthBackdrop,
15+
drawGroundGrid,
16+
drawPhase16DebugOverlay,
17+
drawWireBox,
18+
stepPhase16ViewToggles,
19+
} from '../shared/threeDWireframe.js';
20+
21+
const theme = new Theme(ThemeTokens);
22+
const GRID_COLUMNS = 25;
23+
const GRID_ROWS = 40;
24+
const OBJECT_COUNT = GRID_COLUMNS * GRID_ROWS;
25+
26+
export default class StressTest3DScene extends Scene {
27+
constructor() {
28+
super();
29+
this.viewState = createPhase16ViewState();
30+
this.viewport = {
31+
x: 40,
32+
y: 170,
33+
width: 860,
34+
height: 320,
35+
focalLength: 440,
36+
};
37+
this.simTime = 0;
38+
this.cameraYaw = 0.48;
39+
this.waveSpeed = 1.5;
40+
this.waveAmplitude = 0.35;
41+
this.boxes = this.buildBoxes();
42+
this.lastDrawCount = 0;
43+
}
44+
45+
buildBoxes() {
46+
const boxes = [];
47+
const spacingX = 0.9;
48+
const spacingZ = 0.95;
49+
const startX = -((GRID_COLUMNS - 1) * spacingX) * 0.5;
50+
const startZ = 6;
51+
52+
for (let row = 0; row < GRID_ROWS; row += 1) {
53+
for (let col = 0; col < GRID_COLUMNS; col += 1) {
54+
const index = row * GRID_COLUMNS + col;
55+
boxes.push({
56+
x: startX + col * spacingX,
57+
y: -0.2,
58+
z: startZ + row * spacingZ,
59+
width: 0.55,
60+
height: 0.55,
61+
depth: 0.55,
62+
phase: index * 0.03,
63+
color: (row + col) % 3 === 0 ? '#38bdf8' : ((row + col) % 3 === 1 ? '#a78bfa' : '#34d399'),
64+
});
65+
}
66+
}
67+
68+
return boxes;
69+
}
70+
71+
setCamera3D(camera3D) {
72+
this.camera3D = camera3D;
73+
this.syncCamera();
74+
}
75+
76+
syncCamera() {
77+
if (!this.camera3D) {
78+
return;
79+
}
80+
const focusPoint = { x: 0, y: 0.6, z: 24 };
81+
const basePose = {
82+
position: {
83+
x: Math.sin(this.cameraYaw) * 22,
84+
y: 12.5,
85+
z: focusPoint.z - Math.cos(this.cameraYaw) * 23,
86+
},
87+
rotation: {
88+
x: -0.52,
89+
y: this.cameraYaw,
90+
z: 0,
91+
},
92+
};
93+
applyPhase16CameraMode(this.camera3D, this.viewState, basePose, focusPoint);
94+
}
95+
96+
step3DPhysics(dt, engine) {
97+
const input = engine.input;
98+
stepPhase16ViewToggles(this.viewState, input);
99+
if (input?.isDown('KeyQ')) this.cameraYaw -= 0.9 * dt;
100+
if (input?.isDown('KeyE')) this.cameraYaw += 0.9 * dt;
101+
if (input?.isDown('ArrowUp')) this.waveAmplitude = Math.min(0.8, this.waveAmplitude + 0.6 * dt);
102+
if (input?.isDown('ArrowDown')) this.waveAmplitude = Math.max(0.1, this.waveAmplitude - 0.6 * dt);
103+
104+
this.simTime += dt;
105+
this.syncCamera();
106+
}
107+
108+
render(renderer) {
109+
drawFrame(renderer, theme, [
110+
'Sample 1612 - 3D Stress Test',
111+
'Renders 1,000 animated wireframe objects to pressure 3D visibility throughput.',
112+
'Wave amplitude: Up/Down | Orbit camera: Q/E | Camera mode: C | Debug: V',
113+
]);
114+
115+
renderer.strokeRect(this.viewport.x, this.viewport.y, this.viewport.width, this.viewport.height, '#d8d5ff', 2);
116+
drawDepthBackdrop(renderer, this.viewport);
117+
118+
const cameraState = this.camera3D?.getState?.() ?? {
119+
position: { x: 10, y: 12, z: -4 },
120+
rotation: { x: -0.52, y: this.cameraYaw, z: 0 },
121+
};
122+
const projectionViewport = createProjectionViewport(this.viewport);
123+
drawGroundGrid(renderer, { minX: -12, maxX: 12, minZ: 6, maxZ: 46, y: -0.2, step: 2 }, cameraState, projectionViewport);
124+
125+
this.lastDrawCount = 0;
126+
for (let i = 0; i < this.boxes.length; i += 1) {
127+
const box = this.boxes[i];
128+
const wave = Math.sin(this.simTime * this.waveSpeed + box.phase) * this.waveAmplitude;
129+
drawWireBox(
130+
renderer,
131+
{ x: box.x, y: box.y + wave, z: box.z },
132+
{ width: box.width, height: box.height, depth: box.depth },
133+
cameraState,
134+
projectionViewport,
135+
box.color,
136+
{ lineWidth: 1.35, depthCueEnabled: true }
137+
);
138+
this.lastDrawCount += 1;
139+
}
140+
141+
drawPanel(renderer, 620, 34, 300, 176, 'Stress Runtime', [
142+
`Objects configured: ${OBJECT_COUNT}`,
143+
`Objects drawn: ${this.lastDrawCount}`,
144+
`Grid: ${GRID_COLUMNS} x ${GRID_ROWS}`,
145+
`Wave speed: ${this.waveSpeed.toFixed(2)}`,
146+
`Wave amplitude: ${this.waveAmplitude.toFixed(2)}`,
147+
`Camera yaw: ${this.cameraYaw.toFixed(2)}`,
148+
]);
149+
150+
drawPhase16DebugOverlay(renderer, this.viewport, this.viewState, [
151+
`Sim time: ${this.simTime.toFixed(2)} s`,
152+
'Density profile: full-grid render each frame',
153+
]);
154+
}
155+
}

samples/phase-16/1612/index.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!--
2+
Toolbox Aid
3+
David Quesenberry
4+
04/16/2026
5+
index.html
6+
-->
7+
<!DOCTYPE html>
8+
<html lang="en">
9+
<head>
10+
<meta charset="UTF-8" />
11+
<title>Sample 1612 - 3D Stress Test (1,000 Objects)</title>
12+
<link rel="stylesheet" href="../../../src/engine/ui/baseLayout.css" />
13+
</head>
14+
<body>
15+
<main>
16+
<h1>Sample 1612 - 3D Stress Test (1,000 Objects)</h1>
17+
<p>Demonstrates dense 3D wireframe rendering pressure with 1,000 animated objects.</p>
18+
<canvas id="game" width="960" height="540"></canvas>
19+
20+
<section>
21+
<h3>Engine Classes Used</h3>
22+
<ul>
23+
<li>Engine</li>
24+
<li>Scene</li>
25+
<li>Camera3D</li>
26+
</ul>
27+
</section>
28+
</main>
29+
30+
<script type="module" src="/samples/shared/sampleDetailPageEnhancement.js"></script>
31+
<script type="module" src="./main.js"></script>
32+
</body>
33+
</html>

samples/phase-16/1612/main.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Toolbox Aid
3+
David Quesenberry
4+
04/16/2026
5+
main.js
6+
*/
7+
import Engine from '/src/engine/core/Engine.js';
8+
import { InputService } from '/src/engine/input/index.js';
9+
import { Theme, ThemeTokens } from '/src/engine/theme/index.js';
10+
import StressTest3DScene from './StressTest3DScene.js';
11+
12+
const theme = new Theme(ThemeTokens);
13+
theme.applyDocumentTheme();
14+
15+
const canvas = document.getElementById('game');
16+
const input = new InputService();
17+
18+
const engine = new Engine({
19+
canvas,
20+
width: 960,
21+
height: 540,
22+
fixedStepMs: 1000 / 60,
23+
input,
24+
});
25+
26+
engine.setScene(new StressTest3DScene());
27+
engine.start();

0 commit comments

Comments
 (0)