let-them-talk 5.2.5 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -1
- package/README.md +158 -592
- package/SECURITY.md +3 -3
- package/USAGE.md +151 -0
- package/agent-contracts.js +447 -0
- package/api-agents.js +760 -0
- package/autonomy/decision-v2.js +380 -0
- package/autonomy/watchdog-policy.js +572 -0
- package/cli.js +454 -298
- package/conversation-templates/autonomous-feature.json +83 -22
- package/conversation-templates/code-review.json +69 -21
- package/conversation-templates/debug-squad.json +69 -21
- package/conversation-templates/feature-build.json +69 -21
- package/conversation-templates/research-write.json +69 -21
- package/dashboard.html +3148 -174
- package/dashboard.js +823 -786
- package/data-dir.js +58 -0
- package/docs/architecture/branch-semantics.md +157 -0
- package/docs/architecture/canonical-event-schema.md +88 -0
- package/docs/architecture/markdown-workspace.md +183 -0
- package/docs/architecture/runtime-contract.md +459 -0
- package/docs/architecture/runtime-migration-hardening.md +64 -0
- package/events/hooks.js +154 -0
- package/events/log.js +457 -0
- package/events/replay.js +33 -0
- package/events/schema.js +432 -0
- package/managed-team-integration.js +261 -0
- package/office/agents.js +704 -597
- package/office/animation.js +1 -1
- package/office/assets/arcade-cabinet.js +141 -0
- package/office/assets/archway.js +77 -0
- package/office/assets/bar-counter.js +91 -0
- package/office/assets/bar-stool.js +71 -0
- package/office/assets/beanbag.js +64 -0
- package/office/assets/bench.js +99 -0
- package/office/assets/bollard.js +87 -0
- package/office/assets/cactus.js +100 -0
- package/office/assets/carpet-tile.js +46 -0
- package/office/assets/chair.js +123 -0
- package/office/assets/chandelier.js +107 -0
- package/office/assets/coffee-machine.js +95 -0
- package/office/assets/coffee-table.js +81 -0
- package/office/assets/column.js +95 -0
- package/office/assets/desk-lamp.js +102 -0
- package/office/assets/desk.js +76 -0
- package/office/assets/dining-table.js +105 -0
- package/office/assets/door.js +70 -0
- package/office/assets/dual-monitor.js +72 -0
- package/office/assets/fence.js +76 -0
- package/office/assets/filing-cabinet.js +111 -0
- package/office/assets/floor-lamp.js +69 -0
- package/office/assets/floor-tile.js +54 -0
- package/office/assets/flower-pot.js +76 -0
- package/office/assets/foosball.js +95 -0
- package/office/assets/fridge.js +99 -0
- package/office/assets/gaming-chair.js +154 -0
- package/office/assets/gaming-desk.js +105 -0
- package/office/assets/glass-door.js +72 -0
- package/office/assets/glass-wall.js +64 -0
- package/office/assets/half-wall.js +49 -0
- package/office/assets/hanging-plant.js +112 -0
- package/office/assets/index.js +151 -0
- package/office/assets/indoor-tree.js +90 -0
- package/office/assets/l-sofa.js +153 -0
- package/office/assets/marble-floor.js +64 -0
- package/office/assets/materials.js +40 -0
- package/office/assets/meeting-table.js +88 -0
- package/office/assets/microwave.js +94 -0
- package/office/assets/monitor.js +67 -0
- package/office/assets/neon-strip.js +73 -0
- package/office/assets/painting.js +84 -0
- package/office/assets/palm-tree.js +108 -0
- package/office/assets/pc-tower.js +91 -0
- package/office/assets/pendant-light.js +67 -0
- package/office/assets/ping-pong.js +114 -0
- package/office/assets/plant.js +72 -0
- package/office/assets/planter-box.js +95 -0
- package/office/assets/pool-table.js +94 -0
- package/office/assets/printer.js +113 -0
- package/office/assets/reception-desk.js +133 -0
- package/office/assets/rug.js +78 -0
- package/office/assets/sculpture.js +85 -0
- package/office/assets/server-rack.js +98 -0
- package/office/assets/sink.js +109 -0
- package/office/assets/sofa.js +106 -0
- package/office/assets/speaker.js +83 -0
- package/office/assets/spotlight.js +83 -0
- package/office/assets/street-lamp.js +97 -0
- package/office/assets/trash-can.js +83 -0
- package/office/assets/treadmill.js +126 -0
- package/office/assets/trophy.js +89 -0
- package/office/assets/tv-screen.js +79 -0
- package/office/assets/vase.js +84 -0
- package/office/assets/wall-clock.js +84 -0
- package/office/assets/wall.js +53 -0
- package/office/assets/water-cooler.js +146 -0
- package/office/assets/whiteboard.js +115 -0
- package/office/assets.js +3 -431
- package/office/builder.js +791 -355
- package/office/campus-env.js +1012 -1119
- package/office/environment.js +2 -0
- package/office/gallery.js +997 -0
- package/office/index.js +165 -61
- package/office/navigation.js +173 -152
- package/office/player.js +178 -68
- package/office/robot-character.js +272 -0
- package/office/spectator-camera.js +33 -10
- package/office/state.js +2 -0
- package/office/world-save.js +35 -4
- package/package.json +57 -3
- package/providers/comfyui.js +383 -0
- package/providers/dalle.js +79 -0
- package/providers/gemini.js +181 -0
- package/providers/ollama.js +184 -0
- package/providers/replicate.js +115 -0
- package/providers/zai.js +183 -0
- package/runtime-descriptor.js +270 -0
- package/scripts/check-agent-contract-advisory.js +132 -0
- package/scripts/check-api-agent-parity.js +277 -0
- package/scripts/check-autonomy-v2-decision.js +207 -0
- package/scripts/check-autonomy-v2-execution.js +588 -0
- package/scripts/check-autonomy-v2-watchdog.js +224 -0
- package/scripts/check-branch-fork-snapshot.js +337 -0
- package/scripts/check-branch-isolation.js +787 -0
- package/scripts/check-branch-semantics.js +139 -0
- package/scripts/check-dashboard-control-plane.js +1304 -0
- package/scripts/check-docs-onboarding.js +490 -0
- package/scripts/check-event-schema.js +276 -0
- package/scripts/check-evidence-completion.js +239 -0
- package/scripts/check-invariants.js +992 -0
- package/scripts/check-lifecycle-hooks.js +525 -0
- package/scripts/check-managed-team-integration.js +166 -0
- package/scripts/check-markdown-workspace-export.js +548 -0
- package/scripts/check-markdown-workspace-safety.js +347 -0
- package/scripts/check-markdown-workspace.js +136 -0
- package/scripts/check-message-replay.js +429 -0
- package/scripts/check-migration-hardening.js +300 -0
- package/scripts/check-performance-indexing.js +272 -0
- package/scripts/check-provider-capabilities.js +316 -0
- package/scripts/check-runtime-contract.js +109 -0
- package/scripts/check-session-aware-context.js +172 -0
- package/scripts/check-session-lifecycle.js +210 -0
- package/scripts/export-markdown-workspace.js +84 -0
- package/scripts/fixtures/message-replay/clean.jsonl +2 -0
- package/scripts/fixtures/message-replay/corrupt-correction-payload.jsonl +1 -0
- package/scripts/fixtures/message-replay/corrupt-jsonl.jsonl +1 -0
- package/scripts/fixtures/message-replay/corrupt-payload.jsonl +1 -0
- package/scripts/fixtures/message-replay/out-of-order.jsonl +2 -0
- package/scripts/migrate-legacy-to-canonical.js +201 -0
- package/scripts/run-verification-suite.js +242 -0
- package/scripts/sync-packaged-docs.js +69 -0
- package/server.js +9546 -7214
- package/state/agents.js +161 -0
- package/state/canonical.js +3068 -0
- package/state/dashboard-queries.js +441 -0
- package/state/evidence.js +56 -0
- package/state/io.js +69 -0
- package/state/markdown-workspace.js +951 -0
- package/state/messages.js +669 -0
- package/state/sessions.js +683 -0
- package/state/tasks-workflows.js +92 -0
- package/templates/debate.json +2 -2
- package/templates/managed.json +4 -4
- package/templates/pair.json +2 -2
- package/templates/review.json +2 -2
- package/templates/team.json +3 -3
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'street_lamp',
|
|
6
|
+
name: 'Street Lamp',
|
|
7
|
+
category: 'exterior',
|
|
8
|
+
icon: 'SL',
|
|
9
|
+
gridW: 1, gridD: 1, height: 3.5,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Main pole — dark metal, slight taper
|
|
14
|
+
var pole = new THREE.Mesh(
|
|
15
|
+
new THREE.CylinderGeometry(0.040, 0.060, 3.20, 12),
|
|
16
|
+
PAL.darkMetal()
|
|
17
|
+
);
|
|
18
|
+
pole.position.y = 1.60;
|
|
19
|
+
pole.castShadow = true;
|
|
20
|
+
g.add(pole);
|
|
21
|
+
|
|
22
|
+
// Pole base collar (decorative flared ring)
|
|
23
|
+
var collar = new THREE.Mesh(
|
|
24
|
+
new THREE.CylinderGeometry(0.110, 0.130, 0.10, 16),
|
|
25
|
+
mat(0x1a1c22, { roughness: 0.45, metalness: 0.25 })
|
|
26
|
+
);
|
|
27
|
+
collar.position.y = 0.05;
|
|
28
|
+
collar.castShadow = true;
|
|
29
|
+
g.add(collar);
|
|
30
|
+
|
|
31
|
+
// Base plate
|
|
32
|
+
var basePlate = new THREE.Mesh(
|
|
33
|
+
new THREE.CylinderGeometry(0.130, 0.130, 0.045, 16),
|
|
34
|
+
PAL.darkMetal()
|
|
35
|
+
);
|
|
36
|
+
basePlate.position.y = 0.022;
|
|
37
|
+
g.add(basePlate);
|
|
38
|
+
|
|
39
|
+
// Decorative ring mid-pole
|
|
40
|
+
var midRing = new THREE.Mesh(
|
|
41
|
+
new THREE.TorusGeometry(0.055, 0.014, 8, 18),
|
|
42
|
+
mat(0x2a2d35, { roughness: 0.40, metalness: 0.30 })
|
|
43
|
+
);
|
|
44
|
+
midRing.position.y = 1.80;
|
|
45
|
+
g.add(midRing);
|
|
46
|
+
|
|
47
|
+
// Curved arm / goose-neck extending from top
|
|
48
|
+
var arm = new THREE.Mesh(
|
|
49
|
+
new THREE.CylinderGeometry(0.022, 0.030, 0.50, 10),
|
|
50
|
+
PAL.darkMetal()
|
|
51
|
+
);
|
|
52
|
+
arm.rotation.z = Math.PI / 4;
|
|
53
|
+
arm.position.set(0.18, 3.28, 0);
|
|
54
|
+
arm.castShadow = true;
|
|
55
|
+
g.add(arm);
|
|
56
|
+
|
|
57
|
+
// Lantern head housing
|
|
58
|
+
var lanternBody = new THREE.Mesh(
|
|
59
|
+
new THREE.CylinderGeometry(0.090, 0.110, 0.20, 10),
|
|
60
|
+
mat(0x111318, { roughness: 0.40, metalness: 0.25 })
|
|
61
|
+
);
|
|
62
|
+
lanternBody.position.set(0.32, 3.44, 0);
|
|
63
|
+
lanternBody.castShadow = true;
|
|
64
|
+
g.add(lanternBody);
|
|
65
|
+
|
|
66
|
+
// Lantern top cap
|
|
67
|
+
var lanternCap = new THREE.Mesh(
|
|
68
|
+
new THREE.CylinderGeometry(0.025, 0.095, 0.06, 10),
|
|
69
|
+
PAL.darkMetal()
|
|
70
|
+
);
|
|
71
|
+
lanternCap.position.set(0.32, 3.57, 0);
|
|
72
|
+
g.add(lanternCap);
|
|
73
|
+
|
|
74
|
+
// Lantern glass (warm glowing panel)
|
|
75
|
+
var glass = new THREE.Mesh(
|
|
76
|
+
new THREE.CylinderGeometry(0.085, 0.085, 0.15, 10),
|
|
77
|
+
mat(0xfff0cc, { transparent: true, opacity: 0.65, emissive: 0xffcc66, emissiveIntensity: 0.70, roughness: 0.10 })
|
|
78
|
+
);
|
|
79
|
+
glass.position.set(0.32, 3.44, 0);
|
|
80
|
+
g.add(glass);
|
|
81
|
+
|
|
82
|
+
// Lantern bottom diffuser disc
|
|
83
|
+
var diffuser = new THREE.Mesh(
|
|
84
|
+
new THREE.CylinderGeometry(0.082, 0.082, 0.010, 10),
|
|
85
|
+
mat(0xffeedd, { transparent: true, opacity: 0.80, emissive: 0xffcc55, emissiveIntensity: 0.60 })
|
|
86
|
+
);
|
|
87
|
+
diffuser.position.set(0.32, 3.34, 0);
|
|
88
|
+
g.add(diffuser);
|
|
89
|
+
|
|
90
|
+
// PointLight — warm street glow
|
|
91
|
+
var light = new THREE.PointLight(0xffcc66, 1.2, 6.0);
|
|
92
|
+
light.position.set(0.32, 3.35, 0);
|
|
93
|
+
g.add(light);
|
|
94
|
+
|
|
95
|
+
return g;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'trash_can',
|
|
6
|
+
name: 'Trash Can',
|
|
7
|
+
category: 'exterior',
|
|
8
|
+
icon: 'TC',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.7,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Main cylindrical body — dark metal, slightly tapered (wider at top)
|
|
14
|
+
var body = new THREE.Mesh(
|
|
15
|
+
new THREE.CylinderGeometry(0.145, 0.120, 0.62, 18),
|
|
16
|
+
mat(0x1a1c22, { roughness: 0.50, metalness: 0.30 })
|
|
17
|
+
);
|
|
18
|
+
body.position.y = 0.34;
|
|
19
|
+
body.castShadow = true;
|
|
20
|
+
body.receiveShadow = true;
|
|
21
|
+
g.add(body);
|
|
22
|
+
|
|
23
|
+
// Chrome top rim ring
|
|
24
|
+
var rim = new THREE.Mesh(
|
|
25
|
+
new THREE.TorusGeometry(0.148, 0.016, 8, 22),
|
|
26
|
+
PAL.chrome()
|
|
27
|
+
);
|
|
28
|
+
rim.rotation.x = Math.PI / 2;
|
|
29
|
+
rim.position.y = 0.656;
|
|
30
|
+
g.add(rim);
|
|
31
|
+
|
|
32
|
+
// Chrome bottom rim ring
|
|
33
|
+
var bottomRim = new THREE.Mesh(
|
|
34
|
+
new THREE.TorusGeometry(0.124, 0.012, 8, 22),
|
|
35
|
+
PAL.chrome()
|
|
36
|
+
);
|
|
37
|
+
bottomRim.rotation.x = Math.PI / 2;
|
|
38
|
+
bottomRim.position.y = 0.032;
|
|
39
|
+
g.add(bottomRim);
|
|
40
|
+
|
|
41
|
+
// Lid (slightly domed cap)
|
|
42
|
+
var lid = new THREE.Mesh(
|
|
43
|
+
new THREE.CylinderGeometry(0.148, 0.148, 0.040, 18),
|
|
44
|
+
mat(0x111318, { roughness: 0.45, metalness: 0.25 })
|
|
45
|
+
);
|
|
46
|
+
lid.position.y = 0.680;
|
|
47
|
+
lid.castShadow = true;
|
|
48
|
+
g.add(lid);
|
|
49
|
+
|
|
50
|
+
// Lid handle (small chrome knob)
|
|
51
|
+
var knob = new THREE.Mesh(
|
|
52
|
+
new THREE.CylinderGeometry(0.022, 0.022, 0.032, 10),
|
|
53
|
+
PAL.chrome()
|
|
54
|
+
);
|
|
55
|
+
knob.position.y = 0.716;
|
|
56
|
+
g.add(knob);
|
|
57
|
+
|
|
58
|
+
// Vertical embossed ribs on body (8 ribs)
|
|
59
|
+
var ribMat = mat(0x0e1014, { roughness: 0.55 });
|
|
60
|
+
var ribGeo = new THREE.BoxGeometry(0.012, 0.58, 0.014);
|
|
61
|
+
for (var i = 0; i < 8; i++) {
|
|
62
|
+
var angle = (i / 8) * Math.PI * 2;
|
|
63
|
+
var rib = new THREE.Mesh(ribGeo, ribMat);
|
|
64
|
+
rib.position.set(Math.cos(angle) * 0.138, 0.34, Math.sin(angle) * 0.138);
|
|
65
|
+
rib.rotation.y = -angle;
|
|
66
|
+
g.add(rib);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Perforated pattern dots (small recessed circles on front face — 3x4 grid)
|
|
70
|
+
var holeMat = mat(0x0a0c10, { roughness: 0.70 });
|
|
71
|
+
var holeGeo = new THREE.CylinderGeometry(0.010, 0.010, 0.008, 8);
|
|
72
|
+
[-1, 0, 1].forEach(function(col) {
|
|
73
|
+
[0.55, 0.42, 0.30, 0.18].forEach(function(y) {
|
|
74
|
+
var hole = new THREE.Mesh(holeGeo, holeMat);
|
|
75
|
+
hole.rotation.x = Math.PI / 2;
|
|
76
|
+
hole.position.set(col * 0.038, y, 0.142);
|
|
77
|
+
g.add(hole);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return g;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'treadmill',
|
|
6
|
+
name: 'Treadmill',
|
|
7
|
+
category: 'recreation',
|
|
8
|
+
icon: 'TM',
|
|
9
|
+
gridW: 1, gridD: 2, height: 1.2,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Base frame
|
|
14
|
+
var base = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(0.70, 0.20, 1.60),
|
|
16
|
+
mat(0x111318, { roughness: 0.45, metalness: 0.20 })
|
|
17
|
+
);
|
|
18
|
+
base.position.y = 0.10;
|
|
19
|
+
base.castShadow = true;
|
|
20
|
+
base.receiveShadow = true;
|
|
21
|
+
g.add(base);
|
|
22
|
+
|
|
23
|
+
// Running belt surface (dark rubber)
|
|
24
|
+
var belt = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(0.54, 0.018, 1.38),
|
|
26
|
+
mat(0x1a1a1a, { roughness: 0.92 })
|
|
27
|
+
);
|
|
28
|
+
belt.position.y = 0.212;
|
|
29
|
+
belt.receiveShadow = true;
|
|
30
|
+
g.add(belt);
|
|
31
|
+
|
|
32
|
+
// Belt edge stripes (yellow safety lines)
|
|
33
|
+
var stripeMat = mat(0xeecc00, { roughness: 0.70 });
|
|
34
|
+
var stripeGeo = new THREE.BoxGeometry(0.025, 0.020, 1.38);
|
|
35
|
+
[-0.255, 0.255].forEach(function(x) {
|
|
36
|
+
var stripe = new THREE.Mesh(stripeGeo, stripeMat);
|
|
37
|
+
stripe.position.set(x, 0.222, 0);
|
|
38
|
+
g.add(stripe);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Front roller drum
|
|
42
|
+
var rollerGeo = new THREE.CylinderGeometry(0.055, 0.055, 0.54, 14);
|
|
43
|
+
var rollerMat = PAL.chromeBrushed();
|
|
44
|
+
var frontRoller = new THREE.Mesh(rollerGeo, rollerMat);
|
|
45
|
+
frontRoller.rotation.z = Math.PI / 2;
|
|
46
|
+
frontRoller.position.set(0, 0.21, -0.70);
|
|
47
|
+
frontRoller.castShadow = true;
|
|
48
|
+
g.add(frontRoller);
|
|
49
|
+
|
|
50
|
+
// Rear roller
|
|
51
|
+
var rearRoller = new THREE.Mesh(rollerGeo, rollerMat);
|
|
52
|
+
rearRoller.rotation.z = Math.PI / 2;
|
|
53
|
+
rearRoller.position.set(0, 0.21, 0.70);
|
|
54
|
+
rearRoller.castShadow = true;
|
|
55
|
+
g.add(rearRoller);
|
|
56
|
+
|
|
57
|
+
// Left handlebar upright
|
|
58
|
+
var upMat = mat(0x1e2128, { roughness: 0.40, metalness: 0.30 });
|
|
59
|
+
var upGeo = new THREE.CylinderGeometry(0.022, 0.022, 0.92, 10);
|
|
60
|
+
var leftUp = new THREE.Mesh(upGeo, upMat);
|
|
61
|
+
leftUp.position.set(-0.28, 0.66, -0.45);
|
|
62
|
+
leftUp.castShadow = true;
|
|
63
|
+
g.add(leftUp);
|
|
64
|
+
|
|
65
|
+
// Right handlebar upright
|
|
66
|
+
var rightUp = leftUp.clone();
|
|
67
|
+
rightUp.position.x = 0.28;
|
|
68
|
+
g.add(rightUp);
|
|
69
|
+
|
|
70
|
+
// Crossbar connecting uprights
|
|
71
|
+
var crossbar = new THREE.Mesh(
|
|
72
|
+
new THREE.CylinderGeometry(0.018, 0.018, 0.56, 10),
|
|
73
|
+
upMat
|
|
74
|
+
);
|
|
75
|
+
crossbar.rotation.z = Math.PI / 2;
|
|
76
|
+
crossbar.position.set(0, 1.08, -0.45);
|
|
77
|
+
crossbar.castShadow = true;
|
|
78
|
+
g.add(crossbar);
|
|
79
|
+
|
|
80
|
+
// Handlebar grips (foam-style, slightly wider)
|
|
81
|
+
var gripMat = mat(0x222222, { roughness: 0.90 });
|
|
82
|
+
var gripGeo = new THREE.CylinderGeometry(0.028, 0.028, 0.22, 10);
|
|
83
|
+
var leftGrip = new THREE.Mesh(gripGeo, gripMat);
|
|
84
|
+
leftGrip.rotation.z = Math.PI / 2;
|
|
85
|
+
leftGrip.position.set(-0.19, 1.10, -0.45);
|
|
86
|
+
g.add(leftGrip);
|
|
87
|
+
var rightGrip = leftGrip.clone();
|
|
88
|
+
rightGrip.position.x = 0.19;
|
|
89
|
+
g.add(rightGrip);
|
|
90
|
+
|
|
91
|
+
// Console display panel
|
|
92
|
+
var consoleStem = new THREE.Mesh(
|
|
93
|
+
new THREE.BoxGeometry(0.06, 0.12, 0.04),
|
|
94
|
+
upMat
|
|
95
|
+
);
|
|
96
|
+
consoleStem.position.set(0, 1.16, -0.45);
|
|
97
|
+
g.add(consoleStem);
|
|
98
|
+
|
|
99
|
+
var console_ = new THREE.Mesh(
|
|
100
|
+
new THREE.BoxGeometry(0.36, 0.18, 0.06),
|
|
101
|
+
mat(0x111318, { roughness: 0.45 })
|
|
102
|
+
);
|
|
103
|
+
console_.position.set(0, 1.26, -0.46);
|
|
104
|
+
console_.castShadow = true;
|
|
105
|
+
g.add(console_);
|
|
106
|
+
|
|
107
|
+
// Console screen (emissive blue)
|
|
108
|
+
var consoleScreen = new THREE.Mesh(
|
|
109
|
+
new THREE.BoxGeometry(0.22, 0.10, 0.008),
|
|
110
|
+
mat(0x001128, { emissive: 0x0066cc, emissiveIntensity: 0.90, roughness: 0.1 })
|
|
111
|
+
);
|
|
112
|
+
consoleScreen.position.set(0, 1.27, -0.432);
|
|
113
|
+
g.add(consoleScreen);
|
|
114
|
+
|
|
115
|
+
// Feet (rubber pads)
|
|
116
|
+
var feetMat = mat(0x0a0a0a, { roughness: 0.92 });
|
|
117
|
+
var feetGeo = new THREE.BoxGeometry(0.10, 0.025, 0.10);
|
|
118
|
+
[[-0.28, 0.012, 0.68], [0.28, 0.012, 0.68], [-0.28, 0.012, -0.68], [0.28, 0.012, -0.68]].forEach(function(p) {
|
|
119
|
+
var foot = new THREE.Mesh(feetGeo, feetMat);
|
|
120
|
+
foot.position.set(p[0], p[1], p[2]);
|
|
121
|
+
g.add(foot);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return g;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'trophy',
|
|
6
|
+
name: 'Trophy',
|
|
7
|
+
category: 'decor',
|
|
8
|
+
icon: 'Tr',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.35,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Walnut base slab
|
|
14
|
+
var base = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(0.18, 0.055, 0.12),
|
|
16
|
+
PAL.walnutDark()
|
|
17
|
+
);
|
|
18
|
+
base.position.y = 0.028;
|
|
19
|
+
base.castShadow = true;
|
|
20
|
+
base.receiveShadow = true;
|
|
21
|
+
g.add(base);
|
|
22
|
+
|
|
23
|
+
// Base nameplate strip
|
|
24
|
+
var plate = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(0.12, 0.018, 0.005),
|
|
26
|
+
PAL.gold()
|
|
27
|
+
);
|
|
28
|
+
plate.position.set(0, 0.032, 0.062);
|
|
29
|
+
g.add(plate);
|
|
30
|
+
|
|
31
|
+
// Trophy stem lower (narrow rod)
|
|
32
|
+
var stemLow = new THREE.Mesh(
|
|
33
|
+
new THREE.CylinderGeometry(0.015, 0.022, 0.07, 12),
|
|
34
|
+
PAL.gold()
|
|
35
|
+
);
|
|
36
|
+
stemLow.position.y = 0.09;
|
|
37
|
+
stemLow.castShadow = true;
|
|
38
|
+
g.add(stemLow);
|
|
39
|
+
|
|
40
|
+
// Trophy stem mid (wider knob)
|
|
41
|
+
var knob = new THREE.Mesh(
|
|
42
|
+
new THREE.SphereGeometry(0.028, 14, 14),
|
|
43
|
+
PAL.gold()
|
|
44
|
+
);
|
|
45
|
+
knob.position.y = 0.145;
|
|
46
|
+
knob.castShadow = true;
|
|
47
|
+
g.add(knob);
|
|
48
|
+
|
|
49
|
+
// Trophy stem upper (narrow rod)
|
|
50
|
+
var stemUp = new THREE.Mesh(
|
|
51
|
+
new THREE.CylinderGeometry(0.012, 0.015, 0.055, 12),
|
|
52
|
+
PAL.gold()
|
|
53
|
+
);
|
|
54
|
+
stemUp.position.y = 0.195;
|
|
55
|
+
stemUp.castShadow = true;
|
|
56
|
+
g.add(stemUp);
|
|
57
|
+
|
|
58
|
+
// Cup body (wide at top, narrow at base)
|
|
59
|
+
var cup = new THREE.Mesh(
|
|
60
|
+
new THREE.CylinderGeometry(0.065, 0.025, 0.10, 18),
|
|
61
|
+
PAL.gold()
|
|
62
|
+
);
|
|
63
|
+
cup.position.y = 0.27;
|
|
64
|
+
cup.castShadow = true;
|
|
65
|
+
g.add(cup);
|
|
66
|
+
|
|
67
|
+
// Left handle
|
|
68
|
+
var handleL = new THREE.Mesh(
|
|
69
|
+
new THREE.TorusGeometry(0.025, 0.007, 8, 14, Math.PI),
|
|
70
|
+
PAL.gold()
|
|
71
|
+
);
|
|
72
|
+
handleL.position.set(-0.078, 0.275, 0);
|
|
73
|
+
handleL.rotation.y = Math.PI / 2;
|
|
74
|
+
handleL.castShadow = true;
|
|
75
|
+
g.add(handleL);
|
|
76
|
+
|
|
77
|
+
// Right handle
|
|
78
|
+
var handleR = new THREE.Mesh(
|
|
79
|
+
new THREE.TorusGeometry(0.025, 0.007, 8, 14, Math.PI),
|
|
80
|
+
PAL.gold()
|
|
81
|
+
);
|
|
82
|
+
handleR.position.set(0.078, 0.275, 0);
|
|
83
|
+
handleR.rotation.y = -Math.PI / 2;
|
|
84
|
+
handleR.castShadow = true;
|
|
85
|
+
g.add(handleR);
|
|
86
|
+
|
|
87
|
+
return g;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'tv_screen',
|
|
6
|
+
name: 'TV Screen',
|
|
7
|
+
category: 'tech',
|
|
8
|
+
icon: 'TV',
|
|
9
|
+
gridW: 2, gridD: 1, height: 1.2,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var W = 2.0;
|
|
14
|
+
var H = 1.2;
|
|
15
|
+
var bezelThick = 0.028;
|
|
16
|
+
|
|
17
|
+
// Outer bezel — ultra-thin glossy black
|
|
18
|
+
var bezel = new THREE.Mesh(
|
|
19
|
+
new THREE.BoxGeometry(W, H, bezelThick),
|
|
20
|
+
mat(0x080808, { roughness: 0.15, metalness: 0.25 })
|
|
21
|
+
);
|
|
22
|
+
bezel.position.y = H / 2 + 0.05;
|
|
23
|
+
bezel.castShadow = true;
|
|
24
|
+
g.add(bezel);
|
|
25
|
+
|
|
26
|
+
// Screen panel — large emissive dark blue
|
|
27
|
+
var screen = new THREE.Mesh(
|
|
28
|
+
new THREE.BoxGeometry(W - 0.04, H - 0.04, 0.008),
|
|
29
|
+
mat(0x040c1a, { emissive: 0x051530, emissiveIntensity: 0.65, roughness: 0.02 })
|
|
30
|
+
);
|
|
31
|
+
screen.position.set(0, H / 2 + 0.05, bezelThick / 2 + 0.001);
|
|
32
|
+
g.add(screen);
|
|
33
|
+
|
|
34
|
+
// Subtle scan-line overlay strip (lower third highlight)
|
|
35
|
+
var scanStrip = new THREE.Mesh(
|
|
36
|
+
new THREE.BoxGeometry(W - 0.06, H * 0.28, 0.002),
|
|
37
|
+
mat(0x0a1f3a, { transparent: true, opacity: 0.18, roughness: 0.0 })
|
|
38
|
+
);
|
|
39
|
+
scanStrip.position.set(0, 0.22, bezelThick / 2 + 0.009);
|
|
40
|
+
g.add(scanStrip);
|
|
41
|
+
|
|
42
|
+
// Logo dot center-bottom bezel
|
|
43
|
+
var logo = new THREE.Mesh(
|
|
44
|
+
new THREE.SphereGeometry(0.009, 10, 10),
|
|
45
|
+
mat(0xffffff, { emissive: 0xffffff, emissiveIntensity: 0.5, roughness: 0.2 })
|
|
46
|
+
);
|
|
47
|
+
logo.position.set(0, 0.022, bezelThick / 2 + 0.012);
|
|
48
|
+
g.add(logo);
|
|
49
|
+
|
|
50
|
+
// Wall-mount bracket plate (rear center)
|
|
51
|
+
var mountPlate = new THREE.Mesh(
|
|
52
|
+
new THREE.BoxGeometry(0.18, 0.22, 0.015),
|
|
53
|
+
PAL.chromeBrushed()
|
|
54
|
+
);
|
|
55
|
+
mountPlate.position.set(0, H / 2 + 0.05, -bezelThick / 2 - 0.006);
|
|
56
|
+
g.add(mountPlate);
|
|
57
|
+
|
|
58
|
+
// Mount screw knobs (4 corners of bracket)
|
|
59
|
+
[[-0.06, 0.07], [0.06, 0.07], [-0.06, -0.07], [0.06, -0.07]].forEach(function(pos) {
|
|
60
|
+
var screw = new THREE.Mesh(
|
|
61
|
+
new THREE.CylinderGeometry(0.008, 0.008, 0.014, 8),
|
|
62
|
+
PAL.chrome()
|
|
63
|
+
);
|
|
64
|
+
screw.rotation.x = Math.PI / 2;
|
|
65
|
+
screw.position.set(pos[0], H / 2 + 0.05 + pos[1], -bezelThick / 2 - 0.015);
|
|
66
|
+
g.add(screw);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Thin chrome edge trim (bottom edge)
|
|
70
|
+
var trim = new THREE.Mesh(
|
|
71
|
+
new THREE.BoxGeometry(W + 0.01, 0.010, bezelThick + 0.005),
|
|
72
|
+
PAL.chrome()
|
|
73
|
+
);
|
|
74
|
+
trim.position.y = 0.042;
|
|
75
|
+
g.add(trim);
|
|
76
|
+
|
|
77
|
+
return g;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'vase',
|
|
6
|
+
name: 'Vase',
|
|
7
|
+
category: 'decor',
|
|
8
|
+
icon: 'Vs',
|
|
9
|
+
gridW: 1, gridD: 1, height: 1.0,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Small side table — dark walnut legs
|
|
14
|
+
var tableLeg = mat(0x2a1808, { roughness: 0.60 });
|
|
15
|
+
|
|
16
|
+
var legFL = new THREE.Mesh(new THREE.BoxGeometry(0.035, 0.58, 0.035), tableLeg);
|
|
17
|
+
legFL.position.set(-0.13, 0.29, -0.13);
|
|
18
|
+
legFL.castShadow = true;
|
|
19
|
+
g.add(legFL);
|
|
20
|
+
|
|
21
|
+
var legFR = new THREE.Mesh(new THREE.BoxGeometry(0.035, 0.58, 0.035), tableLeg);
|
|
22
|
+
legFR.position.set(0.13, 0.29, -0.13);
|
|
23
|
+
legFR.castShadow = true;
|
|
24
|
+
g.add(legFR);
|
|
25
|
+
|
|
26
|
+
var legBL = new THREE.Mesh(new THREE.BoxGeometry(0.035, 0.58, 0.035), tableLeg);
|
|
27
|
+
legBL.position.set(-0.13, 0.29, 0.13);
|
|
28
|
+
legBL.castShadow = true;
|
|
29
|
+
g.add(legBL);
|
|
30
|
+
|
|
31
|
+
var legBR = new THREE.Mesh(new THREE.BoxGeometry(0.035, 0.58, 0.035), tableLeg);
|
|
32
|
+
legBR.position.set(0.13, 0.29, 0.13);
|
|
33
|
+
legBR.castShadow = true;
|
|
34
|
+
g.add(legBR);
|
|
35
|
+
|
|
36
|
+
// Table top
|
|
37
|
+
var tabletop = new THREE.Mesh(
|
|
38
|
+
new THREE.BoxGeometry(0.32, 0.025, 0.32),
|
|
39
|
+
PAL.walnutDark()
|
|
40
|
+
);
|
|
41
|
+
tabletop.position.y = 0.6;
|
|
42
|
+
tabletop.castShadow = true;
|
|
43
|
+
tabletop.receiveShadow = true;
|
|
44
|
+
g.add(tabletop);
|
|
45
|
+
|
|
46
|
+
// Vase base (flared bottom)
|
|
47
|
+
var vaseBase = new THREE.Mesh(
|
|
48
|
+
new THREE.CylinderGeometry(0.10, 0.07, 0.08, 20),
|
|
49
|
+
mat(0x1a1a24, { roughness: 0.18, metalness: 0.08 })
|
|
50
|
+
);
|
|
51
|
+
vaseBase.position.y = 0.665;
|
|
52
|
+
vaseBase.castShadow = true;
|
|
53
|
+
g.add(vaseBase);
|
|
54
|
+
|
|
55
|
+
// Vase body (tapered cylinder — dark glaze)
|
|
56
|
+
var vaseBody = new THREE.Mesh(
|
|
57
|
+
new THREE.CylinderGeometry(0.085, 0.10, 0.28, 20),
|
|
58
|
+
mat(0x12121a, { roughness: 0.14, metalness: 0.10 })
|
|
59
|
+
);
|
|
60
|
+
vaseBody.position.y = 0.85;
|
|
61
|
+
vaseBody.castShadow = true;
|
|
62
|
+
g.add(vaseBody);
|
|
63
|
+
|
|
64
|
+
// Vase neck (narrow)
|
|
65
|
+
var vaseNeck = new THREE.Mesh(
|
|
66
|
+
new THREE.CylinderGeometry(0.042, 0.085, 0.10, 20),
|
|
67
|
+
mat(0x12121a, { roughness: 0.14, metalness: 0.10 })
|
|
68
|
+
);
|
|
69
|
+
vaseNeck.position.y = 1.04;
|
|
70
|
+
vaseNeck.castShadow = true;
|
|
71
|
+
g.add(vaseNeck);
|
|
72
|
+
|
|
73
|
+
// Vase lip (slight flare at top)
|
|
74
|
+
var vaseLip = new THREE.Mesh(
|
|
75
|
+
new THREE.CylinderGeometry(0.052, 0.042, 0.03, 20),
|
|
76
|
+
mat(0x1e1e2a, { roughness: 0.12, metalness: 0.12 })
|
|
77
|
+
);
|
|
78
|
+
vaseLip.position.y = 1.105;
|
|
79
|
+
vaseLip.castShadow = true;
|
|
80
|
+
g.add(vaseLip);
|
|
81
|
+
|
|
82
|
+
return g;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'wall_clock',
|
|
6
|
+
name: 'Wall Clock',
|
|
7
|
+
category: 'decor',
|
|
8
|
+
icon: 'Wc',
|
|
9
|
+
gridW: 1, gridD: 1, height: 2.5,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Clock face (dark dial)
|
|
14
|
+
var face = new THREE.Mesh(
|
|
15
|
+
new THREE.CylinderGeometry(0.195, 0.195, 0.018, 40),
|
|
16
|
+
mat(0x18191f, { roughness: 0.60 })
|
|
17
|
+
);
|
|
18
|
+
face.position.set(0, 2.5, 0);
|
|
19
|
+
face.rotation.x = Math.PI / 2;
|
|
20
|
+
face.receiveShadow = true;
|
|
21
|
+
g.add(face);
|
|
22
|
+
|
|
23
|
+
// Chrome rim ring
|
|
24
|
+
var rim = new THREE.Mesh(
|
|
25
|
+
new THREE.TorusGeometry(0.2, 0.018, 12, 48),
|
|
26
|
+
PAL.chrome()
|
|
27
|
+
);
|
|
28
|
+
rim.position.set(0, 2.5, 0.008);
|
|
29
|
+
rim.castShadow = true;
|
|
30
|
+
g.add(rim);
|
|
31
|
+
|
|
32
|
+
// Hour markers (12 small gold dots)
|
|
33
|
+
var markerMat = PAL.gold();
|
|
34
|
+
for (var i = 0; i < 12; i++) {
|
|
35
|
+
var angle = (i / 12) * Math.PI * 2;
|
|
36
|
+
var mx = Math.sin(angle) * 0.155;
|
|
37
|
+
var my = Math.cos(angle) * 0.155;
|
|
38
|
+
var marker = new THREE.Mesh(
|
|
39
|
+
new THREE.CylinderGeometry(0.008, 0.008, 0.012, 8),
|
|
40
|
+
markerMat
|
|
41
|
+
);
|
|
42
|
+
marker.position.set(mx, 2.5 + my, 0.016);
|
|
43
|
+
marker.rotation.x = Math.PI / 2;
|
|
44
|
+
g.add(marker);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Hour hand (short, gold)
|
|
48
|
+
var hourHand = new THREE.Mesh(
|
|
49
|
+
new THREE.BoxGeometry(0.016, 0.09, 0.010),
|
|
50
|
+
PAL.gold()
|
|
51
|
+
);
|
|
52
|
+
hourHand.position.set(0.028, 2.535, 0.022);
|
|
53
|
+
hourHand.rotation.z = -0.9;
|
|
54
|
+
g.add(hourHand);
|
|
55
|
+
|
|
56
|
+
// Minute hand (long, chrome)
|
|
57
|
+
var minHand = new THREE.Mesh(
|
|
58
|
+
new THREE.BoxGeometry(0.011, 0.135, 0.010),
|
|
59
|
+
PAL.chrome()
|
|
60
|
+
);
|
|
61
|
+
minHand.position.set(-0.04, 2.562, 0.024);
|
|
62
|
+
minHand.rotation.z = 0.7;
|
|
63
|
+
g.add(minHand);
|
|
64
|
+
|
|
65
|
+
// Center cap
|
|
66
|
+
var cap = new THREE.Mesh(
|
|
67
|
+
new THREE.CylinderGeometry(0.012, 0.012, 0.014, 12),
|
|
68
|
+
PAL.gold()
|
|
69
|
+
);
|
|
70
|
+
cap.position.set(0, 2.5, 0.022);
|
|
71
|
+
cap.rotation.x = Math.PI / 2;
|
|
72
|
+
g.add(cap);
|
|
73
|
+
|
|
74
|
+
// Wall bracket (small block behind)
|
|
75
|
+
var bracket = new THREE.Mesh(
|
|
76
|
+
new THREE.BoxGeometry(0.06, 0.10, 0.04),
|
|
77
|
+
mat(0x111111, { roughness: 0.6, metalness: 0.4 })
|
|
78
|
+
);
|
|
79
|
+
bracket.position.set(0, 2.5, -0.03);
|
|
80
|
+
g.add(bracket);
|
|
81
|
+
|
|
82
|
+
return g;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'wall',
|
|
6
|
+
name: 'Wall',
|
|
7
|
+
category: 'structural',
|
|
8
|
+
icon: 'Wa',
|
|
9
|
+
gridW: 2, gridD: 1, height: 3,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Main body
|
|
14
|
+
var body = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(2, 3, 0.3),
|
|
16
|
+
PAL.concrete()
|
|
17
|
+
);
|
|
18
|
+
body.castShadow = true;
|
|
19
|
+
body.receiveShadow = true;
|
|
20
|
+
g.add(body);
|
|
21
|
+
|
|
22
|
+
// Top trim strip
|
|
23
|
+
var trim = new THREE.Mesh(
|
|
24
|
+
new THREE.BoxGeometry(2, 0.06, 0.32),
|
|
25
|
+
mat(0x1e2128, { roughness: 0.7 })
|
|
26
|
+
);
|
|
27
|
+
trim.position.y = 1.47;
|
|
28
|
+
trim.castShadow = true;
|
|
29
|
+
g.add(trim);
|
|
30
|
+
|
|
31
|
+
// Bottom base strip
|
|
32
|
+
var base = new THREE.Mesh(
|
|
33
|
+
new THREE.BoxGeometry(2, 0.1, 0.34),
|
|
34
|
+
mat(0x1e2128, { roughness: 0.7 })
|
|
35
|
+
);
|
|
36
|
+
base.position.y = -1.45;
|
|
37
|
+
g.add(base);
|
|
38
|
+
|
|
39
|
+
// Subtle vertical score lines (decoration)
|
|
40
|
+
var score1 = new THREE.Mesh(
|
|
41
|
+
new THREE.BoxGeometry(0.02, 2.8, 0.31),
|
|
42
|
+
mat(0x22252e, { roughness: 0.9 })
|
|
43
|
+
);
|
|
44
|
+
score1.position.x = -0.5;
|
|
45
|
+
g.add(score1);
|
|
46
|
+
|
|
47
|
+
var score2 = score1.clone();
|
|
48
|
+
score2.position.x = 0.5;
|
|
49
|
+
g.add(score2);
|
|
50
|
+
|
|
51
|
+
return g;
|
|
52
|
+
}
|
|
53
|
+
};
|