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,78 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'rug',
|
|
6
|
+
name: 'Rug',
|
|
7
|
+
category: 'decor',
|
|
8
|
+
icon: 'Rg',
|
|
9
|
+
gridW: 3, gridD: 2, height: 0.02,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Main rug body — dark burgundy
|
|
14
|
+
var body = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(3.0, 0.012, 2.0),
|
|
16
|
+
mat(0x4a0a18, { roughness: 0.98 })
|
|
17
|
+
);
|
|
18
|
+
body.position.y = 0.006;
|
|
19
|
+
body.receiveShadow = true;
|
|
20
|
+
g.add(body);
|
|
21
|
+
|
|
22
|
+
// Gold outer border (4 strips)
|
|
23
|
+
var borderMat = mat(0xc9a227, { roughness: 0.60, metalness: 0.15 });
|
|
24
|
+
|
|
25
|
+
var borderN = new THREE.Mesh(
|
|
26
|
+
new THREE.BoxGeometry(3.0, 0.013, 0.12),
|
|
27
|
+
borderMat
|
|
28
|
+
);
|
|
29
|
+
borderN.position.set(0, 0.007, -0.94);
|
|
30
|
+
borderN.receiveShadow = true;
|
|
31
|
+
g.add(borderN);
|
|
32
|
+
|
|
33
|
+
var borderS = new THREE.Mesh(
|
|
34
|
+
new THREE.BoxGeometry(3.0, 0.013, 0.12),
|
|
35
|
+
borderMat
|
|
36
|
+
);
|
|
37
|
+
borderS.position.set(0, 0.007, 0.94);
|
|
38
|
+
borderS.receiveShadow = true;
|
|
39
|
+
g.add(borderS);
|
|
40
|
+
|
|
41
|
+
var borderW = new THREE.Mesh(
|
|
42
|
+
new THREE.BoxGeometry(0.12, 0.013, 2.0),
|
|
43
|
+
borderMat
|
|
44
|
+
);
|
|
45
|
+
borderW.position.set(-1.44, 0.007, 0);
|
|
46
|
+
borderW.receiveShadow = true;
|
|
47
|
+
g.add(borderW);
|
|
48
|
+
|
|
49
|
+
var borderE = new THREE.Mesh(
|
|
50
|
+
new THREE.BoxGeometry(0.12, 0.013, 2.0),
|
|
51
|
+
borderMat
|
|
52
|
+
);
|
|
53
|
+
borderE.position.set(1.44, 0.007, 0);
|
|
54
|
+
borderE.receiveShadow = true;
|
|
55
|
+
g.add(borderE);
|
|
56
|
+
|
|
57
|
+
// Inner accent border (thin dark line)
|
|
58
|
+
var innerMat = mat(0x2a0510, { roughness: 0.98 });
|
|
59
|
+
|
|
60
|
+
var inN = new THREE.Mesh(new THREE.BoxGeometry(2.6, 0.014, 0.04), innerMat);
|
|
61
|
+
inN.position.set(0, 0.008, -0.78);
|
|
62
|
+
g.add(inN);
|
|
63
|
+
|
|
64
|
+
var inS = new THREE.Mesh(new THREE.BoxGeometry(2.6, 0.014, 0.04), innerMat);
|
|
65
|
+
inS.position.set(0, 0.008, 0.78);
|
|
66
|
+
g.add(inS);
|
|
67
|
+
|
|
68
|
+
var inW = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.014, 1.6), innerMat);
|
|
69
|
+
inW.position.set(-1.28, 0.008, 0);
|
|
70
|
+
g.add(inW);
|
|
71
|
+
|
|
72
|
+
var inE = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.014, 1.6), innerMat);
|
|
73
|
+
inE.position.set(1.28, 0.008, 0);
|
|
74
|
+
g.add(inE);
|
|
75
|
+
|
|
76
|
+
return g;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'sculpture',
|
|
6
|
+
name: 'Sculpture',
|
|
7
|
+
category: 'decor',
|
|
8
|
+
icon: 'Sc',
|
|
9
|
+
gridW: 1, gridD: 1, height: 1.2,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Pedestal base — dark slab
|
|
14
|
+
var pedBase = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(0.55, 0.06, 0.55),
|
|
16
|
+
PAL.marbleBlack()
|
|
17
|
+
);
|
|
18
|
+
pedBase.position.y = 0.03;
|
|
19
|
+
pedBase.castShadow = true;
|
|
20
|
+
pedBase.receiveShadow = true;
|
|
21
|
+
g.add(pedBase);
|
|
22
|
+
|
|
23
|
+
// Pedestal body
|
|
24
|
+
var pedBody = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(0.5, 1.0, 0.5),
|
|
26
|
+
mat(0x15171e, { roughness: 0.25, metalness: 0.05 })
|
|
27
|
+
);
|
|
28
|
+
pedBody.position.y = 0.56;
|
|
29
|
+
pedBody.castShadow = true;
|
|
30
|
+
pedBody.receiveShadow = true;
|
|
31
|
+
g.add(pedBody);
|
|
32
|
+
|
|
33
|
+
// Pedestal top cap
|
|
34
|
+
var pedTop = new THREE.Mesh(
|
|
35
|
+
new THREE.BoxGeometry(0.55, 0.05, 0.55),
|
|
36
|
+
PAL.marbleBlack()
|
|
37
|
+
);
|
|
38
|
+
pedTop.position.y = 1.085;
|
|
39
|
+
pedTop.castShadow = true;
|
|
40
|
+
g.add(pedTop);
|
|
41
|
+
|
|
42
|
+
// Chrome sphere (abstract sculpture)
|
|
43
|
+
var sphere = new THREE.Mesh(
|
|
44
|
+
new THREE.SphereGeometry(0.2, 32, 32),
|
|
45
|
+
PAL.chrome()
|
|
46
|
+
);
|
|
47
|
+
sphere.position.y = 1.31;
|
|
48
|
+
sphere.castShadow = true;
|
|
49
|
+
g.add(sphere);
|
|
50
|
+
|
|
51
|
+
// Small accent ring around base of sphere
|
|
52
|
+
var ring = new THREE.Mesh(
|
|
53
|
+
new THREE.TorusGeometry(0.21, 0.015, 12, 40),
|
|
54
|
+
PAL.gold()
|
|
55
|
+
);
|
|
56
|
+
ring.position.y = 1.11;
|
|
57
|
+
ring.rotation.x = Math.PI / 2;
|
|
58
|
+
ring.castShadow = true;
|
|
59
|
+
g.add(ring);
|
|
60
|
+
|
|
61
|
+
// Abstract protruding spike (artistic detail)
|
|
62
|
+
var spike = new THREE.Mesh(
|
|
63
|
+
new THREE.ConeGeometry(0.03, 0.25, 8),
|
|
64
|
+
PAL.chromeBrushed()
|
|
65
|
+
);
|
|
66
|
+
spike.position.set(0.12, 1.48, 0.08);
|
|
67
|
+
spike.rotation.z = -0.5;
|
|
68
|
+
spike.rotation.x = 0.3;
|
|
69
|
+
spike.castShadow = true;
|
|
70
|
+
g.add(spike);
|
|
71
|
+
|
|
72
|
+
// Second smaller spike
|
|
73
|
+
var spike2 = new THREE.Mesh(
|
|
74
|
+
new THREE.ConeGeometry(0.02, 0.18, 8),
|
|
75
|
+
PAL.chromeBrushed()
|
|
76
|
+
);
|
|
77
|
+
spike2.position.set(-0.14, 1.44, -0.06);
|
|
78
|
+
spike2.rotation.z = 0.6;
|
|
79
|
+
spike2.rotation.x = -0.2;
|
|
80
|
+
spike2.castShadow = true;
|
|
81
|
+
g.add(spike2);
|
|
82
|
+
|
|
83
|
+
return g;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'server_rack',
|
|
6
|
+
name: 'Server Rack',
|
|
7
|
+
category: 'tech',
|
|
8
|
+
icon: 'SR',
|
|
9
|
+
gridW: 1, gridD: 1, height: 1.5,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var W = 0.60;
|
|
14
|
+
var H = 1.50;
|
|
15
|
+
var D = 0.55;
|
|
16
|
+
var halfH = H / 2;
|
|
17
|
+
|
|
18
|
+
var cabinetMat = mat(0x0e1014, { roughness: 0.45, metalness: 0.30 });
|
|
19
|
+
var frameMat = PAL.chromeBrushed();
|
|
20
|
+
var ventMat = mat(0x1a1d22, { roughness: 0.60, metalness: 0.15 });
|
|
21
|
+
|
|
22
|
+
// Main cabinet body
|
|
23
|
+
var body = new THREE.Mesh(new THREE.BoxGeometry(W, H, D), cabinetMat);
|
|
24
|
+
body.position.y = halfH;
|
|
25
|
+
body.castShadow = true;
|
|
26
|
+
g.add(body);
|
|
27
|
+
|
|
28
|
+
// Front door frame
|
|
29
|
+
var doorFrame = new THREE.Mesh(new THREE.BoxGeometry(W + 0.01, H + 0.01, 0.015), frameMat);
|
|
30
|
+
doorFrame.position.set(0, halfH, D / 2 + 0.005);
|
|
31
|
+
g.add(doorFrame);
|
|
32
|
+
|
|
33
|
+
// Front perforated panel (dark inset)
|
|
34
|
+
var frontPanel = new THREE.Mesh(new THREE.BoxGeometry(W - 0.04, H - 0.04, 0.010), ventMat);
|
|
35
|
+
frontPanel.position.set(0, halfH, D / 2 + 0.006);
|
|
36
|
+
g.add(frontPanel);
|
|
37
|
+
|
|
38
|
+
// Ventilation grille rows (horizontal slits on front)
|
|
39
|
+
var grilleMat = mat(0x090b0e, { roughness: 0.50 });
|
|
40
|
+
var grillCount = 10;
|
|
41
|
+
for (var i = 0; i < grillCount; i++) {
|
|
42
|
+
var gy = 0.10 + i * (H - 0.18) / (grillCount - 1);
|
|
43
|
+
var grille = new THREE.Mesh(
|
|
44
|
+
new THREE.BoxGeometry(W - 0.08, 0.012, 0.015),
|
|
45
|
+
grilleMat
|
|
46
|
+
);
|
|
47
|
+
grille.position.set(0, gy, D / 2 + 0.012);
|
|
48
|
+
g.add(grille);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 1U server unit rails (thin horizontal dividers)
|
|
52
|
+
var railMat = mat(0x2a2e36, { roughness: 0.55, metalness: 0.25 });
|
|
53
|
+
var railCount = 6;
|
|
54
|
+
for (var r = 0; r < railCount; r++) {
|
|
55
|
+
var ry = 0.15 + r * (H - 0.25) / railCount;
|
|
56
|
+
var rail = new THREE.Mesh(new THREE.BoxGeometry(W - 0.02, 0.006, 0.008), railMat);
|
|
57
|
+
rail.position.set(0, ry, D / 2 + 0.003);
|
|
58
|
+
g.add(rail);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// LED indicator dots (4, stacked vertically on right side of front)
|
|
62
|
+
var ledColors = [0x00ff88, 0x00aaff, 0xffcc00, 0xff3300];
|
|
63
|
+
ledColors.forEach(function(col, idx) {
|
|
64
|
+
var led = new THREE.Mesh(
|
|
65
|
+
new THREE.SphereGeometry(0.009, 10, 10),
|
|
66
|
+
mat(col, { emissive: col, emissiveIntensity: 1.0 })
|
|
67
|
+
);
|
|
68
|
+
led.position.set(W / 2 - 0.045, 0.95 + idx * 0.10, D / 2 + 0.018);
|
|
69
|
+
g.add(led);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Side vent strips (left and right faces)
|
|
73
|
+
[-1, 1].forEach(function(side) {
|
|
74
|
+
var sideVent = new THREE.Mesh(
|
|
75
|
+
new THREE.BoxGeometry(0.008, H * 0.65, D - 0.08),
|
|
76
|
+
ventMat
|
|
77
|
+
);
|
|
78
|
+
sideVent.position.set(side * (W / 2 + 0.001), halfH, 0);
|
|
79
|
+
g.add(sideVent);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Top exhaust panel
|
|
83
|
+
var topVent = new THREE.Mesh(new THREE.BoxGeometry(W - 0.06, 0.010, D - 0.06), ventMat);
|
|
84
|
+
topVent.position.y = H + 0.001;
|
|
85
|
+
g.add(topVent);
|
|
86
|
+
|
|
87
|
+
// Caster feet (4 corners)
|
|
88
|
+
var casterMat = PAL.rubber();
|
|
89
|
+
[[-W * 0.38, -D * 0.38], [W * 0.38, -D * 0.38],
|
|
90
|
+
[-W * 0.38, D * 0.38], [W * 0.38, D * 0.38]].forEach(function(pos) {
|
|
91
|
+
var caster = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.025, 0.040, 12), casterMat);
|
|
92
|
+
caster.position.set(pos[0], 0.020, pos[1]);
|
|
93
|
+
g.add(caster);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return g;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'sink',
|
|
6
|
+
name: 'Kitchen Sink',
|
|
7
|
+
category: 'kitchen',
|
|
8
|
+
icon: 'Sk',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.9,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Cabinet base body
|
|
14
|
+
var cabinet = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(0.80, 0.82, 0.60),
|
|
16
|
+
mat(0x16181d, { roughness: 0.50 })
|
|
17
|
+
);
|
|
18
|
+
cabinet.position.y = 0.41;
|
|
19
|
+
cabinet.castShadow = true;
|
|
20
|
+
cabinet.receiveShadow = true;
|
|
21
|
+
g.add(cabinet);
|
|
22
|
+
|
|
23
|
+
// Cabinet door face
|
|
24
|
+
var door = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(0.74, 0.70, 0.012),
|
|
26
|
+
mat(0x1c1f26, { roughness: 0.45, metalness: 0.10 })
|
|
27
|
+
);
|
|
28
|
+
door.position.set(0, 0.42, 0.306);
|
|
29
|
+
g.add(door);
|
|
30
|
+
|
|
31
|
+
// Door handle (small chrome bar)
|
|
32
|
+
var doorHandle = new THREE.Mesh(
|
|
33
|
+
new THREE.BoxGeometry(0.18, 0.022, 0.022),
|
|
34
|
+
PAL.chrome()
|
|
35
|
+
);
|
|
36
|
+
doorHandle.position.set(0, 0.60, 0.320);
|
|
37
|
+
g.add(doorHandle);
|
|
38
|
+
|
|
39
|
+
// Countertop surface
|
|
40
|
+
var countertop = new THREE.Mesh(
|
|
41
|
+
new THREE.BoxGeometry(0.80, 0.04, 0.60),
|
|
42
|
+
mat(0x1e2128, { roughness: 0.25, metalness: 0.15 })
|
|
43
|
+
);
|
|
44
|
+
countertop.position.y = 0.86;
|
|
45
|
+
countertop.castShadow = true;
|
|
46
|
+
g.add(countertop);
|
|
47
|
+
|
|
48
|
+
// Basin recess (dark stainless interior)
|
|
49
|
+
var basin = new THREE.Mesh(
|
|
50
|
+
new THREE.BoxGeometry(0.52, 0.16, 0.36),
|
|
51
|
+
mat(0x888888, { roughness: 0.20, metalness: 0.75 })
|
|
52
|
+
);
|
|
53
|
+
basin.position.set(0, 0.80, -0.02);
|
|
54
|
+
basin.castShadow = true;
|
|
55
|
+
g.add(basin);
|
|
56
|
+
|
|
57
|
+
// Basin inner bottom
|
|
58
|
+
var basinBase = new THREE.Mesh(
|
|
59
|
+
new THREE.BoxGeometry(0.50, 0.012, 0.34),
|
|
60
|
+
mat(0x9a9a9a, { roughness: 0.18, metalness: 0.80 })
|
|
61
|
+
);
|
|
62
|
+
basinBase.position.set(0, 0.722, -0.02);
|
|
63
|
+
g.add(basinBase);
|
|
64
|
+
|
|
65
|
+
// Basin drain dot
|
|
66
|
+
var drain = new THREE.Mesh(
|
|
67
|
+
new THREE.CylinderGeometry(0.025, 0.025, 0.01, 12),
|
|
68
|
+
mat(0x444444, { roughness: 0.30, metalness: 0.60 })
|
|
69
|
+
);
|
|
70
|
+
drain.position.set(0.12, 0.716, 0.06);
|
|
71
|
+
g.add(drain);
|
|
72
|
+
|
|
73
|
+
// Chrome faucet base
|
|
74
|
+
var faucetBase = new THREE.Mesh(
|
|
75
|
+
new THREE.CylinderGeometry(0.030, 0.035, 0.04, 12),
|
|
76
|
+
PAL.chrome()
|
|
77
|
+
);
|
|
78
|
+
faucetBase.position.set(0, 0.892, -0.20);
|
|
79
|
+
g.add(faucetBase);
|
|
80
|
+
|
|
81
|
+
// Faucet neck (vertical rise)
|
|
82
|
+
var neck = new THREE.Mesh(
|
|
83
|
+
new THREE.CylinderGeometry(0.014, 0.014, 0.18, 10),
|
|
84
|
+
PAL.chrome()
|
|
85
|
+
);
|
|
86
|
+
neck.position.set(0, 0.98, -0.20);
|
|
87
|
+
g.add(neck);
|
|
88
|
+
|
|
89
|
+
// Faucet arc (horizontal spout)
|
|
90
|
+
var spout = new THREE.Mesh(
|
|
91
|
+
new THREE.CylinderGeometry(0.012, 0.012, 0.22, 10),
|
|
92
|
+
PAL.chrome()
|
|
93
|
+
);
|
|
94
|
+
spout.rotation.x = Math.PI / 2;
|
|
95
|
+
spout.position.set(0, 1.07, -0.09);
|
|
96
|
+
spout.castShadow = true;
|
|
97
|
+
g.add(spout);
|
|
98
|
+
|
|
99
|
+
// Faucet spout tip (pointing down)
|
|
100
|
+
var tip = new THREE.Mesh(
|
|
101
|
+
new THREE.CylinderGeometry(0.018, 0.012, 0.04, 8),
|
|
102
|
+
PAL.chrome()
|
|
103
|
+
);
|
|
104
|
+
tip.position.set(0, 1.055, 0.02);
|
|
105
|
+
g.add(tip);
|
|
106
|
+
|
|
107
|
+
return g;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'sofa',
|
|
6
|
+
name: 'Sofa',
|
|
7
|
+
category: 'furniture',
|
|
8
|
+
icon: 'Sf',
|
|
9
|
+
gridW: 3, gridD: 1, height: 0.9,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// Base platform (structural frame)
|
|
14
|
+
var base = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(3.0, 0.18, 0.9),
|
|
16
|
+
mat(0x17191f, { roughness: 0.6, metalness: 0.05 })
|
|
17
|
+
);
|
|
18
|
+
base.position.y = 0.09;
|
|
19
|
+
base.castShadow = true;
|
|
20
|
+
base.receiveShadow = true;
|
|
21
|
+
g.add(base);
|
|
22
|
+
|
|
23
|
+
// Seat cushion surface (3 visible cushions merged as one pad, split by seams)
|
|
24
|
+
var seatPad = new THREE.Mesh(
|
|
25
|
+
new THREE.BoxGeometry(2.88, 0.16, 0.76),
|
|
26
|
+
PAL.fabric()
|
|
27
|
+
);
|
|
28
|
+
seatPad.position.y = 0.26;
|
|
29
|
+
seatPad.castShadow = true;
|
|
30
|
+
seatPad.receiveShadow = true;
|
|
31
|
+
g.add(seatPad);
|
|
32
|
+
|
|
33
|
+
// 3 cushion seams (thin dark lines on top of seat pad)
|
|
34
|
+
var seamMat = mat(0x1a1c22, { roughness: 0.9 });
|
|
35
|
+
[-0.96, 0.96].forEach(function(x) {
|
|
36
|
+
var seam = new THREE.Mesh(new THREE.BoxGeometry(0.015, 0.162, 0.76), seamMat);
|
|
37
|
+
seam.position.set(x, 0.26, 0);
|
|
38
|
+
g.add(seam);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Backrest (full width)
|
|
42
|
+
var back = new THREE.Mesh(
|
|
43
|
+
new THREE.BoxGeometry(2.88, 0.56, 0.18),
|
|
44
|
+
PAL.fabric()
|
|
45
|
+
);
|
|
46
|
+
back.position.set(0, 0.62, -0.35);
|
|
47
|
+
back.castShadow = true;
|
|
48
|
+
g.add(back);
|
|
49
|
+
|
|
50
|
+
// Back top cap (slightly overhanging)
|
|
51
|
+
var backCap = new THREE.Mesh(
|
|
52
|
+
new THREE.BoxGeometry(3.0, 0.06, 0.20),
|
|
53
|
+
mat(0x1e2028, { roughness: 0.5 })
|
|
54
|
+
);
|
|
55
|
+
backCap.position.set(0, 0.92, -0.34);
|
|
56
|
+
backCap.castShadow = true;
|
|
57
|
+
g.add(backCap);
|
|
58
|
+
|
|
59
|
+
// Left arm
|
|
60
|
+
var armMat = PAL.fabric();
|
|
61
|
+
var leftArm = new THREE.Mesh(
|
|
62
|
+
new THREE.BoxGeometry(0.18, 0.46, 0.9),
|
|
63
|
+
armMat
|
|
64
|
+
);
|
|
65
|
+
leftArm.position.set(-1.41, 0.41, 0);
|
|
66
|
+
leftArm.castShadow = true;
|
|
67
|
+
g.add(leftArm);
|
|
68
|
+
|
|
69
|
+
// Right arm
|
|
70
|
+
var rightArm = leftArm.clone();
|
|
71
|
+
rightArm.position.x = 1.41;
|
|
72
|
+
g.add(rightArm);
|
|
73
|
+
|
|
74
|
+
// Arm top caps
|
|
75
|
+
var armCapMat = mat(0x1e2028, { roughness: 0.45 });
|
|
76
|
+
var leftArmCap = new THREE.Mesh(new THREE.BoxGeometry(0.20, 0.04, 0.92), armCapMat);
|
|
77
|
+
leftArmCap.position.set(-1.41, 0.65, 0);
|
|
78
|
+
g.add(leftArmCap);
|
|
79
|
+
var rightArmCap = leftArmCap.clone();
|
|
80
|
+
rightArmCap.position.x = 1.41;
|
|
81
|
+
g.add(rightArmCap);
|
|
82
|
+
|
|
83
|
+
// 3 seat cushions (individual, sitting on the pad)
|
|
84
|
+
var cushionMat = mat(0x252830, { roughness: 0.92 });
|
|
85
|
+
[-0.96, 0, 0.96].forEach(function(x) {
|
|
86
|
+
var cushion = new THREE.Mesh(
|
|
87
|
+
new THREE.BoxGeometry(0.88, 0.10, 0.72),
|
|
88
|
+
cushionMat
|
|
89
|
+
);
|
|
90
|
+
cushion.position.set(x, 0.37, 0.01);
|
|
91
|
+
cushion.castShadow = true;
|
|
92
|
+
g.add(cushion);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// 4 low chrome legs
|
|
96
|
+
var legMat = PAL.chrome();
|
|
97
|
+
var legGeo = new THREE.CylinderGeometry(0.025, 0.02, 0.09, 8);
|
|
98
|
+
[[-1.35, -0.35], [1.35, -0.35], [-1.35, 0.38], [1.35, 0.38]].forEach(function(p) {
|
|
99
|
+
var leg = new THREE.Mesh(legGeo, legMat);
|
|
100
|
+
leg.position.set(p[0], 0.045, p[1]);
|
|
101
|
+
g.add(leg);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return g;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'speaker',
|
|
6
|
+
name: 'Bluetooth Speaker',
|
|
7
|
+
category: 'tech',
|
|
8
|
+
icon: 'Sp',
|
|
9
|
+
gridW: 1, gridD: 1, height: 0.25,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var R = 0.075; // radius
|
|
14
|
+
var LEN = 0.15; // cylinder length (axis = Z)
|
|
15
|
+
|
|
16
|
+
// Main body — anodised dark cylinder
|
|
17
|
+
var body = new THREE.Mesh(
|
|
18
|
+
new THREE.CylinderGeometry(R, R, LEN, 32),
|
|
19
|
+
mat(0x1a1c20, { roughness: 0.38, metalness: 0.30 })
|
|
20
|
+
);
|
|
21
|
+
body.rotation.x = Math.PI / 2;
|
|
22
|
+
body.position.y = R;
|
|
23
|
+
body.castShadow = true;
|
|
24
|
+
g.add(body);
|
|
25
|
+
|
|
26
|
+
// Woven fabric grille band (slightly lighter, rough)
|
|
27
|
+
var grille = new THREE.Mesh(
|
|
28
|
+
new THREE.CylinderGeometry(R + 0.001, R + 0.001, LEN * 0.70, 32),
|
|
29
|
+
mat(0x2a2d32, { roughness: 0.92 })
|
|
30
|
+
);
|
|
31
|
+
grille.rotation.x = Math.PI / 2;
|
|
32
|
+
grille.position.y = R;
|
|
33
|
+
g.add(grille);
|
|
34
|
+
|
|
35
|
+
// Driver cone (front face)
|
|
36
|
+
var cone = new THREE.Mesh(
|
|
37
|
+
new THREE.CylinderGeometry(0.045, 0.035, 0.010, 32),
|
|
38
|
+
mat(0x0e0f10, { roughness: 0.50, metalness: 0.20 })
|
|
39
|
+
);
|
|
40
|
+
cone.rotation.x = Math.PI / 2;
|
|
41
|
+
cone.position.set(0, R, LEN / 2 + 0.004);
|
|
42
|
+
g.add(cone);
|
|
43
|
+
|
|
44
|
+
// Dust cap center of driver
|
|
45
|
+
var dustCap = new THREE.Mesh(
|
|
46
|
+
new THREE.SphereGeometry(0.018, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2),
|
|
47
|
+
mat(0x080808, { roughness: 0.60 })
|
|
48
|
+
);
|
|
49
|
+
dustCap.rotation.x = Math.PI / 2;
|
|
50
|
+
dustCap.position.set(0, R, LEN / 2 + 0.014);
|
|
51
|
+
g.add(dustCap);
|
|
52
|
+
|
|
53
|
+
// LED ring (around driver, glowing cyan)
|
|
54
|
+
var ledRing = new THREE.Mesh(
|
|
55
|
+
new THREE.TorusGeometry(0.048, 0.005, 8, 32),
|
|
56
|
+
mat(0x00e5ff, { emissive: 0x00c8e0, emissiveIntensity: 0.85 })
|
|
57
|
+
);
|
|
58
|
+
ledRing.rotation.x = Math.PI / 2;
|
|
59
|
+
ledRing.position.set(0, R, LEN / 2 + 0.006);
|
|
60
|
+
g.add(ledRing);
|
|
61
|
+
|
|
62
|
+
// End caps (chrome rings each side)
|
|
63
|
+
[-1, 1].forEach(function(side) {
|
|
64
|
+
var cap = new THREE.Mesh(
|
|
65
|
+
new THREE.CylinderGeometry(R, R, 0.012, 32),
|
|
66
|
+
PAL.chrome()
|
|
67
|
+
);
|
|
68
|
+
cap.rotation.x = Math.PI / 2;
|
|
69
|
+
cap.position.set(0, R, side * (LEN / 2 + 0.004));
|
|
70
|
+
g.add(cap);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Volume button strip on top of body
|
|
74
|
+
var volStrip = new THREE.Mesh(
|
|
75
|
+
new THREE.BoxGeometry(0.055, 0.009, 0.014),
|
|
76
|
+
mat(0x888888, { roughness: 0.25, metalness: 0.70 })
|
|
77
|
+
);
|
|
78
|
+
volStrip.position.set(0, R * 2 - 0.005, 0.02);
|
|
79
|
+
g.add(volStrip);
|
|
80
|
+
|
|
81
|
+
return g;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'spotlight',
|
|
6
|
+
name: 'Track Spotlight',
|
|
7
|
+
category: 'lighting',
|
|
8
|
+
icon: 'SL',
|
|
9
|
+
gridW: 1, gridD: 1, height: 2.5,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var mountY = 2.50; // ceiling mount height
|
|
14
|
+
var headY = mountY - 0.08;
|
|
15
|
+
var chromeMat = PAL.chrome();
|
|
16
|
+
var bodyMat = mat(0x1c1e24, { roughness: 0.35, metalness: 0.55 });
|
|
17
|
+
|
|
18
|
+
// Track rail segment (short, ceiling-mounted)
|
|
19
|
+
var track = new THREE.Mesh(
|
|
20
|
+
new THREE.BoxGeometry(0.35, 0.028, 0.038),
|
|
21
|
+
mat(0x888888, { roughness: 0.28, metalness: 0.70 })
|
|
22
|
+
);
|
|
23
|
+
track.position.y = mountY;
|
|
24
|
+
g.add(track);
|
|
25
|
+
|
|
26
|
+
// Mount clip connecting housing to track
|
|
27
|
+
var clip = new THREE.Mesh(
|
|
28
|
+
new THREE.BoxGeometry(0.028, 0.050, 0.028),
|
|
29
|
+
chromeMat
|
|
30
|
+
);
|
|
31
|
+
clip.position.y = mountY - 0.025;
|
|
32
|
+
g.add(clip);
|
|
33
|
+
|
|
34
|
+
// Main spotlight housing (tapered cylinder)
|
|
35
|
+
var housing = new THREE.Mesh(
|
|
36
|
+
new THREE.CylinderGeometry(0.040, 0.055, 0.110, 20),
|
|
37
|
+
bodyMat
|
|
38
|
+
);
|
|
39
|
+
housing.position.y = headY - 0.055;
|
|
40
|
+
housing.castShadow = true;
|
|
41
|
+
g.add(housing);
|
|
42
|
+
|
|
43
|
+
// Chrome housing ring (top)
|
|
44
|
+
var topRing = new THREE.Mesh(
|
|
45
|
+
new THREE.TorusGeometry(0.042, 0.005, 8, 20),
|
|
46
|
+
chromeMat
|
|
47
|
+
);
|
|
48
|
+
topRing.position.y = headY;
|
|
49
|
+
g.add(topRing);
|
|
50
|
+
|
|
51
|
+
// Inner reflector bowl
|
|
52
|
+
var reflector = new THREE.Mesh(
|
|
53
|
+
new THREE.CylinderGeometry(0.030, 0.048, 0.070, 20, 1, true),
|
|
54
|
+
mat(0xc8c8c8, { roughness: 0.05, metalness: 0.95, side: THREE.BackSide })
|
|
55
|
+
);
|
|
56
|
+
reflector.position.y = headY - 0.060;
|
|
57
|
+
g.add(reflector);
|
|
58
|
+
|
|
59
|
+
// Lens glass (front of housing)
|
|
60
|
+
var lens = new THREE.Mesh(
|
|
61
|
+
new THREE.CircleGeometry(0.038, 24),
|
|
62
|
+
mat(0xdde8ff, { transparent: true, opacity: 0.35, roughness: 0.02, emissive: 0xffffff, emissiveIntensity: 0.25 })
|
|
63
|
+
);
|
|
64
|
+
lens.position.y = headY - 0.112;
|
|
65
|
+
lens.rotation.x = Math.PI / 2;
|
|
66
|
+
g.add(lens);
|
|
67
|
+
|
|
68
|
+
// Focus ring (chrome band around lens end)
|
|
69
|
+
var focusRing = new THREE.Mesh(
|
|
70
|
+
new THREE.TorusGeometry(0.040, 0.006, 8, 20),
|
|
71
|
+
chromeMat
|
|
72
|
+
);
|
|
73
|
+
focusRing.position.y = headY - 0.113;
|
|
74
|
+
g.add(focusRing);
|
|
75
|
+
|
|
76
|
+
// Focused point light (aimed downward)
|
|
77
|
+
var light = new THREE.PointLight(0xffffff, 0.4, 6);
|
|
78
|
+
light.position.y = headY - 0.12;
|
|
79
|
+
g.add(light);
|
|
80
|
+
|
|
81
|
+
return g;
|
|
82
|
+
}
|
|
83
|
+
};
|