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.
Files changed (166) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/README.md +158 -592
  3. package/SECURITY.md +3 -3
  4. package/USAGE.md +151 -0
  5. package/agent-contracts.js +447 -0
  6. package/api-agents.js +760 -0
  7. package/autonomy/decision-v2.js +380 -0
  8. package/autonomy/watchdog-policy.js +572 -0
  9. package/cli.js +454 -298
  10. package/conversation-templates/autonomous-feature.json +83 -22
  11. package/conversation-templates/code-review.json +69 -21
  12. package/conversation-templates/debug-squad.json +69 -21
  13. package/conversation-templates/feature-build.json +69 -21
  14. package/conversation-templates/research-write.json +69 -21
  15. package/dashboard.html +3148 -174
  16. package/dashboard.js +823 -786
  17. package/data-dir.js +58 -0
  18. package/docs/architecture/branch-semantics.md +157 -0
  19. package/docs/architecture/canonical-event-schema.md +88 -0
  20. package/docs/architecture/markdown-workspace.md +183 -0
  21. package/docs/architecture/runtime-contract.md +459 -0
  22. package/docs/architecture/runtime-migration-hardening.md +64 -0
  23. package/events/hooks.js +154 -0
  24. package/events/log.js +457 -0
  25. package/events/replay.js +33 -0
  26. package/events/schema.js +432 -0
  27. package/managed-team-integration.js +261 -0
  28. package/office/agents.js +704 -597
  29. package/office/animation.js +1 -1
  30. package/office/assets/arcade-cabinet.js +141 -0
  31. package/office/assets/archway.js +77 -0
  32. package/office/assets/bar-counter.js +91 -0
  33. package/office/assets/bar-stool.js +71 -0
  34. package/office/assets/beanbag.js +64 -0
  35. package/office/assets/bench.js +99 -0
  36. package/office/assets/bollard.js +87 -0
  37. package/office/assets/cactus.js +100 -0
  38. package/office/assets/carpet-tile.js +46 -0
  39. package/office/assets/chair.js +123 -0
  40. package/office/assets/chandelier.js +107 -0
  41. package/office/assets/coffee-machine.js +95 -0
  42. package/office/assets/coffee-table.js +81 -0
  43. package/office/assets/column.js +95 -0
  44. package/office/assets/desk-lamp.js +102 -0
  45. package/office/assets/desk.js +76 -0
  46. package/office/assets/dining-table.js +105 -0
  47. package/office/assets/door.js +70 -0
  48. package/office/assets/dual-monitor.js +72 -0
  49. package/office/assets/fence.js +76 -0
  50. package/office/assets/filing-cabinet.js +111 -0
  51. package/office/assets/floor-lamp.js +69 -0
  52. package/office/assets/floor-tile.js +54 -0
  53. package/office/assets/flower-pot.js +76 -0
  54. package/office/assets/foosball.js +95 -0
  55. package/office/assets/fridge.js +99 -0
  56. package/office/assets/gaming-chair.js +154 -0
  57. package/office/assets/gaming-desk.js +105 -0
  58. package/office/assets/glass-door.js +72 -0
  59. package/office/assets/glass-wall.js +64 -0
  60. package/office/assets/half-wall.js +49 -0
  61. package/office/assets/hanging-plant.js +112 -0
  62. package/office/assets/index.js +151 -0
  63. package/office/assets/indoor-tree.js +90 -0
  64. package/office/assets/l-sofa.js +153 -0
  65. package/office/assets/marble-floor.js +64 -0
  66. package/office/assets/materials.js +40 -0
  67. package/office/assets/meeting-table.js +88 -0
  68. package/office/assets/microwave.js +94 -0
  69. package/office/assets/monitor.js +67 -0
  70. package/office/assets/neon-strip.js +73 -0
  71. package/office/assets/painting.js +84 -0
  72. package/office/assets/palm-tree.js +108 -0
  73. package/office/assets/pc-tower.js +91 -0
  74. package/office/assets/pendant-light.js +67 -0
  75. package/office/assets/ping-pong.js +114 -0
  76. package/office/assets/plant.js +72 -0
  77. package/office/assets/planter-box.js +95 -0
  78. package/office/assets/pool-table.js +94 -0
  79. package/office/assets/printer.js +113 -0
  80. package/office/assets/reception-desk.js +133 -0
  81. package/office/assets/rug.js +78 -0
  82. package/office/assets/sculpture.js +85 -0
  83. package/office/assets/server-rack.js +98 -0
  84. package/office/assets/sink.js +109 -0
  85. package/office/assets/sofa.js +106 -0
  86. package/office/assets/speaker.js +83 -0
  87. package/office/assets/spotlight.js +83 -0
  88. package/office/assets/street-lamp.js +97 -0
  89. package/office/assets/trash-can.js +83 -0
  90. package/office/assets/treadmill.js +126 -0
  91. package/office/assets/trophy.js +89 -0
  92. package/office/assets/tv-screen.js +79 -0
  93. package/office/assets/vase.js +84 -0
  94. package/office/assets/wall-clock.js +84 -0
  95. package/office/assets/wall.js +53 -0
  96. package/office/assets/water-cooler.js +146 -0
  97. package/office/assets/whiteboard.js +115 -0
  98. package/office/assets.js +3 -431
  99. package/office/builder.js +791 -355
  100. package/office/campus-env.js +1012 -1119
  101. package/office/environment.js +2 -0
  102. package/office/gallery.js +997 -0
  103. package/office/index.js +165 -61
  104. package/office/navigation.js +173 -152
  105. package/office/player.js +178 -68
  106. package/office/robot-character.js +272 -0
  107. package/office/spectator-camera.js +33 -10
  108. package/office/state.js +2 -0
  109. package/office/world-save.js +35 -4
  110. package/package.json +57 -3
  111. package/providers/comfyui.js +383 -0
  112. package/providers/dalle.js +79 -0
  113. package/providers/gemini.js +181 -0
  114. package/providers/ollama.js +184 -0
  115. package/providers/replicate.js +115 -0
  116. package/providers/zai.js +183 -0
  117. package/runtime-descriptor.js +270 -0
  118. package/scripts/check-agent-contract-advisory.js +132 -0
  119. package/scripts/check-api-agent-parity.js +277 -0
  120. package/scripts/check-autonomy-v2-decision.js +207 -0
  121. package/scripts/check-autonomy-v2-execution.js +588 -0
  122. package/scripts/check-autonomy-v2-watchdog.js +224 -0
  123. package/scripts/check-branch-fork-snapshot.js +337 -0
  124. package/scripts/check-branch-isolation.js +787 -0
  125. package/scripts/check-branch-semantics.js +139 -0
  126. package/scripts/check-dashboard-control-plane.js +1304 -0
  127. package/scripts/check-docs-onboarding.js +490 -0
  128. package/scripts/check-event-schema.js +276 -0
  129. package/scripts/check-evidence-completion.js +239 -0
  130. package/scripts/check-invariants.js +992 -0
  131. package/scripts/check-lifecycle-hooks.js +525 -0
  132. package/scripts/check-managed-team-integration.js +166 -0
  133. package/scripts/check-markdown-workspace-export.js +548 -0
  134. package/scripts/check-markdown-workspace-safety.js +347 -0
  135. package/scripts/check-markdown-workspace.js +136 -0
  136. package/scripts/check-message-replay.js +429 -0
  137. package/scripts/check-migration-hardening.js +300 -0
  138. package/scripts/check-performance-indexing.js +272 -0
  139. package/scripts/check-provider-capabilities.js +316 -0
  140. package/scripts/check-runtime-contract.js +109 -0
  141. package/scripts/check-session-aware-context.js +172 -0
  142. package/scripts/check-session-lifecycle.js +210 -0
  143. package/scripts/export-markdown-workspace.js +84 -0
  144. package/scripts/fixtures/message-replay/clean.jsonl +2 -0
  145. package/scripts/fixtures/message-replay/corrupt-correction-payload.jsonl +1 -0
  146. package/scripts/fixtures/message-replay/corrupt-jsonl.jsonl +1 -0
  147. package/scripts/fixtures/message-replay/corrupt-payload.jsonl +1 -0
  148. package/scripts/fixtures/message-replay/out-of-order.jsonl +2 -0
  149. package/scripts/migrate-legacy-to-canonical.js +201 -0
  150. package/scripts/run-verification-suite.js +242 -0
  151. package/scripts/sync-packaged-docs.js +69 -0
  152. package/server.js +9546 -7214
  153. package/state/agents.js +161 -0
  154. package/state/canonical.js +3068 -0
  155. package/state/dashboard-queries.js +441 -0
  156. package/state/evidence.js +56 -0
  157. package/state/io.js +69 -0
  158. package/state/markdown-workspace.js +951 -0
  159. package/state/messages.js +669 -0
  160. package/state/sessions.js +683 -0
  161. package/state/tasks-workflows.js +92 -0
  162. package/templates/debate.json +2 -2
  163. package/templates/managed.json +4 -4
  164. package/templates/pair.json +2 -2
  165. package/templates/review.json +2 -2
  166. package/templates/team.json +3 -3
@@ -0,0 +1,100 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'cactus',
6
+ name: 'Cactus',
7
+ category: 'nature',
8
+ icon: 'Ca',
9
+ gridW: 1, gridD: 1, height: 0.5,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Terracotta pot — warm dark tone
14
+ var pot = new THREE.Mesh(
15
+ new THREE.CylinderGeometry(0.095, 0.072, 0.165, 16),
16
+ mat(0x3d1f10, { roughness: 0.85 })
17
+ );
18
+ pot.position.y = 0.083;
19
+ pot.castShadow = true;
20
+ pot.receiveShadow = true;
21
+ g.add(pot);
22
+
23
+ // Pot rim detail
24
+ var rim = new THREE.Mesh(
25
+ new THREE.TorusGeometry(0.098, 0.013, 8, 20),
26
+ mat(0x2a1208, { roughness: 0.80 })
27
+ );
28
+ rim.rotation.x = Math.PI / 2;
29
+ rim.position.y = 0.163;
30
+ g.add(rim);
31
+
32
+ // Gravel / soil surface
33
+ var soil = new THREE.Mesh(
34
+ new THREE.CylinderGeometry(0.083, 0.083, 0.014, 16),
35
+ mat(0x1e1c18, { roughness: 0.99 })
36
+ );
37
+ soil.position.y = 0.175;
38
+ g.add(soil);
39
+
40
+ // Cactus main body — fat cylinder, green
41
+ var cactusMat = mat(0x2a6030, { roughness: 0.70 });
42
+ var body = new THREE.Mesh(
43
+ new THREE.CylinderGeometry(0.055, 0.065, 0.30, 10),
44
+ cactusMat
45
+ );
46
+ body.position.y = 0.33;
47
+ body.castShadow = true;
48
+ g.add(body);
49
+
50
+ // Cactus rib lines (darker vertical strips)
51
+ var ribMat = mat(0x1e4a22, { roughness: 0.75 });
52
+ for (var i = 0; i < 5; i++) {
53
+ var ribAngle = (i / 5) * Math.PI * 2;
54
+ var rib = new THREE.Mesh(
55
+ new THREE.BoxGeometry(0.012, 0.28, 0.014),
56
+ ribMat
57
+ );
58
+ rib.position.set(
59
+ Math.sin(ribAngle) * 0.048,
60
+ 0.33,
61
+ Math.cos(ribAngle) * 0.048
62
+ );
63
+ rib.rotation.y = -ribAngle;
64
+ g.add(rib);
65
+ }
66
+
67
+ // Spines — small white/cream cones
68
+ var spineMat = mat(0xe8e0cc, { roughness: 0.60 });
69
+ var spineRows = [{ y: 0.22, r: 0.062 }, { y: 0.32, r: 0.060 }, { y: 0.42, r: 0.056 }];
70
+ spineRows.forEach(function(row) {
71
+ for (var s = 0; s < 8; s++) {
72
+ var sa = (s / 8) * Math.PI * 2;
73
+ var spine = new THREE.Mesh(
74
+ new THREE.ConeGeometry(0.004, 0.025, 4),
75
+ spineMat
76
+ );
77
+ spine.position.set(
78
+ Math.sin(sa) * row.r,
79
+ row.y,
80
+ Math.cos(sa) * row.r
81
+ );
82
+ spine.rotation.z = Math.PI / 2 - 0.2;
83
+ spine.rotation.y = -sa;
84
+ g.add(spine);
85
+ }
86
+ });
87
+
88
+ // Top of cactus — slightly rounded cap
89
+ var cap = new THREE.Mesh(
90
+ new THREE.SphereGeometry(0.055, 10, 8),
91
+ cactusMat
92
+ );
93
+ cap.scale.y = 0.55;
94
+ cap.position.y = 0.480;
95
+ cap.castShadow = true;
96
+ g.add(cap);
97
+
98
+ return g;
99
+ }
100
+ };
@@ -0,0 +1,46 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'carpet-tile',
6
+ name: 'Carpet Tile',
7
+ category: 'structural',
8
+ icon: 'CT',
9
+ gridW: 2, gridD: 2, height: 0.03,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Carpet base — charcoal fabric
14
+ var carpet = new THREE.Mesh(
15
+ new THREE.BoxGeometry(1.98, 0.03, 1.98),
16
+ mat(0x2e3040, { roughness: 0.98 })
17
+ );
18
+ carpet.receiveShadow = true;
19
+ g.add(carpet);
20
+
21
+ // Subtle pattern — directional nap lines (darker strips)
22
+ var napMat = mat(0x272938, { roughness: 1.0 });
23
+ var i;
24
+ for (i = -3; i <= 3; i++) {
25
+ var nap = new THREE.Mesh(
26
+ new THREE.BoxGeometry(1.96, 0.031, 0.04),
27
+ napMat
28
+ );
29
+ nap.position.z = i * 0.28;
30
+ g.add(nap);
31
+ }
32
+
33
+ // Thin border edge reveal (slightly lighter)
34
+ var edgeMat = mat(0x3a3d50, { roughness: 0.95 });
35
+ var edgeN = new THREE.Mesh(new THREE.BoxGeometry(2, 0.032, 0.04), edgeMat);
36
+ edgeN.position.z = -0.98;
37
+ g.add(edgeN);
38
+ var edgeS = edgeN.clone(); edgeS.position.z = 0.98; g.add(edgeS);
39
+ var edgeW = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.032, 2), edgeMat);
40
+ edgeW.position.x = -0.98;
41
+ g.add(edgeW);
42
+ var edgeE = edgeW.clone(); edgeE.position.x = 0.98; g.add(edgeE);
43
+
44
+ return g;
45
+ }
46
+ };
@@ -0,0 +1,123 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'chair',
6
+ name: 'Office Chair',
7
+ category: 'furniture',
8
+ icon: 'Ch',
9
+ gridW: 1, gridD: 1, height: 1.1,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // 5-star base — chrome disc
14
+ var baseDisc = new THREE.Mesh(
15
+ new THREE.CylinderGeometry(0.28, 0.28, 0.025, 5),
16
+ PAL.chrome()
17
+ );
18
+ baseDisc.position.y = 0.02;
19
+ baseDisc.castShadow = true;
20
+ g.add(baseDisc);
21
+
22
+ // 5 arms radiating outward
23
+ var armMat = PAL.chrome();
24
+ for (var i = 0; i < 5; i++) {
25
+ var arm = new THREE.Mesh(
26
+ new THREE.BoxGeometry(0.26, 0.025, 0.045),
27
+ armMat
28
+ );
29
+ arm.position.y = 0.02;
30
+ arm.rotation.y = (i / 5) * Math.PI * 2;
31
+ arm.castShadow = true;
32
+ g.add(arm);
33
+
34
+ // Wheel at each arm tip
35
+ var wheel = new THREE.Mesh(
36
+ new THREE.CylinderGeometry(0.03, 0.03, 0.04, 10),
37
+ mat(0x1a1a1a, { roughness: 0.9 })
38
+ );
39
+ var angle = (i / 5) * Math.PI * 2;
40
+ wheel.position.set(Math.sin(angle) * 0.26, 0.018, Math.cos(angle) * 0.26);
41
+ wheel.rotation.z = Math.PI / 2;
42
+ g.add(wheel);
43
+ }
44
+
45
+ // Central post (pneumatic cylinder)
46
+ var post = new THREE.Mesh(
47
+ new THREE.CylinderGeometry(0.04, 0.05, 0.46, 12),
48
+ PAL.chromeBrushed()
49
+ );
50
+ post.position.y = 0.26;
51
+ post.castShadow = true;
52
+ g.add(post);
53
+
54
+ // Seat cushion
55
+ var seat = new THREE.Mesh(
56
+ new THREE.BoxGeometry(0.5, 0.08, 0.48),
57
+ PAL.leatherBlack()
58
+ );
59
+ seat.position.y = 0.52;
60
+ seat.castShadow = true;
61
+ seat.receiveShadow = true;
62
+ g.add(seat);
63
+
64
+ // Seat shell (underside)
65
+ var seatShell = new THREE.Mesh(
66
+ new THREE.BoxGeometry(0.52, 0.03, 0.50),
67
+ mat(0x1e2128, { roughness: 0.6 })
68
+ );
69
+ seatShell.position.y = 0.475;
70
+ g.add(seatShell);
71
+
72
+ // Back lower cushion
73
+ var backLow = new THREE.Mesh(
74
+ new THREE.BoxGeometry(0.48, 0.34, 0.07),
75
+ PAL.leatherBlack()
76
+ );
77
+ backLow.position.set(0, 0.77, -0.21);
78
+ backLow.castShadow = true;
79
+ g.add(backLow);
80
+
81
+ // Back upper cushion
82
+ var backUp = new THREE.Mesh(
83
+ new THREE.BoxGeometry(0.48, 0.28, 0.07),
84
+ PAL.leatherBlack()
85
+ );
86
+ backUp.position.set(0, 1.03, -0.19);
87
+ backUp.castShadow = true;
88
+ g.add(backUp);
89
+
90
+ // Back frame
91
+ var backFrame = new THREE.Mesh(
92
+ new THREE.BoxGeometry(0.52, 0.66, 0.04),
93
+ mat(0x17191f, { roughness: 0.5, metalness: 0.1 })
94
+ );
95
+ backFrame.position.set(0, 0.89, -0.25);
96
+ g.add(backFrame);
97
+
98
+ // Left armrest
99
+ var armrestMat = mat(0x1a1a1a, { roughness: 0.75 });
100
+ var leftArm = new THREE.Mesh(
101
+ new THREE.BoxGeometry(0.07, 0.04, 0.22),
102
+ armrestMat
103
+ );
104
+ leftArm.position.set(-0.26, 0.72, -0.05);
105
+ leftArm.castShadow = true;
106
+ g.add(leftArm);
107
+
108
+ var rightArm = leftArm.clone();
109
+ rightArm.position.x = 0.26;
110
+ g.add(rightArm);
111
+
112
+ // Armrest posts
113
+ var postMat = PAL.chromeBrushed();
114
+ var leftPost = new THREE.Mesh(new THREE.BoxGeometry(0.025, 0.2, 0.025), postMat);
115
+ leftPost.position.set(-0.26, 0.62, -0.05);
116
+ g.add(leftPost);
117
+ var rightPost = leftPost.clone();
118
+ rightPost.position.x = 0.26;
119
+ g.add(rightPost);
120
+
121
+ return g;
122
+ }
123
+ };
@@ -0,0 +1,107 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'chandelier',
6
+ name: 'Chandelier',
7
+ category: 'lighting',
8
+ icon: 'CH',
9
+ gridW: 1, gridD: 1, height: 3.0,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ var ringY = 2.50;
14
+ var ringR = 0.40;
15
+ var armCount = 6;
16
+ var chromeMat = PAL.chrome();
17
+
18
+ // Ceiling canopy (mount disk)
19
+ var canopy = new THREE.Mesh(new THREE.CylinderGeometry(0.075, 0.075, 0.022, 24), chromeMat);
20
+ canopy.position.y = 3.0;
21
+ g.add(canopy);
22
+
23
+ // Main drop rod from ceiling to ring
24
+ var rod = new THREE.Mesh(
25
+ new THREE.CylinderGeometry(0.010, 0.010, 3.0 - ringY - 0.011, 12),
26
+ chromeMat
27
+ );
28
+ rod.position.y = ringY + (3.0 - ringY - 0.011) / 2 + 0.011;
29
+ g.add(rod);
30
+
31
+ // Chrome ring
32
+ var ring = new THREE.Mesh(
33
+ new THREE.TorusGeometry(ringR, 0.012, 10, 64),
34
+ chromeMat
35
+ );
36
+ ring.position.y = ringY;
37
+ g.add(ring);
38
+
39
+ // Ring center hub
40
+ var hub = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.025, 0.040, 16), chromeMat);
41
+ hub.position.y = ringY;
42
+ g.add(hub);
43
+
44
+ // 6 pendant arms radiating from ring
45
+ for (var i = 0; i < armCount; i++) {
46
+ var angle = (i / armCount) * Math.PI * 2;
47
+ var ax = Math.sin(angle) * ringR;
48
+ var az = Math.cos(angle) * ringR;
49
+
50
+ // Arm spoke (from hub to ring)
51
+ var spokeLen = ringR - 0.026;
52
+ var spoke = new THREE.Mesh(
53
+ new THREE.CylinderGeometry(0.006, 0.006, spokeLen, 8),
54
+ chromeMat
55
+ );
56
+ spoke.position.set(Math.sin(angle) * (ringR / 2), ringY, Math.cos(angle) * (ringR / 2));
57
+ spoke.rotation.z = Math.PI / 2;
58
+ spoke.rotation.y = angle;
59
+ g.add(spoke);
60
+
61
+ // Pendant drop wire
62
+ var dropLen = 0.18;
63
+ var wire = new THREE.Mesh(
64
+ new THREE.CylinderGeometry(0.004, 0.004, dropLen, 8),
65
+ mat(0x999999, { roughness: 0.30, metalness: 0.70 })
66
+ );
67
+ wire.position.set(ax, ringY - dropLen / 2, az);
68
+ g.add(wire);
69
+
70
+ // Globe bulb shade
71
+ var globe = new THREE.Mesh(
72
+ new THREE.SphereGeometry(0.040, 18, 12),
73
+ mat(0xfff5e0, { transparent: true, opacity: 0.55, roughness: 0.05, side: THREE.DoubleSide })
74
+ );
75
+ globe.position.set(ax, ringY - dropLen - 0.040, az);
76
+ g.add(globe);
77
+
78
+ // Warm filament glow inside globe
79
+ var filament = new THREE.Mesh(
80
+ new THREE.SphereGeometry(0.016, 10, 8),
81
+ mat(0xffe8a0, { emissive: 0xffdd80, emissiveIntensity: 1.5, transparent: true, opacity: 0.95 })
82
+ );
83
+ filament.position.set(ax, ringY - dropLen - 0.040, az);
84
+ g.add(filament);
85
+
86
+ // Globe chrome neck fitting
87
+ var globeNeck = new THREE.Mesh(
88
+ new THREE.CylinderGeometry(0.010, 0.010, 0.015, 10),
89
+ chromeMat
90
+ );
91
+ globeNeck.position.set(ax, ringY - dropLen - 0.004, az);
92
+ g.add(globeNeck);
93
+
94
+ // Per-arm warm point light (low intensity, many = soft fill)
95
+ var armLight = new THREE.PointLight(0xffe8a0, 0.09, 3.5);
96
+ armLight.position.set(ax, ringY - dropLen - 0.040, az);
97
+ g.add(armLight);
98
+ }
99
+
100
+ // Centre ambient fill light at ring level
101
+ var fillLight = new THREE.PointLight(0xfff0cc, 0.18, 5);
102
+ fillLight.position.y = ringY;
103
+ g.add(fillLight);
104
+
105
+ return g;
106
+ }
107
+ };
@@ -0,0 +1,95 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'coffee_machine',
6
+ name: 'Coffee Machine',
7
+ category: 'kitchen',
8
+ icon: 'CM',
9
+ gridW: 1, gridD: 1, height: 0.5,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Main body — dark boxy form
14
+ var body = new THREE.Mesh(
15
+ new THREE.BoxGeometry(0.40, 0.42, 0.36),
16
+ mat(0x111318, { roughness: 0.40, metalness: 0.20 })
17
+ );
18
+ body.position.y = 0.21;
19
+ body.castShadow = true;
20
+ body.receiveShadow = true;
21
+ g.add(body);
22
+
23
+ // Chrome top cap
24
+ var topCap = new THREE.Mesh(
25
+ new THREE.BoxGeometry(0.40, 0.035, 0.36),
26
+ PAL.chrome()
27
+ );
28
+ topCap.position.y = 0.435;
29
+ topCap.castShadow = true;
30
+ g.add(topCap);
31
+
32
+ // Front face plate (slightly recessed dark panel)
33
+ var faceplate = new THREE.Mesh(
34
+ new THREE.BoxGeometry(0.32, 0.30, 0.01),
35
+ mat(0x1a1c22, { roughness: 0.55, metalness: 0.10 })
36
+ );
37
+ faceplate.position.set(0, 0.24, 0.185);
38
+ g.add(faceplate);
39
+
40
+ // Small display screen (emissive blue)
41
+ var screen = new THREE.Mesh(
42
+ new THREE.BoxGeometry(0.14, 0.07, 0.008),
43
+ mat(0x002244, { emissive: 0x004488, emissiveIntensity: 0.9, roughness: 0.1 })
44
+ );
45
+ screen.position.set(0.06, 0.32, 0.19);
46
+ g.add(screen);
47
+
48
+ // Group of 3 control buttons
49
+ var btnMat = PAL.chrome();
50
+ var btnGeo = new THREE.CylinderGeometry(0.018, 0.018, 0.015, 10);
51
+ [-0.07, 0, 0.07].forEach(function(x) {
52
+ var btn = new THREE.Mesh(btnGeo, btnMat);
53
+ btn.rotation.x = Math.PI / 2;
54
+ btn.position.set(x, 0.20, 0.192);
55
+ g.add(btn);
56
+ });
57
+
58
+ // Steam nozzle (chrome tube angled out)
59
+ var nozzle = new THREE.Mesh(
60
+ new THREE.CylinderGeometry(0.012, 0.014, 0.14, 8),
61
+ PAL.chrome()
62
+ );
63
+ nozzle.rotation.z = -0.35;
64
+ nozzle.position.set(-0.16, 0.32, 0.10);
65
+ nozzle.castShadow = true;
66
+ g.add(nozzle);
67
+
68
+ // Nozzle tip cap
69
+ var nozzleTip = new THREE.Mesh(
70
+ new THREE.CylinderGeometry(0.018, 0.012, 0.022, 8),
71
+ PAL.chromeBrushed()
72
+ );
73
+ nozzleTip.position.set(-0.205, 0.36, 0.10);
74
+ nozzleTip.rotation.z = -0.35;
75
+ g.add(nozzleTip);
76
+
77
+ // Drip tray (chrome grill plate)
78
+ var tray = new THREE.Mesh(
79
+ new THREE.BoxGeometry(0.28, 0.014, 0.18),
80
+ PAL.chromeBrushed()
81
+ );
82
+ tray.position.set(0, 0.048, 0.04);
83
+ g.add(tray);
84
+
85
+ // Water reservoir at back (dark translucent)
86
+ var reservoir = new THREE.Mesh(
87
+ new THREE.BoxGeometry(0.12, 0.28, 0.10),
88
+ mat(0x1a2030, { transparent: true, opacity: 0.80, roughness: 0.25 })
89
+ );
90
+ reservoir.position.set(0.13, 0.28, -0.14);
91
+ g.add(reservoir);
92
+
93
+ return g;
94
+ }
95
+ };
@@ -0,0 +1,81 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'coffee-table',
6
+ name: 'Coffee Table',
7
+ category: 'furniture',
8
+ icon: 'CT',
9
+ gridW: 1, gridD: 1, height: 0.45,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Glass top
14
+ var glassTop = new THREE.Mesh(
15
+ new THREE.BoxGeometry(1.0, 0.012, 0.5),
16
+ mat(0xaaccee, { transparent: true, opacity: 0.35, roughness: 0.04, metalness: 0.08 })
17
+ );
18
+ glassTop.position.y = 0.45;
19
+ glassTop.receiveShadow = true;
20
+ g.add(glassTop);
21
+
22
+ // Chrome frame around glass top
23
+ var frameMat = PAL.chrome();
24
+ var frontBar = new THREE.Mesh(new THREE.BoxGeometry(1.0, 0.018, 0.018), frameMat);
25
+ frontBar.position.set(0, 0.444, 0.241);
26
+ frontBar.castShadow = true;
27
+ g.add(frontBar);
28
+
29
+ var backBar = frontBar.clone();
30
+ backBar.position.z = -0.241;
31
+ g.add(backBar);
32
+
33
+ var leftBar = new THREE.Mesh(new THREE.BoxGeometry(0.018, 0.018, 0.5), frameMat);
34
+ leftBar.position.set(-0.491, 0.444, 0);
35
+ leftBar.castShadow = true;
36
+ g.add(leftBar);
37
+
38
+ var rightBar = leftBar.clone();
39
+ rightBar.position.x = 0.491;
40
+ g.add(rightBar);
41
+
42
+ // Lower shelf (smoked glass)
43
+ var shelf = new THREE.Mesh(
44
+ new THREE.BoxGeometry(0.88, 0.010, 0.40),
45
+ mat(0x445566, { transparent: true, opacity: 0.55, roughness: 0.12 })
46
+ );
47
+ shelf.position.y = 0.18;
48
+ shelf.receiveShadow = true;
49
+ g.add(shelf);
50
+
51
+ // 4 chrome legs — slim round
52
+ var legMat = PAL.chrome();
53
+ var legGeo = new THREE.CylinderGeometry(0.018, 0.014, 0.44, 10);
54
+ [[-0.44, 0.22], [0.44, 0.22], [-0.44, -0.22], [0.44, -0.22]].forEach(function(p) {
55
+ var leg = new THREE.Mesh(legGeo, legMat);
56
+ leg.position.set(p[0], 0.22, p[1]);
57
+ leg.castShadow = true;
58
+ g.add(leg);
59
+ });
60
+
61
+ // Horizontal stretcher bars connecting legs (lower)
62
+ var stretcherMat = PAL.chromeBrushed();
63
+ var hStretch1 = new THREE.Mesh(new THREE.BoxGeometry(0.88, 0.015, 0.015), stretcherMat);
64
+ hStretch1.position.set(0, 0.12, 0.22);
65
+ g.add(hStretch1);
66
+
67
+ var hStretch2 = hStretch1.clone();
68
+ hStretch2.position.z = -0.22;
69
+ g.add(hStretch2);
70
+
71
+ var vStretch1 = new THREE.Mesh(new THREE.BoxGeometry(0.015, 0.015, 0.44), stretcherMat);
72
+ vStretch1.position.set(-0.44, 0.12, 0);
73
+ g.add(vStretch1);
74
+
75
+ var vStretch2 = vStretch1.clone();
76
+ vStretch2.position.x = 0.44;
77
+ g.add(vStretch2);
78
+
79
+ return g;
80
+ }
81
+ };
@@ -0,0 +1,95 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'column',
6
+ name: 'Column',
7
+ category: 'structural',
8
+ icon: 'Co',
9
+ gridW: 1, gridD: 1, height: 4,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ var marble = PAL.marbleWhite();
14
+ var gold = PAL.gold();
15
+
16
+ // Main shaft — cylinder
17
+ var shaft = new THREE.Mesh(
18
+ new THREE.CylinderGeometry(0.15, 0.17, 3.6, 16),
19
+ marble
20
+ );
21
+ shaft.position.y = 0;
22
+ shaft.castShadow = true;
23
+ shaft.receiveShadow = true;
24
+ g.add(shaft);
25
+
26
+ // Base plinth (square)
27
+ var base = new THREE.Mesh(
28
+ new THREE.BoxGeometry(0.42, 0.2, 0.42),
29
+ marble
30
+ );
31
+ base.position.y = -1.9;
32
+ base.castShadow = true;
33
+ g.add(base);
34
+
35
+ // Base plinth bottom step
36
+ var baseStep = new THREE.Mesh(
37
+ new THREE.BoxGeometry(0.48, 0.1, 0.48),
38
+ marble
39
+ );
40
+ baseStep.position.y = -2.0;
41
+ g.add(baseStep);
42
+
43
+ // Capital block (top)
44
+ var capital = new THREE.Mesh(
45
+ new THREE.BoxGeometry(0.44, 0.2, 0.44),
46
+ marble
47
+ );
48
+ capital.position.y = 1.9;
49
+ capital.castShadow = true;
50
+ g.add(capital);
51
+
52
+ // Capital abacus (wider flat top)
53
+ var abacus = new THREE.Mesh(
54
+ new THREE.BoxGeometry(0.5, 0.08, 0.5),
55
+ marble
56
+ );
57
+ abacus.position.y = 2.0;
58
+ g.add(abacus);
59
+
60
+ // Gold capital ring torus
61
+ var ring = new THREE.Mesh(
62
+ new THREE.TorusGeometry(0.165, 0.025, 8, 24),
63
+ gold
64
+ );
65
+ ring.rotation.x = Math.PI / 2;
66
+ ring.position.y = 1.72;
67
+ ring.castShadow = true;
68
+ g.add(ring);
69
+
70
+ // Second gold ring (lower accent)
71
+ var ringLow = new THREE.Mesh(
72
+ new THREE.TorusGeometry(0.175, 0.018, 8, 24),
73
+ gold
74
+ );
75
+ ringLow.rotation.x = Math.PI / 2;
76
+ ringLow.position.y = -1.72;
77
+ g.add(ringLow);
78
+
79
+ // Subtle fluting grooves (flat vertical strips on shaft)
80
+ var fluteMat = mat(0xddd8cc, { roughness: 0.2, metalness: 0.05 });
81
+ var i;
82
+ for (i = 0; i < 8; i++) {
83
+ var angle = (i / 8) * Math.PI * 2;
84
+ var flute = new THREE.Mesh(
85
+ new THREE.BoxGeometry(0.018, 3.4, 0.018),
86
+ fluteMat
87
+ );
88
+ flute.position.x = Math.cos(angle) * 0.15;
89
+ flute.position.z = Math.sin(angle) * 0.15;
90
+ g.add(flute);
91
+ }
92
+
93
+ return g;
94
+ }
95
+ };