let-them-talk 5.3.0 → 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 -7216
- 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,67 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'pendant_light',
|
|
6
|
+
name: 'Pendant Light',
|
|
7
|
+
category: 'lighting',
|
|
8
|
+
icon: 'PL',
|
|
9
|
+
gridW: 1, gridD: 1, height: 3.0,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var wireY = 3.0; // wire top anchor
|
|
14
|
+
var shadeY = 2.10; // bottom of shade
|
|
15
|
+
var R = 0.12; // globe radius
|
|
16
|
+
|
|
17
|
+
var chromeMat = PAL.chrome();
|
|
18
|
+
var cordMat = mat(0x1a1a1a, { roughness: 0.90 });
|
|
19
|
+
|
|
20
|
+
// Ceiling rose (mount disk)
|
|
21
|
+
var rose = new THREE.Mesh(new THREE.CylinderGeometry(0.055, 0.055, 0.018, 20), chromeMat);
|
|
22
|
+
rose.position.y = wireY;
|
|
23
|
+
g.add(rose);
|
|
24
|
+
|
|
25
|
+
// Pendant cord (thin cylinder)
|
|
26
|
+
var cordLen = wireY - shadeY - R - 0.01;
|
|
27
|
+
var cord = new THREE.Mesh(
|
|
28
|
+
new THREE.CylinderGeometry(0.006, 0.006, cordLen, 8),
|
|
29
|
+
cordMat
|
|
30
|
+
);
|
|
31
|
+
cord.position.y = shadeY + R + 0.01 + cordLen / 2;
|
|
32
|
+
g.add(cord);
|
|
33
|
+
|
|
34
|
+
// Globe shade (hollow sphere shell — DoubleSide)
|
|
35
|
+
var globeOuter = new THREE.Mesh(
|
|
36
|
+
new THREE.SphereGeometry(R, 28, 20),
|
|
37
|
+
mat(0xeae0d0, { transparent: true, opacity: 0.55, roughness: 0.10, side: THREE.DoubleSide })
|
|
38
|
+
);
|
|
39
|
+
globeOuter.position.y = shadeY + R;
|
|
40
|
+
g.add(globeOuter);
|
|
41
|
+
|
|
42
|
+
// Internal warm bulb glow
|
|
43
|
+
var bulb = new THREE.Mesh(
|
|
44
|
+
new THREE.SphereGeometry(0.028, 14, 10),
|
|
45
|
+
mat(0xfff0cc, { emissive: 0xfff0cc, emissiveIntensity: 1.4, transparent: true, opacity: 0.95 })
|
|
46
|
+
);
|
|
47
|
+
bulb.position.y = shadeY + R;
|
|
48
|
+
g.add(bulb);
|
|
49
|
+
|
|
50
|
+
// Chrome neck fitting (top of globe)
|
|
51
|
+
var neck = new THREE.Mesh(new THREE.CylinderGeometry(0.018, 0.018, 0.025, 14), chromeMat);
|
|
52
|
+
neck.position.y = shadeY + R * 2 - 0.005;
|
|
53
|
+
g.add(neck);
|
|
54
|
+
|
|
55
|
+
// Chrome bottom vent ring (open bottom)
|
|
56
|
+
var botRing = new THREE.Mesh(new THREE.TorusGeometry(R - 0.005, 0.005, 8, 28), chromeMat);
|
|
57
|
+
botRing.position.y = shadeY + 0.008;
|
|
58
|
+
g.add(botRing);
|
|
59
|
+
|
|
60
|
+
// Point light — hangs at bulb position
|
|
61
|
+
var light = new THREE.PointLight(0xfff0cc, 0.45, 5);
|
|
62
|
+
light.position.y = shadeY + R;
|
|
63
|
+
g.add(light);
|
|
64
|
+
|
|
65
|
+
return g;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'ping_pong',
|
|
6
|
+
name: 'Ping Pong Table',
|
|
7
|
+
category: 'recreation',
|
|
8
|
+
icon: 'PP',
|
|
9
|
+
gridW: 3, gridD: 2, height: 0.76,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Table top — green with dark edge
|
|
14
|
+
var top = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(2.74, 0.04, 1.52),
|
|
16
|
+
mat(0x115522, { roughness: 0.75 })
|
|
17
|
+
);
|
|
18
|
+
top.position.y = 0.74;
|
|
19
|
+
top.castShadow = true;
|
|
20
|
+
top.receiveShadow = true;
|
|
21
|
+
g.add(top);
|
|
22
|
+
|
|
23
|
+
// White edge border (thin frame around top surface)
|
|
24
|
+
var edgeMat = mat(0xffffff, { roughness: 0.70 });
|
|
25
|
+
var edgeLong = new THREE.BoxGeometry(2.74, 0.042, 0.018);
|
|
26
|
+
var edgeShort = new THREE.BoxGeometry(0.018, 0.042, 1.52);
|
|
27
|
+
[0.761, -0.761].forEach(function(z) {
|
|
28
|
+
var e = new THREE.Mesh(edgeLong, edgeMat);
|
|
29
|
+
e.position.set(0, 0.74, z);
|
|
30
|
+
g.add(e);
|
|
31
|
+
});
|
|
32
|
+
[-1.371, 1.371].forEach(function(x) {
|
|
33
|
+
var e = new THREE.Mesh(edgeShort, edgeMat);
|
|
34
|
+
e.position.set(x, 0.74, 0);
|
|
35
|
+
g.add(e);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// White center line (lengthwise)
|
|
39
|
+
var centerLine = new THREE.Mesh(
|
|
40
|
+
new THREE.BoxGeometry(2.74, 0.045, 0.022),
|
|
41
|
+
edgeMat
|
|
42
|
+
);
|
|
43
|
+
centerLine.position.set(0, 0.74, 0);
|
|
44
|
+
g.add(centerLine);
|
|
45
|
+
|
|
46
|
+
// White half-court line (across middle)
|
|
47
|
+
var halfLine = new THREE.Mesh(
|
|
48
|
+
new THREE.BoxGeometry(0.022, 0.045, 1.52),
|
|
49
|
+
edgeMat
|
|
50
|
+
);
|
|
51
|
+
halfLine.position.set(0, 0.74, 0);
|
|
52
|
+
g.add(halfLine);
|
|
53
|
+
|
|
54
|
+
// Net post — left
|
|
55
|
+
var postMat = PAL.chrome();
|
|
56
|
+
var postGeo = new THREE.CylinderGeometry(0.014, 0.014, 0.20, 8);
|
|
57
|
+
var leftPost = new THREE.Mesh(postGeo, postMat);
|
|
58
|
+
leftPost.position.set(0, 0.85, 0.78);
|
|
59
|
+
leftPost.castShadow = true;
|
|
60
|
+
g.add(leftPost);
|
|
61
|
+
|
|
62
|
+
// Net post — right
|
|
63
|
+
var rightPost = leftPost.clone();
|
|
64
|
+
rightPost.position.z = -0.78;
|
|
65
|
+
g.add(rightPost);
|
|
66
|
+
|
|
67
|
+
// Net top bar
|
|
68
|
+
var netBar = new THREE.Mesh(
|
|
69
|
+
new THREE.CylinderGeometry(0.008, 0.008, 1.56, 8),
|
|
70
|
+
postMat
|
|
71
|
+
);
|
|
72
|
+
netBar.rotation.x = Math.PI / 2;
|
|
73
|
+
netBar.position.set(0, 0.945, 0);
|
|
74
|
+
g.add(netBar);
|
|
75
|
+
|
|
76
|
+
// Net mesh (semi-transparent white)
|
|
77
|
+
var net = new THREE.Mesh(
|
|
78
|
+
new THREE.BoxGeometry(0.008, 0.16, 1.52),
|
|
79
|
+
mat(0xffffff, { transparent: true, opacity: 0.55, roughness: 0.70, side: THREE.DoubleSide })
|
|
80
|
+
);
|
|
81
|
+
net.position.set(0, 0.865, 0);
|
|
82
|
+
g.add(net);
|
|
83
|
+
|
|
84
|
+
// Chrome folding legs (angled X-frame style) — 4 corner assemblies
|
|
85
|
+
var legMat = PAL.chromeBrushed();
|
|
86
|
+
var legGeo = new THREE.CylinderGeometry(0.018, 0.018, 0.78, 8);
|
|
87
|
+
[[-1.18, 0.37, 0.58], [1.18, 0.37, 0.58], [-1.18, 0.37, -0.58], [1.18, 0.37, -0.58]].forEach(function(p) {
|
|
88
|
+
var leg = new THREE.Mesh(legGeo, legMat);
|
|
89
|
+
leg.position.set(p[0], p[1], p[2]);
|
|
90
|
+
leg.castShadow = true;
|
|
91
|
+
g.add(leg);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Horizontal leg brace (side spreader bars)
|
|
95
|
+
var braceGeo = new THREE.CylinderGeometry(0.012, 0.012, 1.16, 8);
|
|
96
|
+
[[0.58], [-0.58]].forEach(function(arr) {
|
|
97
|
+
var brace = new THREE.Mesh(braceGeo, legMat);
|
|
98
|
+
brace.rotation.z = Math.PI / 2;
|
|
99
|
+
brace.position.set(0, 0.16, arr[0]);
|
|
100
|
+
g.add(brace);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Small rubber feet
|
|
104
|
+
var feetMat = mat(0x0a0a0a, { roughness: 0.92 });
|
|
105
|
+
var feetGeo = new THREE.CylinderGeometry(0.022, 0.022, 0.016, 8);
|
|
106
|
+
[[-1.18, 0.008, 0.58], [1.18, 0.008, 0.58], [-1.18, 0.008, -0.58], [1.18, 0.008, -0.58]].forEach(function(p) {
|
|
107
|
+
var foot = new THREE.Mesh(feetGeo, feetMat);
|
|
108
|
+
foot.position.set(p[0], p[1], p[2]);
|
|
109
|
+
g.add(foot);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return g;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'plant',
|
|
6
|
+
name: 'Plant',
|
|
7
|
+
category: 'nature',
|
|
8
|
+
icon: 'Pl',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.8,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Concrete planter — cylindrical
|
|
14
|
+
var planter = new THREE.Mesh(
|
|
15
|
+
new THREE.CylinderGeometry(0.22, 0.17, 0.30, 20),
|
|
16
|
+
mat(0x3a3d44, { roughness: 0.90 })
|
|
17
|
+
);
|
|
18
|
+
planter.position.y = 0.15;
|
|
19
|
+
planter.castShadow = true;
|
|
20
|
+
planter.receiveShadow = true;
|
|
21
|
+
g.add(planter);
|
|
22
|
+
|
|
23
|
+
// Planter rim
|
|
24
|
+
var rim = new THREE.Mesh(
|
|
25
|
+
new THREE.TorusGeometry(0.22, 0.018, 8, 28),
|
|
26
|
+
mat(0x2a2d33, { roughness: 0.85 })
|
|
27
|
+
);
|
|
28
|
+
rim.position.y = 0.298;
|
|
29
|
+
rim.rotation.x = Math.PI / 2;
|
|
30
|
+
g.add(rim);
|
|
31
|
+
|
|
32
|
+
// Soil surface
|
|
33
|
+
var soil = new THREE.Mesh(
|
|
34
|
+
new THREE.CylinderGeometry(0.20, 0.20, 0.02, 20),
|
|
35
|
+
mat(0x1a1510, { roughness: 0.99 })
|
|
36
|
+
);
|
|
37
|
+
soil.position.y = 0.31;
|
|
38
|
+
g.add(soil);
|
|
39
|
+
|
|
40
|
+
// Leaf cluster 1 (center, taller)
|
|
41
|
+
var leaf1 = new THREE.Mesh(
|
|
42
|
+
new THREE.SphereGeometry(0.19, 12, 10),
|
|
43
|
+
PAL.leaf()
|
|
44
|
+
);
|
|
45
|
+
leaf1.scale.set(1, 1.35, 1);
|
|
46
|
+
leaf1.position.set(0, 0.62, 0);
|
|
47
|
+
leaf1.castShadow = true;
|
|
48
|
+
g.add(leaf1);
|
|
49
|
+
|
|
50
|
+
// Leaf cluster 2 (left, lower)
|
|
51
|
+
var leaf2 = new THREE.Mesh(
|
|
52
|
+
new THREE.SphereGeometry(0.14, 10, 8),
|
|
53
|
+
mat(0x226638, { roughness: 0.82 })
|
|
54
|
+
);
|
|
55
|
+
leaf2.scale.set(1, 1.1, 1);
|
|
56
|
+
leaf2.position.set(-0.16, 0.52, 0.05);
|
|
57
|
+
leaf2.castShadow = true;
|
|
58
|
+
g.add(leaf2);
|
|
59
|
+
|
|
60
|
+
// Leaf cluster 3 (right)
|
|
61
|
+
var leaf3 = new THREE.Mesh(
|
|
62
|
+
new THREE.SphereGeometry(0.13, 10, 8),
|
|
63
|
+
mat(0x1e5c30, { roughness: 0.84 })
|
|
64
|
+
);
|
|
65
|
+
leaf3.scale.set(1, 1.2, 1);
|
|
66
|
+
leaf3.position.set(0.15, 0.55, -0.08);
|
|
67
|
+
leaf3.castShadow = true;
|
|
68
|
+
g.add(leaf3);
|
|
69
|
+
|
|
70
|
+
return g;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'planter_box',
|
|
6
|
+
name: 'Planter Box',
|
|
7
|
+
category: 'exterior',
|
|
8
|
+
icon: 'PB',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.6,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var concrete = PAL.concrete();
|
|
14
|
+
|
|
15
|
+
// Main concrete box body
|
|
16
|
+
var body = new THREE.Mesh(
|
|
17
|
+
new THREE.BoxGeometry(1.00, 0.50, 0.50),
|
|
18
|
+
concrete
|
|
19
|
+
);
|
|
20
|
+
body.position.y = 0.25;
|
|
21
|
+
body.castShadow = true;
|
|
22
|
+
body.receiveShadow = true;
|
|
23
|
+
g.add(body);
|
|
24
|
+
|
|
25
|
+
// Inner soil recess (dark soil color, sits inside top)
|
|
26
|
+
var soil = new THREE.Mesh(
|
|
27
|
+
new THREE.BoxGeometry(0.88, 0.12, 0.38),
|
|
28
|
+
mat(0x1a1206, { roughness: 0.95 })
|
|
29
|
+
);
|
|
30
|
+
soil.position.y = 0.50;
|
|
31
|
+
g.add(soil);
|
|
32
|
+
|
|
33
|
+
// Chamfered top edge detail (thin cap strip)
|
|
34
|
+
var cap = new THREE.Mesh(
|
|
35
|
+
new THREE.BoxGeometry(1.00, 0.030, 0.50),
|
|
36
|
+
mat(0x343740, { roughness: 0.80 })
|
|
37
|
+
);
|
|
38
|
+
cap.position.y = 0.515;
|
|
39
|
+
g.add(cap);
|
|
40
|
+
|
|
41
|
+
// Horizontal groove lines on body (2 decorative channels)
|
|
42
|
+
var grooveMat = mat(0x1e2028, { roughness: 0.90 });
|
|
43
|
+
var grooveGeo = new THREE.BoxGeometry(1.002, 0.018, 0.502);
|
|
44
|
+
[0.18, 0.32].forEach(function(y) {
|
|
45
|
+
var groove = new THREE.Mesh(grooveGeo, grooveMat);
|
|
46
|
+
groove.position.y = y;
|
|
47
|
+
g.add(groove);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Greenery — cluster of rounded bush shapes
|
|
51
|
+
var leafMat = PAL.leaf();
|
|
52
|
+
var leafMat2 = mat(0x1d6e3a, { roughness: 0.82 });
|
|
53
|
+
|
|
54
|
+
var bushPositions = [
|
|
55
|
+
{ x: -0.26, s: 0.18, h: 0.14 },
|
|
56
|
+
{ x: 0, s: 0.22, h: 0.18 },
|
|
57
|
+
{ x: 0.26, s: 0.17, h: 0.13 }
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
bushPositions.forEach(function(b, idx) {
|
|
61
|
+
var bush = new THREE.Mesh(
|
|
62
|
+
new THREE.SphereGeometry(b.s, 10, 8),
|
|
63
|
+
idx % 2 === 0 ? leafMat : leafMat2
|
|
64
|
+
);
|
|
65
|
+
bush.scale.set(1.0, b.h / b.s, 1.0);
|
|
66
|
+
bush.position.set(b.x, 0.54 + b.h, 0);
|
|
67
|
+
bush.castShadow = true;
|
|
68
|
+
g.add(bush);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Small accent sprigs between bushes
|
|
72
|
+
var sprigMat = mat(0x3aaa5e, { roughness: 0.78 });
|
|
73
|
+
[-0.13, 0.13].forEach(function(x) {
|
|
74
|
+
var sprig = new THREE.Mesh(
|
|
75
|
+
new THREE.SphereGeometry(0.09, 8, 6),
|
|
76
|
+
sprigMat
|
|
77
|
+
);
|
|
78
|
+
sprig.scale.set(0.7, 0.9, 0.7);
|
|
79
|
+
sprig.position.set(x, 0.66, 0.04);
|
|
80
|
+
sprig.castShadow = true;
|
|
81
|
+
g.add(sprig);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Drainage detail (small holes on bottom face)
|
|
85
|
+
var drainMat = mat(0x111111, { roughness: 0.80 });
|
|
86
|
+
var drainGeo = new THREE.CylinderGeometry(0.018, 0.018, 0.012, 8);
|
|
87
|
+
[-0.22, 0, 0.22].forEach(function(x) {
|
|
88
|
+
var drain = new THREE.Mesh(drainGeo, drainMat);
|
|
89
|
+
drain.position.set(x, 0.004, 0);
|
|
90
|
+
g.add(drain);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return g;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'pool_table',
|
|
6
|
+
name: 'Pool Table',
|
|
7
|
+
category: 'recreation',
|
|
8
|
+
icon: 'PT',
|
|
9
|
+
gridW: 3, gridD: 2, height: 0.85,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Walnut outer frame
|
|
14
|
+
var frame = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(2.50, 0.16, 1.40),
|
|
16
|
+
PAL.walnutDark()
|
|
17
|
+
);
|
|
18
|
+
frame.position.y = 0.82;
|
|
19
|
+
frame.castShadow = true;
|
|
20
|
+
frame.receiveShadow = true;
|
|
21
|
+
g.add(frame);
|
|
22
|
+
|
|
23
|
+
// Green felt playing surface
|
|
24
|
+
var felt = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(2.28, 0.012, 1.18),
|
|
26
|
+
PAL.greenFelt()
|
|
27
|
+
);
|
|
28
|
+
felt.position.y = 0.914;
|
|
29
|
+
felt.receiveShadow = true;
|
|
30
|
+
g.add(felt);
|
|
31
|
+
|
|
32
|
+
// White center line
|
|
33
|
+
var centerLine = new THREE.Mesh(
|
|
34
|
+
new THREE.BoxGeometry(0.012, 0.015, 1.18),
|
|
35
|
+
mat(0xffffff, { roughness: 0.80 })
|
|
36
|
+
);
|
|
37
|
+
centerLine.position.y = 0.922;
|
|
38
|
+
g.add(centerLine);
|
|
39
|
+
|
|
40
|
+
// Baulk line (1/4 from end)
|
|
41
|
+
var baulkLine = new THREE.Mesh(
|
|
42
|
+
new THREE.BoxGeometry(0.012, 0.015, 1.18),
|
|
43
|
+
mat(0xffffff, { roughness: 0.80 })
|
|
44
|
+
);
|
|
45
|
+
baulkLine.position.set(-0.57, 0.922, 0);
|
|
46
|
+
g.add(baulkLine);
|
|
47
|
+
|
|
48
|
+
// 4 thick legs
|
|
49
|
+
var legMat = PAL.walnutDark();
|
|
50
|
+
var legGeo = new THREE.BoxGeometry(0.12, 0.78, 0.12);
|
|
51
|
+
[[-1.10, 0.39, 0.55], [1.10, 0.39, 0.55], [-1.10, 0.39, -0.55], [1.10, 0.39, -0.55]].forEach(function(p) {
|
|
52
|
+
var leg = new THREE.Mesh(legGeo, legMat);
|
|
53
|
+
leg.position.set(p[0], p[1], p[2]);
|
|
54
|
+
leg.castShadow = true;
|
|
55
|
+
g.add(leg);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// 6 pockets — small dark spheres
|
|
59
|
+
var pocketMat = mat(0x0a0a0a, { roughness: 0.70 });
|
|
60
|
+
var pocketGeo = new THREE.SphereGeometry(0.055, 10, 8);
|
|
61
|
+
var pocketPositions = [
|
|
62
|
+
[-1.11, 0.920, 0.56], // corners
|
|
63
|
+
[1.11, 0.920, 0.56],
|
|
64
|
+
[-1.11, 0.920, -0.56],
|
|
65
|
+
[1.11, 0.920, -0.56],
|
|
66
|
+
[0, 0.920, 0.60], // side midpoints
|
|
67
|
+
[0, 0.920, -0.60]
|
|
68
|
+
];
|
|
69
|
+
pocketPositions.forEach(function(p) {
|
|
70
|
+
var pocket = new THREE.Mesh(pocketGeo, pocketMat);
|
|
71
|
+
pocket.position.set(p[0], p[1], p[2]);
|
|
72
|
+
g.add(pocket);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Rail cushions (dark rubber strips around the inside edge)
|
|
76
|
+
var railMat = mat(0x1a1a0a, { roughness: 0.85 });
|
|
77
|
+
// Long rails
|
|
78
|
+
var longRailGeo = new THREE.BoxGeometry(2.26, 0.08, 0.04);
|
|
79
|
+
[0.565, -0.565].forEach(function(z) {
|
|
80
|
+
var rail = new THREE.Mesh(longRailGeo, railMat);
|
|
81
|
+
rail.position.set(0, 0.89, z);
|
|
82
|
+
g.add(rail);
|
|
83
|
+
});
|
|
84
|
+
// Short rails
|
|
85
|
+
var shortRailGeo = new THREE.BoxGeometry(0.04, 0.08, 1.10);
|
|
86
|
+
[-1.11, 1.11].forEach(function(x) {
|
|
87
|
+
var rail = new THREE.Mesh(shortRailGeo, railMat);
|
|
88
|
+
rail.position.set(x, 0.89, 0);
|
|
89
|
+
g.add(rail);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return g;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'printer',
|
|
6
|
+
name: 'Printer',
|
|
7
|
+
category: 'office',
|
|
8
|
+
icon: 'Pr',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.4,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var bodyMat = mat(0x1e2128, { roughness: 0.50, metalness: 0.12 });
|
|
14
|
+
var accentMat = mat(0x252830, { roughness: 0.45, metalness: 0.10 });
|
|
15
|
+
|
|
16
|
+
// Main body block
|
|
17
|
+
var body = new THREE.Mesh(
|
|
18
|
+
new THREE.BoxGeometry(0.6, 0.32, 0.5),
|
|
19
|
+
bodyMat
|
|
20
|
+
);
|
|
21
|
+
body.position.y = 0.2;
|
|
22
|
+
body.castShadow = true;
|
|
23
|
+
body.receiveShadow = true;
|
|
24
|
+
g.add(body);
|
|
25
|
+
|
|
26
|
+
// Top scanner lid (slightly lighter)
|
|
27
|
+
var lid = new THREE.Mesh(
|
|
28
|
+
new THREE.BoxGeometry(0.6, 0.055, 0.5),
|
|
29
|
+
accentMat
|
|
30
|
+
);
|
|
31
|
+
lid.position.y = 0.388;
|
|
32
|
+
lid.castShadow = true;
|
|
33
|
+
g.add(lid);
|
|
34
|
+
|
|
35
|
+
// Scanner glass on top
|
|
36
|
+
var scanGlass = new THREE.Mesh(
|
|
37
|
+
new THREE.BoxGeometry(0.54, 0.01, 0.44),
|
|
38
|
+
mat(0x445566, { transparent: true, opacity: 0.55, roughness: 0.10 })
|
|
39
|
+
);
|
|
40
|
+
scanGlass.position.y = 0.418;
|
|
41
|
+
g.add(scanGlass);
|
|
42
|
+
|
|
43
|
+
// Paper output tray (front, slanted slot)
|
|
44
|
+
var outTray = new THREE.Mesh(
|
|
45
|
+
new THREE.BoxGeometry(0.44, 0.012, 0.22),
|
|
46
|
+
accentMat
|
|
47
|
+
);
|
|
48
|
+
outTray.rotation.x = -0.22;
|
|
49
|
+
outTray.position.set(0, 0.305, 0.255);
|
|
50
|
+
g.add(outTray);
|
|
51
|
+
|
|
52
|
+
// Paper input tray (slightly open slot at back)
|
|
53
|
+
var inTray = new THREE.Mesh(
|
|
54
|
+
new THREE.BoxGeometry(0.40, 0.012, 0.18),
|
|
55
|
+
accentMat
|
|
56
|
+
);
|
|
57
|
+
inTray.rotation.x = 0.2;
|
|
58
|
+
inTray.position.set(0, 0.355, -0.23);
|
|
59
|
+
g.add(inTray);
|
|
60
|
+
|
|
61
|
+
// Front control panel strip
|
|
62
|
+
var panel = new THREE.Mesh(
|
|
63
|
+
new THREE.BoxGeometry(0.58, 0.055, 0.012),
|
|
64
|
+
mat(0x111318, { roughness: 0.4 })
|
|
65
|
+
);
|
|
66
|
+
panel.position.set(0, 0.32, 0.256);
|
|
67
|
+
g.add(panel);
|
|
68
|
+
|
|
69
|
+
// Small LED indicator light (green)
|
|
70
|
+
var led = new THREE.Mesh(
|
|
71
|
+
new THREE.SphereGeometry(0.008, 8, 8),
|
|
72
|
+
mat(0x22c55e, { emissive: 0x22c55e, emissiveIntensity: 0.8 })
|
|
73
|
+
);
|
|
74
|
+
led.position.set(0.22, 0.325, 0.258);
|
|
75
|
+
g.add(led);
|
|
76
|
+
|
|
77
|
+
// Power button
|
|
78
|
+
var btn = new THREE.Mesh(
|
|
79
|
+
new THREE.CylinderGeometry(0.01, 0.01, 0.008, 10),
|
|
80
|
+
mat(0x444444, { roughness: 0.6 })
|
|
81
|
+
);
|
|
82
|
+
btn.rotation.x = Math.PI / 2;
|
|
83
|
+
btn.position.set(0.18, 0.322, 0.258);
|
|
84
|
+
g.add(btn);
|
|
85
|
+
|
|
86
|
+
// Brand label strip
|
|
87
|
+
var label = new THREE.Mesh(
|
|
88
|
+
new THREE.BoxGeometry(0.18, 0.025, 0.008),
|
|
89
|
+
mat(0x111111, { roughness: 0.7 })
|
|
90
|
+
);
|
|
91
|
+
label.position.set(-0.12, 0.322, 0.257);
|
|
92
|
+
g.add(label);
|
|
93
|
+
|
|
94
|
+
// USB/port strip on right side
|
|
95
|
+
var portStrip = new THREE.Mesh(
|
|
96
|
+
new THREE.BoxGeometry(0.012, 0.025, 0.05),
|
|
97
|
+
mat(0x111111, { roughness: 0.7 })
|
|
98
|
+
);
|
|
99
|
+
portStrip.position.set(0.307, 0.20, 0.1);
|
|
100
|
+
g.add(portStrip);
|
|
101
|
+
|
|
102
|
+
// 4 rubber feet
|
|
103
|
+
var footMat = mat(0x111111, { roughness: 0.95 });
|
|
104
|
+
var footGeo = new THREE.CylinderGeometry(0.018, 0.018, 0.012, 8);
|
|
105
|
+
[[-0.24, -0.21], [0.24, -0.21], [-0.24, 0.21], [0.24, 0.21]].forEach(function(p) {
|
|
106
|
+
var foot = new THREE.Mesh(footGeo, footMat);
|
|
107
|
+
foot.position.set(p[0], 0.006, p[1]);
|
|
108
|
+
g.add(foot);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return g;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'reception-desk',
|
|
6
|
+
name: 'Reception Desk',
|
|
7
|
+
category: 'office',
|
|
8
|
+
icon: 'RD',
|
|
9
|
+
gridW: 4, gridD: 2, height: 1.1,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var bodyMat = mat(0x17191f, { roughness: 0.55, metalness: 0.10 });
|
|
14
|
+
var marbleMat = PAL.marbleBlack();
|
|
15
|
+
var ledMat = mat(0x58a6ff, { emissive: 0x58a6ff, emissiveIntensity: 0.7, roughness: 0.2 });
|
|
16
|
+
|
|
17
|
+
// === MAIN COUNTER (long front section) ===
|
|
18
|
+
// Counter body
|
|
19
|
+
var mainBody = new THREE.Mesh(
|
|
20
|
+
new THREE.BoxGeometry(4.0, 1.0, 0.65),
|
|
21
|
+
bodyMat
|
|
22
|
+
);
|
|
23
|
+
mainBody.position.set(0, 0.5, 0);
|
|
24
|
+
mainBody.castShadow = true;
|
|
25
|
+
mainBody.receiveShadow = true;
|
|
26
|
+
g.add(mainBody);
|
|
27
|
+
|
|
28
|
+
// Marble top — main
|
|
29
|
+
var mainTop = new THREE.Mesh(
|
|
30
|
+
new THREE.BoxGeometry(4.04, 0.06, 0.69),
|
|
31
|
+
marbleMat
|
|
32
|
+
);
|
|
33
|
+
mainTop.position.set(0, 1.03, 0);
|
|
34
|
+
mainTop.castShadow = true;
|
|
35
|
+
g.add(mainTop);
|
|
36
|
+
|
|
37
|
+
// Front panel fascia (slightly raised detail strip)
|
|
38
|
+
var fascia = new THREE.Mesh(
|
|
39
|
+
new THREE.BoxGeometry(3.96, 0.55, 0.02),
|
|
40
|
+
mat(0x1e2128, { roughness: 0.4, metalness: 0.18 })
|
|
41
|
+
);
|
|
42
|
+
fascia.position.set(0, 0.52, 0.335);
|
|
43
|
+
g.add(fascia);
|
|
44
|
+
|
|
45
|
+
// LED underglow strip — main front
|
|
46
|
+
var ledStrip = new THREE.Mesh(
|
|
47
|
+
new THREE.BoxGeometry(3.96, 0.018, 0.025),
|
|
48
|
+
ledMat
|
|
49
|
+
);
|
|
50
|
+
ledStrip.position.set(0, 0.065, 0.332);
|
|
51
|
+
g.add(ledStrip);
|
|
52
|
+
|
|
53
|
+
// Vertical divider panels on fascia (3 evenly spaced)
|
|
54
|
+
var divMat = mat(0x252830, { roughness: 0.5, metalness: 0.15 });
|
|
55
|
+
[-1.32, 0, 1.32].forEach(function(x) {
|
|
56
|
+
var div = new THREE.Mesh(new THREE.BoxGeometry(0.015, 0.52, 0.022), divMat);
|
|
57
|
+
div.position.set(x, 0.52, 0.336);
|
|
58
|
+
g.add(div);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// === WING SECTION (shorter right-angle return) ===
|
|
62
|
+
var wingBody = new THREE.Mesh(
|
|
63
|
+
new THREE.BoxGeometry(1.2, 1.0, 0.65),
|
|
64
|
+
bodyMat
|
|
65
|
+
);
|
|
66
|
+
wingBody.position.set(2.0, 0.5, 0.925);
|
|
67
|
+
wingBody.rotation.y = Math.PI / 2;
|
|
68
|
+
wingBody.castShadow = true;
|
|
69
|
+
wingBody.receiveShadow = true;
|
|
70
|
+
g.add(wingBody);
|
|
71
|
+
|
|
72
|
+
// Wing marble top
|
|
73
|
+
var wingTop = new THREE.Mesh(
|
|
74
|
+
new THREE.BoxGeometry(1.24, 0.06, 0.69),
|
|
75
|
+
marbleMat
|
|
76
|
+
);
|
|
77
|
+
wingTop.position.set(2.0, 1.03, 0.925);
|
|
78
|
+
wingTop.rotation.y = Math.PI / 2;
|
|
79
|
+
wingTop.castShadow = true;
|
|
80
|
+
g.add(wingTop);
|
|
81
|
+
|
|
82
|
+
// Wing front fascia
|
|
83
|
+
var wingFascia = new THREE.Mesh(
|
|
84
|
+
new THREE.BoxGeometry(0.02, 0.55, 1.16),
|
|
85
|
+
mat(0x1e2128, { roughness: 0.4, metalness: 0.18 })
|
|
86
|
+
);
|
|
87
|
+
wingFascia.position.set(2.335, 0.52, 0.925);
|
|
88
|
+
g.add(wingFascia);
|
|
89
|
+
|
|
90
|
+
// Wing LED underglow
|
|
91
|
+
var wingLed = new THREE.Mesh(
|
|
92
|
+
new THREE.BoxGeometry(0.025, 0.018, 1.16),
|
|
93
|
+
ledMat
|
|
94
|
+
);
|
|
95
|
+
wingLed.position.set(2.333, 0.065, 0.925);
|
|
96
|
+
g.add(wingLed);
|
|
97
|
+
|
|
98
|
+
// Corner connector piece (fills the gap)
|
|
99
|
+
var corner = new THREE.Mesh(
|
|
100
|
+
new THREE.BoxGeometry(0.65, 1.0, 0.65),
|
|
101
|
+
bodyMat
|
|
102
|
+
);
|
|
103
|
+
corner.position.set(2.0, 0.5, 0.325);
|
|
104
|
+
corner.castShadow = true;
|
|
105
|
+
g.add(corner);
|
|
106
|
+
|
|
107
|
+
// Corner marble top
|
|
108
|
+
var cornerTop = new THREE.Mesh(
|
|
109
|
+
new THREE.BoxGeometry(0.69, 0.06, 0.69),
|
|
110
|
+
marbleMat
|
|
111
|
+
);
|
|
112
|
+
cornerTop.position.set(2.0, 1.03, 0.325);
|
|
113
|
+
g.add(cornerTop);
|
|
114
|
+
|
|
115
|
+
// Inside rear shelf (staff side) — main
|
|
116
|
+
var innerShelf = new THREE.Mesh(
|
|
117
|
+
new THREE.BoxGeometry(3.8, 0.03, 0.42),
|
|
118
|
+
mat(0x1e2128, { roughness: 0.5 })
|
|
119
|
+
);
|
|
120
|
+
innerShelf.position.set(0, 0.72, -0.1);
|
|
121
|
+
g.add(innerShelf);
|
|
122
|
+
|
|
123
|
+
// Monitor mount riser on inner shelf
|
|
124
|
+
var riser = new THREE.Mesh(
|
|
125
|
+
new THREE.BoxGeometry(0.55, 0.06, 0.30),
|
|
126
|
+
mat(0x252830, { roughness: 0.45 })
|
|
127
|
+
);
|
|
128
|
+
riser.position.set(-0.8, 0.755, -0.1);
|
|
129
|
+
g.add(riser);
|
|
130
|
+
|
|
131
|
+
return g;
|
|
132
|
+
}
|
|
133
|
+
};
|