Skip to content

Commit 1de6bd3

Browse files
author
DavidQ
committed
Add Advanced 3D Samples batch 3 (1615-1617)
1 parent 4fd83a7 commit 1de6bd3

15 files changed

Lines changed: 970 additions & 2 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 1612-1614, integrate into index, package to <project folder>/tmp/BUILD_PR_LEVEL_17_26_ADVANCED_3D_SAMPLES_BATCH_2.zip
3+
COMMAND: Implement samples 1615-1617, integrate into index, package to <project folder>/tmp/BUILD_PR_LEVEL_17_27_ADVANCED_3D_SAMPLES_BATCH_3.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 2 (1612-1614)
1+
Add Advanced 3D Samples batch 3 (1615-1617)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# BUILD_PR_LEVEL_17_27_ADVANCED_3D_SAMPLES_BATCH_3
2+
3+
Implement:
4+
- samples/1615-entity-composition
5+
- samples/1616-world-streaming
6+
- samples/1617-large-world
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PLAN_PR_LEVEL_17_27_ADVANCED_3D_SAMPLES_BATCH_3
2+
3+
Purpose:
4+
Continue Advanced 3D Samples.
5+
6+
Scope:
7+
- 1615 Entity Composition
8+
- 1616 World Streaming
9+
- 1617 Large World Streaming

samples/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ <h2>Phase 16 - 3D Capability Track</h2>
487487
<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>
488488
<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>
489489
<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>
490+
<a class="live" href="./phase-16/1615/index.html" title="Assembles one 3D actor from modular parts to demonstrate composition and local transforms." data-tags="camera3d, composition3d, entity3d, render3d, scene, themetokens" data-primary="entity-composition">Sample 1615 - Entity Composition</a>
491+
<a class="live" href="./phase-16/1616/index.html" title="Streams nearby chunks around a moving anchor to visualize real-time world activation." data-tags="camera3d, streaming3d, world3d, scene, themetokens" data-primary="world-streaming">Sample 1616 - World Streaming</a>
492+
<a class="live" href="./phase-16/1617/index.html" title="Demonstrates capped streaming windows for a larger world grid with movement and visibility budgeting." data-tags="camera3d, streaming3d, largeworld3d, scene, themetokens" data-primary="large-world-streaming">Sample 1617 - Large World Streaming</a>
490493
</div>
491494
</section>
492495
</div>
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
Toolbox Aid
3+
David Quesenberry
4+
04/16/2026
5+
EntityComposition3DScene.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+
23+
function rotateY(point, yaw) {
24+
const cos = Math.cos(yaw);
25+
const sin = Math.sin(yaw);
26+
return {
27+
x: point.x * cos - point.z * sin,
28+
y: point.y,
29+
z: point.x * sin + point.z * cos,
30+
};
31+
}
32+
33+
export default class EntityComposition3DScene extends Scene {
34+
constructor() {
35+
super();
36+
this.viewState = createPhase16ViewState();
37+
this.viewport = {
38+
x: 40,
39+
y: 170,
40+
width: 860,
41+
height: 320,
42+
focalLength: 460,
43+
};
44+
this.root = { x: 0, y: 0, z: 13 };
45+
this.assemblyYaw = 0.4;
46+
this.autoSpinSpeed = 0.45;
47+
this.partSpacing = 1;
48+
this.spinPaused = false;
49+
this.pauseLatch = false;
50+
this.parts = this.createParts();
51+
}
52+
53+
createParts() {
54+
return [
55+
{ name: 'core', offset: { x: 0, y: 0.9, z: 0 }, size: { width: 1.8, height: 1.5, depth: 1.8 }, color: '#38bdf8' },
56+
{ name: 'head', offset: { x: 0.2, y: 2.7, z: 0 }, size: { width: 1.2, height: 1.1, depth: 1.2 }, color: '#a78bfa' },
57+
{ name: 'arm-left', offset: { x: -1.7, y: 1.2, z: 0 }, size: { width: 0.65, height: 1.5, depth: 0.65 }, color: '#34d399' },
58+
{ name: 'arm-right', offset: { x: 2.2, y: 1.2, z: 0 }, size: { width: 0.65, height: 1.5, depth: 0.65 }, color: '#34d399' },
59+
{ name: 'pod-front', offset: { x: 0.25, y: 0.2, z: -1.55 }, size: { width: 1.3, height: 0.7, depth: 0.7 }, color: '#f59e0b' },
60+
{ name: 'leg-left', offset: { x: -0.65, y: -1.05, z: 0.1 }, size: { width: 0.65, height: 1.2, depth: 0.65 }, color: '#93c5fd' },
61+
{ name: 'leg-right', offset: { x: 1.1, y: -1.05, z: 0.1 }, size: { width: 0.65, height: 1.2, depth: 0.65 }, color: '#93c5fd' },
62+
];
63+
}
64+
65+
setCamera3D(camera3D) {
66+
this.camera3D = camera3D;
67+
this.syncCamera();
68+
}
69+
70+
syncCamera() {
71+
if (!this.camera3D) {
72+
return;
73+
}
74+
const focusPoint = {
75+
x: this.root.x + 0.4,
76+
y: this.root.y + 1.45,
77+
z: this.root.z + 0.2,
78+
};
79+
const basePose = {
80+
position: {
81+
x: focusPoint.x + Math.sin(this.assemblyYaw) * 10.8,
82+
y: focusPoint.y + 6.5,
83+
z: focusPoint.z - Math.cos(this.assemblyYaw) * 10.8,
84+
},
85+
rotation: {
86+
x: -0.52,
87+
y: this.assemblyYaw,
88+
z: 0,
89+
},
90+
};
91+
applyPhase16CameraMode(this.camera3D, this.viewState, basePose, focusPoint);
92+
}
93+
94+
step3DPhysics(dt, engine) {
95+
const input = engine.input;
96+
stepPhase16ViewToggles(this.viewState, input);
97+
98+
if (input?.isDown('KeyQ')) this.assemblyYaw -= 0.95 * dt;
99+
if (input?.isDown('KeyE')) this.assemblyYaw += 0.95 * dt;
100+
if (input?.isDown('ArrowUp')) this.partSpacing = Math.min(1.65, this.partSpacing + 0.95 * dt);
101+
if (input?.isDown('ArrowDown')) this.partSpacing = Math.max(0.7, this.partSpacing - 0.95 * dt);
102+
103+
const pausePressed = input?.isDown('Space') === true;
104+
if (pausePressed && !this.pauseLatch) {
105+
this.spinPaused = !this.spinPaused;
106+
}
107+
this.pauseLatch = pausePressed;
108+
109+
if (!this.spinPaused) {
110+
this.assemblyYaw += this.autoSpinSpeed * dt;
111+
}
112+
113+
this.syncCamera();
114+
}
115+
116+
render(renderer) {
117+
drawFrame(renderer, theme, [
118+
'Sample 1615 - 3D Entity Composition',
119+
'Builds one actor from modular parts with controllable spacing and orbit view.',
120+
'Orbit: Q/E | Part spacing: Up/Down | Pause spin: Space | Camera: C | Debug: V',
121+
]);
122+
123+
renderer.strokeRect(this.viewport.x, this.viewport.y, this.viewport.width, this.viewport.height, '#d8d5ff', 2);
124+
drawDepthBackdrop(renderer, this.viewport);
125+
126+
const cameraState = this.camera3D?.getState?.() ?? {
127+
position: { x: 7, y: 8, z: 1 },
128+
rotation: { x: -0.52, y: this.assemblyYaw, z: 0 },
129+
};
130+
const projectionViewport = createProjectionViewport(this.viewport);
131+
drawGroundGrid(renderer, { minX: -9, maxX: 9, minZ: 7, maxZ: 21, y: -1.4, step: 2 }, cameraState, projectionViewport);
132+
133+
for (let i = 0; i < this.parts.length; i += 1) {
134+
const part = this.parts[i];
135+
const rotated = rotateY(
136+
{
137+
x: part.offset.x * this.partSpacing,
138+
y: part.offset.y,
139+
z: part.offset.z * this.partSpacing,
140+
},
141+
this.assemblyYaw
142+
);
143+
drawWireBox(
144+
renderer,
145+
{
146+
x: this.root.x + rotated.x,
147+
y: this.root.y + rotated.y,
148+
z: this.root.z + rotated.z,
149+
},
150+
part.size,
151+
cameraState,
152+
projectionViewport,
153+
part.color,
154+
{ lineWidth: 2, depthCueEnabled: true }
155+
);
156+
}
157+
158+
drawPanel(renderer, 620, 34, 300, 188, 'Composition Runtime', [
159+
`Parts: ${this.parts.length}`,
160+
`Part spacing: ${this.partSpacing.toFixed(2)}`,
161+
`Assembly yaw: ${this.assemblyYaw.toFixed(2)}`,
162+
`Auto spin: ${this.spinPaused ? 'paused' : `${this.autoSpinSpeed.toFixed(2)} rad/s`}`,
163+
`Camera mode: ${this.viewState.cameraMode}`,
164+
'Composition: root + head + limbs + pods',
165+
]);
166+
167+
drawPhase16DebugOverlay(renderer, this.viewport, this.viewState, [
168+
'Hierarchy demo: local offsets transformed around one root',
169+
'Spacing control applies to lateral and depth offsets',
170+
]);
171+
}
172+
}

samples/phase-16/1615/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 1615 - 3D Entity Composition</title>
12+
<link rel="stylesheet" href="../../../src/engine/ui/baseLayout.css" />
13+
</head>
14+
<body>
15+
<main>
16+
<h1>Sample 1615 - 3D Entity Composition</h1>
17+
<p>Demonstrates a composed 3D entity built from modular parts with live spacing and rotation controls.</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/1615/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 EntityComposition3DScene from './EntityComposition3DScene.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 EntityComposition3DScene());
27+
engine.start();

0 commit comments

Comments
 (0)