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,64 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'glass-wall',
6
+ name: 'Glass Wall',
7
+ category: 'structural',
8
+ icon: 'GW',
9
+ gridW: 2, gridD: 1, height: 3,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Glass panel
14
+ var panel = new THREE.Mesh(
15
+ new THREE.BoxGeometry(2, 3, 0.06),
16
+ PAL.glass()
17
+ );
18
+ panel.castShadow = false;
19
+ panel.receiveShadow = true;
20
+ g.add(panel);
21
+
22
+ // Top chrome frame
23
+ var topFrame = new THREE.Mesh(
24
+ new THREE.BoxGeometry(2, 0.08, 0.1),
25
+ PAL.chrome()
26
+ );
27
+ topFrame.position.y = 1.5;
28
+ topFrame.castShadow = true;
29
+ g.add(topFrame);
30
+
31
+ // Bottom chrome frame
32
+ var botFrame = new THREE.Mesh(
33
+ new THREE.BoxGeometry(2, 0.08, 0.1),
34
+ PAL.chrome()
35
+ );
36
+ botFrame.position.y = -1.5;
37
+ botFrame.castShadow = true;
38
+ g.add(botFrame);
39
+
40
+ // Left vertical chrome post
41
+ var leftPost = new THREE.Mesh(
42
+ new THREE.BoxGeometry(0.06, 3, 0.1),
43
+ PAL.chrome()
44
+ );
45
+ leftPost.position.x = -0.97;
46
+ leftPost.castShadow = true;
47
+ g.add(leftPost);
48
+
49
+ // Right vertical chrome post
50
+ var rightPost = leftPost.clone();
51
+ rightPost.position.x = 0.97;
52
+ g.add(rightPost);
53
+
54
+ // Mid chrome rail (horizontal)
55
+ var midRail = new THREE.Mesh(
56
+ new THREE.BoxGeometry(2, 0.04, 0.08),
57
+ PAL.chromeBrushed()
58
+ );
59
+ midRail.position.y = 0.5;
60
+ g.add(midRail);
61
+
62
+ return g;
63
+ }
64
+ };
@@ -0,0 +1,49 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'half-wall',
6
+ name: 'Half Wall',
7
+ category: 'structural',
8
+ icon: 'HW',
9
+ gridW: 2, gridD: 1, height: 1.2,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Main body
14
+ var body = new THREE.Mesh(
15
+ new THREE.BoxGeometry(2, 1.2, 0.25),
16
+ PAL.concrete()
17
+ );
18
+ body.castShadow = true;
19
+ body.receiveShadow = true;
20
+ g.add(body);
21
+
22
+ // Top cap — chrome rail
23
+ var cap = new THREE.Mesh(
24
+ new THREE.BoxGeometry(2.04, 0.07, 0.32),
25
+ PAL.chrome()
26
+ );
27
+ cap.position.y = 0.635;
28
+ cap.castShadow = true;
29
+ g.add(cap);
30
+
31
+ // Base strip
32
+ var base = new THREE.Mesh(
33
+ new THREE.BoxGeometry(2.04, 0.09, 0.28),
34
+ mat(0x1e2128, { roughness: 0.7 })
35
+ );
36
+ base.position.y = -0.555;
37
+ g.add(base);
38
+
39
+ // Front face subtle recess panel
40
+ var panel = new THREE.Mesh(
41
+ new THREE.BoxGeometry(1.7, 0.85, 0.02),
42
+ mat(0x24272f, { roughness: 0.9 })
43
+ );
44
+ panel.position.z = 0.13;
45
+ g.add(panel);
46
+
47
+ return g;
48
+ }
49
+ };
@@ -0,0 +1,112 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'hanging_plant',
6
+ name: 'Hanging Plant',
7
+ category: 'nature',
8
+ icon: 'Hp',
9
+ gridW: 1, gridD: 1, height: 3.0,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Ceiling mount bracket
14
+ var mount = new THREE.Mesh(
15
+ new THREE.BoxGeometry(0.06, 0.06, 0.06),
16
+ mat(0x111111, { roughness: 0.5, metalness: 0.6 })
17
+ );
18
+ mount.position.y = 3.0;
19
+ g.add(mount);
20
+
21
+ // Chain links (vertical rod segments)
22
+ var chainMat = PAL.chromeBrushed();
23
+ var chainSegments = 6;
24
+ for (var i = 0; i < chainSegments; i++) {
25
+ var link = new THREE.Mesh(
26
+ new THREE.TorusGeometry(0.018, 0.006, 6, 10),
27
+ chainMat
28
+ );
29
+ link.position.y = 2.92 - i * 0.145;
30
+ link.rotation.x = (i % 2 === 0) ? 0 : Math.PI / 2;
31
+ g.add(link);
32
+ }
33
+
34
+ // Hanging pot (round, dark clay)
35
+ var pot = new THREE.Mesh(
36
+ new THREE.CylinderGeometry(0.16, 0.11, 0.22, 18),
37
+ mat(0x1a1822, { roughness: 0.82 })
38
+ );
39
+ pot.position.y = 2.04;
40
+ pot.castShadow = true;
41
+ g.add(pot);
42
+
43
+ // Pot rim
44
+ var rim = new THREE.Mesh(
45
+ new THREE.TorusGeometry(0.165, 0.016, 8, 24),
46
+ mat(0x111018, { roughness: 0.78 })
47
+ );
48
+ rim.rotation.x = Math.PI / 2;
49
+ rim.position.y = 2.148;
50
+ g.add(rim);
51
+
52
+ // Support wires (3 wires from rim to chain)
53
+ var wireMat = mat(0x666666, { roughness: 0.40, metalness: 0.60 });
54
+ for (var w = 0; w < 3; w++) {
55
+ var wireAngle = (w / 3) * Math.PI * 2;
56
+ var wire = new THREE.Mesh(
57
+ new THREE.CylinderGeometry(0.004, 0.004, 0.76, 4),
58
+ wireMat
59
+ );
60
+ wire.position.set(
61
+ Math.sin(wireAngle) * 0.13,
62
+ 2.53,
63
+ Math.cos(wireAngle) * 0.13
64
+ );
65
+ wire.rotation.z = Math.atan2(Math.sin(wireAngle) * 0.13, 0.38);
66
+ wire.rotation.x = Math.atan2(Math.cos(wireAngle) * 0.13, 0.38);
67
+ g.add(wire);
68
+ }
69
+
70
+ // Soil
71
+ var soil = new THREE.Mesh(
72
+ new THREE.CylinderGeometry(0.148, 0.148, 0.014, 18),
73
+ mat(0x1a1510, { roughness: 0.99 })
74
+ );
75
+ soil.position.y = 2.155;
76
+ g.add(soil);
77
+
78
+ // Trailing leaf clusters (draping down)
79
+ var leafColors = [0x2d8a4e, 0x226638, 0x1e5c30, 0x358050];
80
+ var trailCount = 7;
81
+ for (var t = 0; t < trailCount; t++) {
82
+ var tAngle = (t / trailCount) * Math.PI * 2;
83
+ var tRadius = 0.10 + (t % 3) * 0.04;
84
+ var tDrop = t * 0.10;
85
+
86
+ var leaf = new THREE.Mesh(
87
+ new THREE.SphereGeometry(0.062, 8, 7),
88
+ mat(leafColors[t % leafColors.length], { roughness: 0.82 })
89
+ );
90
+ leaf.scale.set(0.7, 0.5, 1.2);
91
+ leaf.position.set(
92
+ Math.sin(tAngle) * (tRadius + 0.05),
93
+ 1.95 - tDrop,
94
+ Math.cos(tAngle) * (tRadius + 0.05)
95
+ );
96
+ leaf.castShadow = true;
97
+ g.add(leaf);
98
+ }
99
+
100
+ // Main foliage cluster in pot
101
+ var mainLeaf = new THREE.Mesh(
102
+ new THREE.SphereGeometry(0.18, 12, 10),
103
+ mat(0x2d8a4e, { roughness: 0.80 })
104
+ );
105
+ mainLeaf.scale.set(1, 0.65, 1);
106
+ mainLeaf.position.y = 2.22;
107
+ mainLeaf.castShadow = true;
108
+ g.add(mainLeaf);
109
+
110
+ return g;
111
+ }
112
+ };
@@ -0,0 +1,151 @@
1
+ // Asset Registry — auto-imports all individual asset files
2
+ // Each asset is a separate file for maintainability
3
+ import * as THREE from 'three';
4
+
5
+ // Categories
6
+ export var ASSET_CATEGORIES = [
7
+ { id: 'structural', label: 'Structural', icon: 'ST' },
8
+ { id: 'furniture', label: 'Furniture', icon: 'FN' },
9
+ { id: 'office', label: 'Office', icon: 'OF' },
10
+ { id: 'decor', label: 'Decor', icon: 'DC' },
11
+ { id: 'nature', label: 'Nature', icon: 'NT' },
12
+ { id: 'tech', label: 'Tech', icon: 'TC' },
13
+ { id: 'lighting', label: 'Lighting', icon: 'LT' },
14
+ { id: 'kitchen', label: 'Kitchen', icon: 'KT' },
15
+ { id: 'recreation', label: 'Recreation', icon: 'RC' },
16
+ { id: 'exterior', label: 'Exterior', icon: 'EX' },
17
+ ];
18
+
19
+ // Import all asset modules
20
+ import wall from './wall.js';
21
+ import glass_wall from './glass-wall.js';
22
+ import half_wall from './half-wall.js';
23
+ import floor_tile from './floor-tile.js';
24
+ import marble_floor from './marble-floor.js';
25
+ import carpet_tile from './carpet-tile.js';
26
+ import door from './door.js';
27
+ import glass_door from './glass-door.js';
28
+ import archway from './archway.js';
29
+ import column from './column.js';
30
+
31
+ import desk from './desk.js';
32
+ import gaming_desk from './gaming-desk.js';
33
+ import chair from './chair.js';
34
+ import gaming_chair from './gaming-chair.js';
35
+ import sofa from './sofa.js';
36
+ import l_sofa from './l-sofa.js';
37
+ import coffee_table from './coffee-table.js';
38
+ import dining_table from './dining-table.js';
39
+
40
+ import filing_cabinet from './filing-cabinet.js';
41
+ import whiteboard from './whiteboard.js';
42
+ import meeting_table from './meeting-table.js';
43
+ import reception_desk from './reception-desk.js';
44
+ import printer from './printer.js';
45
+ import water_cooler from './water-cooler.js';
46
+
47
+ import painting from './painting.js';
48
+ import sculpture from './sculpture.js';
49
+ import rug from './rug.js';
50
+ import vase from './vase.js';
51
+ import trophy from './trophy.js';
52
+ import wall_clock from './wall-clock.js';
53
+
54
+ import plant from './plant.js';
55
+ import indoor_tree from './indoor-tree.js';
56
+ import palm_tree from './palm-tree.js';
57
+ import flower_pot from './flower-pot.js';
58
+ import hanging_plant from './hanging-plant.js';
59
+ import cactus from './cactus.js';
60
+
61
+ import monitor from './monitor.js';
62
+ import dual_monitor from './dual-monitor.js';
63
+ import pc_tower from './pc-tower.js';
64
+ import server_rack from './server-rack.js';
65
+ import tv_screen from './tv-screen.js';
66
+ import speaker from './speaker.js';
67
+
68
+ import floor_lamp from './floor-lamp.js';
69
+ import pendant_light from './pendant-light.js';
70
+ import desk_lamp from './desk-lamp.js';
71
+ import spotlight from './spotlight.js';
72
+ import neon_strip from './neon-strip.js';
73
+ import chandelier from './chandelier.js';
74
+
75
+ import bar_counter from './bar-counter.js';
76
+ import bar_stool from './bar-stool.js';
77
+ import coffee_machine from './coffee-machine.js';
78
+ import fridge from './fridge.js';
79
+ import sink from './sink.js';
80
+ import microwave from './microwave.js';
81
+
82
+ import pool_table from './pool-table.js';
83
+ import foosball from './foosball.js';
84
+ import arcade_cabinet from './arcade-cabinet.js';
85
+ import treadmill from './treadmill.js';
86
+ import beanbag from './beanbag.js';
87
+ import ping_pong from './ping-pong.js';
88
+
89
+ import bench from './bench.js';
90
+ import street_lamp from './street-lamp.js';
91
+ import trash_can from './trash-can.js';
92
+ import planter_box from './planter-box.js';
93
+ import fence from './fence.js';
94
+ import bollard from './bollard.js';
95
+
96
+ // Master asset list
97
+ export var ASSETS = [
98
+ // Structural
99
+ wall, glass_wall, half_wall, floor_tile, marble_floor, carpet_tile, door, glass_door, archway, column,
100
+ // Furniture
101
+ desk, gaming_desk, chair, gaming_chair, sofa, l_sofa, coffee_table, dining_table,
102
+ // Office
103
+ filing_cabinet, whiteboard, meeting_table, reception_desk, printer, water_cooler,
104
+ // Decor
105
+ painting, sculpture, rug, vase, trophy, wall_clock,
106
+ // Nature
107
+ plant, indoor_tree, palm_tree, flower_pot, hanging_plant, cactus,
108
+ // Tech
109
+ monitor, dual_monitor, pc_tower, server_rack, tv_screen, speaker,
110
+ // Lighting
111
+ floor_lamp, pendant_light, desk_lamp, spotlight, neon_strip, chandelier,
112
+ // Kitchen
113
+ bar_counter, bar_stool, coffee_machine, fridge, sink, microwave,
114
+ // Recreation
115
+ pool_table, foosball, arcade_cabinet, treadmill, beanbag, ping_pong,
116
+ // Exterior
117
+ bench, street_lamp, trash_can, planter_box, fence, bollard,
118
+ ];
119
+
120
+ // Get asset by ID
121
+ export function getAsset(id) {
122
+ for (var i = 0; i < ASSETS.length; i++) {
123
+ if (ASSETS[i].id === id) return ASSETS[i];
124
+ }
125
+ return null;
126
+ }
127
+
128
+ // Get assets by category
129
+ export function getAssetsByCategory(cat) {
130
+ return ASSETS.filter(function(a) { return a.category === cat; });
131
+ }
132
+
133
+ // Create a ghost (transparent preview) of an asset
134
+ export function createGhost(assetId) {
135
+ var asset = getAsset(assetId);
136
+ if (!asset) return null;
137
+ var group = asset.factory();
138
+ group.traverse(function(child) {
139
+ if (child.isMesh) {
140
+ child.material = new THREE.MeshStandardMaterial({
141
+ color: 0x44ff88,
142
+ transparent: true,
143
+ opacity: 0.35,
144
+ depthWrite: false,
145
+ });
146
+ }
147
+ });
148
+ group.userData.isGhost = true;
149
+ group.userData.assetId = assetId;
150
+ return group;
151
+ }
@@ -0,0 +1,90 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'indoor_tree',
6
+ name: 'Indoor Tree',
7
+ category: 'nature',
8
+ icon: 'IT',
9
+ gridW: 1, gridD: 1, height: 3.5,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // Large planter (square, dark concrete)
14
+ var planter = new THREE.Mesh(
15
+ new THREE.BoxGeometry(0.72, 0.40, 0.72),
16
+ mat(0x2e3038, { roughness: 0.88 })
17
+ );
18
+ planter.position.y = 0.20;
19
+ planter.castShadow = true;
20
+ planter.receiveShadow = true;
21
+ g.add(planter);
22
+
23
+ // Planter rim trim (gold strip)
24
+ var rimTop = new THREE.Mesh(
25
+ new THREE.BoxGeometry(0.76, 0.03, 0.76),
26
+ PAL.gold()
27
+ );
28
+ rimTop.position.y = 0.415;
29
+ g.add(rimTop);
30
+
31
+ // Soil
32
+ var soil = new THREE.Mesh(
33
+ new THREE.BoxGeometry(0.68, 0.025, 0.68),
34
+ mat(0x1a1510, { roughness: 0.99 })
35
+ );
36
+ soil.position.y = 0.413;
37
+ g.add(soil);
38
+
39
+ // Trunk — lower
40
+ var trunkMat = mat(0x3d2b12, { roughness: 0.80 });
41
+ var trunkLow = new THREE.Mesh(
42
+ new THREE.CylinderGeometry(0.075, 0.095, 1.20, 10),
43
+ trunkMat
44
+ );
45
+ trunkLow.position.y = 1.02;
46
+ trunkLow.castShadow = true;
47
+ g.add(trunkLow);
48
+
49
+ // Trunk — upper (slims slightly)
50
+ var trunkUp = new THREE.Mesh(
51
+ new THREE.CylinderGeometry(0.048, 0.075, 1.10, 10),
52
+ trunkMat
53
+ );
54
+ trunkUp.position.y = 2.17;
55
+ trunkUp.castShadow = true;
56
+ g.add(trunkUp);
57
+
58
+ // Canopy tier 1 — bottom, widest
59
+ var canopy1 = new THREE.Mesh(
60
+ new THREE.SphereGeometry(0.55, 14, 10),
61
+ PAL.leaf()
62
+ );
63
+ canopy1.scale.set(1, 0.7, 1);
64
+ canopy1.position.y = 2.65;
65
+ canopy1.castShadow = true;
66
+ g.add(canopy1);
67
+
68
+ // Canopy tier 2 — middle
69
+ var canopy2 = new THREE.Mesh(
70
+ new THREE.SphereGeometry(0.44, 14, 10),
71
+ mat(0x226638, { roughness: 0.80 })
72
+ );
73
+ canopy2.scale.set(1, 0.75, 1);
74
+ canopy2.position.y = 3.05;
75
+ canopy2.castShadow = true;
76
+ g.add(canopy2);
77
+
78
+ // Canopy tier 3 — top, smallest, pointy
79
+ var canopy3 = new THREE.Mesh(
80
+ new THREE.SphereGeometry(0.28, 12, 10),
81
+ mat(0x1e5c30, { roughness: 0.82 })
82
+ );
83
+ canopy3.scale.set(1, 1.2, 1);
84
+ canopy3.position.y = 3.42;
85
+ canopy3.castShadow = true;
86
+ g.add(canopy3);
87
+
88
+ return g;
89
+ }
90
+ };
@@ -0,0 +1,153 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'l-sofa',
6
+ name: 'L-Sofa',
7
+ category: 'furniture',
8
+ icon: 'LS',
9
+ gridW: 4, gridD: 2, height: 0.9,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+ var fabricMat = PAL.fabric();
13
+ var frameMat = mat(0x17191f, { roughness: 0.6 });
14
+ var capMat = mat(0x1e2028, { roughness: 0.45 });
15
+ var cushionMat = mat(0x252830, { roughness: 0.92 });
16
+
17
+ // === MAIN SECTION (3W, along X axis) ===
18
+ var mainBase = new THREE.Mesh(
19
+ new THREE.BoxGeometry(3.0, 0.18, 0.9),
20
+ frameMat
21
+ );
22
+ mainBase.position.set(0, 0.09, 0);
23
+ mainBase.castShadow = true;
24
+ mainBase.receiveShadow = true;
25
+ g.add(mainBase);
26
+
27
+ var mainSeat = new THREE.Mesh(
28
+ new THREE.BoxGeometry(2.88, 0.16, 0.76),
29
+ fabricMat
30
+ );
31
+ mainSeat.position.set(0, 0.26, 0);
32
+ mainSeat.castShadow = true;
33
+ g.add(mainSeat);
34
+
35
+ var mainBack = new THREE.Mesh(
36
+ new THREE.BoxGeometry(2.88, 0.56, 0.18),
37
+ fabricMat
38
+ );
39
+ mainBack.position.set(0, 0.62, -0.35);
40
+ mainBack.castShadow = true;
41
+ g.add(mainBack);
42
+
43
+ var mainBackCap = new THREE.Mesh(
44
+ new THREE.BoxGeometry(3.0, 0.06, 0.20),
45
+ capMat
46
+ );
47
+ mainBackCap.position.set(0, 0.92, -0.34);
48
+ g.add(mainBackCap);
49
+
50
+ // 3 seat cushions main
51
+ [-0.96, 0, 0.96].forEach(function(x) {
52
+ var c = new THREE.Mesh(new THREE.BoxGeometry(0.88, 0.10, 0.72), cushionMat);
53
+ c.position.set(x, 0.37, 0.01);
54
+ c.castShadow = true;
55
+ g.add(c);
56
+ });
57
+
58
+ // Left arm (main section)
59
+ var leftArm = new THREE.Mesh(new THREE.BoxGeometry(0.18, 0.46, 0.9), fabricMat);
60
+ leftArm.position.set(-1.41, 0.41, 0);
61
+ leftArm.castShadow = true;
62
+ g.add(leftArm);
63
+
64
+ var leftArmCap = new THREE.Mesh(new THREE.BoxGeometry(0.20, 0.04, 0.92), capMat);
65
+ leftArmCap.position.set(-1.41, 0.65, 0);
66
+ g.add(leftArmCap);
67
+
68
+ // === WING SECTION (1.5W, along Z axis, attached to right side) ===
69
+ // Offset so it attaches at right end of main section
70
+ var wingBase = new THREE.Mesh(
71
+ new THREE.BoxGeometry(1.5, 0.18, 0.9),
72
+ frameMat
73
+ );
74
+ wingBase.position.set(2.0, 0.09, 0.85);
75
+ wingBase.rotation.y = Math.PI / 2;
76
+ wingBase.castShadow = true;
77
+ wingBase.receiveShadow = true;
78
+ g.add(wingBase);
79
+
80
+ var wingSeat = new THREE.Mesh(
81
+ new THREE.BoxGeometry(1.38, 0.16, 0.76),
82
+ fabricMat
83
+ );
84
+ wingSeat.position.set(2.0, 0.26, 0.85);
85
+ wingSeat.rotation.y = Math.PI / 2;
86
+ wingSeat.castShadow = true;
87
+ g.add(wingSeat);
88
+
89
+ var wingBack = new THREE.Mesh(
90
+ new THREE.BoxGeometry(1.38, 0.56, 0.18),
91
+ fabricMat
92
+ );
93
+ wingBack.position.set(2.35, 0.62, 0.85);
94
+ wingBack.rotation.y = Math.PI / 2;
95
+ wingBack.castShadow = true;
96
+ g.add(wingBack);
97
+
98
+ var wingBackCap = new THREE.Mesh(
99
+ new THREE.BoxGeometry(1.5, 0.06, 0.20),
100
+ capMat
101
+ );
102
+ wingBackCap.position.set(2.35, 0.92, 0.85);
103
+ wingBackCap.rotation.y = Math.PI / 2;
104
+ g.add(wingBackCap);
105
+
106
+ // 2 seat cushions on wing
107
+ [-0.38, 0.38].forEach(function(offset) {
108
+ var c = new THREE.Mesh(new THREE.BoxGeometry(0.62, 0.10, 0.72), cushionMat);
109
+ c.position.set(2.0, 0.37, 0.85 + offset);
110
+ c.castShadow = true;
111
+ g.add(c);
112
+ });
113
+
114
+ // Wing end arm
115
+ var wingArm = new THREE.Mesh(new THREE.BoxGeometry(0.18, 0.46, 0.9), fabricMat);
116
+ wingArm.position.set(2.0, 0.41, 1.63);
117
+ wingArm.rotation.y = Math.PI / 2;
118
+ wingArm.castShadow = true;
119
+ g.add(wingArm);
120
+
121
+ var wingArmCap = new THREE.Mesh(new THREE.BoxGeometry(0.20, 0.04, 0.92), capMat);
122
+ wingArmCap.position.set(2.0, 0.65, 1.63);
123
+ wingArmCap.rotation.y = Math.PI / 2;
124
+ g.add(wingArmCap);
125
+
126
+ // Corner connector piece
127
+ var corner = new THREE.Mesh(
128
+ new THREE.BoxGeometry(0.9, 0.18, 0.9),
129
+ frameMat
130
+ );
131
+ corner.position.set(1.5, 0.09, 0.45);
132
+ corner.castShadow = true;
133
+ g.add(corner);
134
+
135
+ var cornerSeat = new THREE.Mesh(
136
+ new THREE.BoxGeometry(0.78, 0.16, 0.78),
137
+ fabricMat
138
+ );
139
+ cornerSeat.position.set(1.5, 0.26, 0.45);
140
+ g.add(cornerSeat);
141
+
142
+ // 6 chrome legs
143
+ var legMat = PAL.chrome();
144
+ var legGeo = new THREE.CylinderGeometry(0.025, 0.02, 0.09, 8);
145
+ [[-1.35, -0.35], [-1.35, 0.38], [0.5, -0.35], [1.5, 1.25], [2.0, 1.25], [1.5, -0.35]].forEach(function(p) {
146
+ var leg = new THREE.Mesh(legGeo, legMat);
147
+ leg.position.set(p[0], 0.045, p[1]);
148
+ g.add(leg);
149
+ });
150
+
151
+ return g;
152
+ }
153
+ };
@@ -0,0 +1,64 @@
1
+ import * as THREE from 'three';
2
+ import { mat, PAL } from './materials.js';
3
+
4
+ export default {
5
+ id: 'marble-floor',
6
+ name: 'Marble Floor',
7
+ category: 'structural',
8
+ icon: 'MF',
9
+ gridW: 2, gridD: 2, height: 0.02,
10
+ factory: function() {
11
+ var g = new THREE.Group();
12
+
13
+ // White marble slab
14
+ var slab = new THREE.Mesh(
15
+ new THREE.BoxGeometry(2, 0.02, 2),
16
+ PAL.marbleWhite()
17
+ );
18
+ slab.receiveShadow = true;
19
+ g.add(slab);
20
+
21
+ // Gold border inlay — all 4 sides
22
+ var goldMat = PAL.gold();
23
+ var borderThick = 0.04;
24
+ var borderH = 0.022;
25
+
26
+ var borderN = new THREE.Mesh(
27
+ new THREE.BoxGeometry(2, borderH, borderThick),
28
+ goldMat
29
+ );
30
+ borderN.position.z = -(1 - borderThick / 2);
31
+ g.add(borderN);
32
+
33
+ var borderS = borderN.clone();
34
+ borderS.position.z = 1 - borderThick / 2;
35
+ g.add(borderS);
36
+
37
+ var borderW = new THREE.Mesh(
38
+ new THREE.BoxGeometry(borderThick, borderH, 2),
39
+ goldMat
40
+ );
41
+ borderW.position.x = -(1 - borderThick / 2);
42
+ g.add(borderW);
43
+
44
+ var borderE = borderW.clone();
45
+ borderE.position.x = 1 - borderThick / 2;
46
+ g.add(borderE);
47
+
48
+ // Inner gold diamond accent lines
49
+ var innerMat = mat(0xc9a227, { roughness: 0.35, metalness: 0.65 });
50
+ var accentH = new THREE.Mesh(
51
+ new THREE.BoxGeometry(1.5, borderH, 0.015),
52
+ innerMat
53
+ );
54
+ g.add(accentH);
55
+
56
+ var accentV = new THREE.Mesh(
57
+ new THREE.BoxGeometry(0.015, borderH, 1.5),
58
+ innerMat
59
+ );
60
+ g.add(accentV);
61
+
62
+ return g;
63
+ }
64
+ };