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,146 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'water-cooler',
|
|
6
|
+
name: 'Water Cooler',
|
|
7
|
+
category: 'office',
|
|
8
|
+
icon: 'WC',
|
|
9
|
+
gridW: 1, gridD: 1, height: 1.2,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
var bodyMat = mat(0x1e2128, { roughness: 0.45, metalness: 0.15 });
|
|
14
|
+
|
|
15
|
+
// Base cabinet body
|
|
16
|
+
var base = new THREE.Mesh(
|
|
17
|
+
new THREE.BoxGeometry(0.3, 0.75, 0.3),
|
|
18
|
+
bodyMat
|
|
19
|
+
);
|
|
20
|
+
base.position.y = 0.375;
|
|
21
|
+
base.castShadow = true;
|
|
22
|
+
base.receiveShadow = true;
|
|
23
|
+
g.add(base);
|
|
24
|
+
|
|
25
|
+
// Base door line (subtle seam)
|
|
26
|
+
var doorSeam = new THREE.Mesh(
|
|
27
|
+
new THREE.BoxGeometry(0.005, 0.44, 0.302),
|
|
28
|
+
mat(0x111318, { roughness: 0.9 })
|
|
29
|
+
);
|
|
30
|
+
doorSeam.position.set(0, 0.34, 0);
|
|
31
|
+
g.add(doorSeam);
|
|
32
|
+
|
|
33
|
+
// Front door panel
|
|
34
|
+
var door = new THREE.Mesh(
|
|
35
|
+
new THREE.BoxGeometry(0.28, 0.42, 0.012),
|
|
36
|
+
mat(0x252830, { roughness: 0.4, metalness: 0.14 })
|
|
37
|
+
);
|
|
38
|
+
door.position.set(0, 0.32, 0.156);
|
|
39
|
+
g.add(door);
|
|
40
|
+
|
|
41
|
+
// Door handle
|
|
42
|
+
var handle = new THREE.Mesh(
|
|
43
|
+
new THREE.BoxGeometry(0.06, 0.018, 0.018),
|
|
44
|
+
PAL.chrome()
|
|
45
|
+
);
|
|
46
|
+
handle.position.set(0.09, 0.32, 0.165);
|
|
47
|
+
g.add(handle);
|
|
48
|
+
|
|
49
|
+
// Drip tray platform (top of cabinet)
|
|
50
|
+
var tray = new THREE.Mesh(
|
|
51
|
+
new THREE.BoxGeometry(0.30, 0.04, 0.30),
|
|
52
|
+
mat(0x252830, { roughness: 0.5, metalness: 0.20 })
|
|
53
|
+
);
|
|
54
|
+
tray.position.y = 0.77;
|
|
55
|
+
tray.castShadow = true;
|
|
56
|
+
g.add(tray);
|
|
57
|
+
|
|
58
|
+
// Drip tray grid (decorative)
|
|
59
|
+
var gridMat = mat(0x333640, { roughness: 0.7, metalness: 0.3 });
|
|
60
|
+
for (var i = -1; i <= 1; i++) {
|
|
61
|
+
var gridLine = new THREE.Mesh(new THREE.BoxGeometry(0.26, 0.008, 0.005), gridMat);
|
|
62
|
+
gridLine.position.set(0, 0.793, i * 0.08);
|
|
63
|
+
g.add(gridLine);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Dispenser housing (middle section)
|
|
67
|
+
var dispenser = new THREE.Mesh(
|
|
68
|
+
new THREE.BoxGeometry(0.28, 0.22, 0.28),
|
|
69
|
+
bodyMat
|
|
70
|
+
);
|
|
71
|
+
dispenser.position.y = 0.90;
|
|
72
|
+
dispenser.castShadow = true;
|
|
73
|
+
g.add(dispenser);
|
|
74
|
+
|
|
75
|
+
// Hot tap (red)
|
|
76
|
+
var hotTap = new THREE.Mesh(
|
|
77
|
+
new THREE.CylinderGeometry(0.018, 0.018, 0.045, 10),
|
|
78
|
+
mat(0xcc2222, { roughness: 0.4 })
|
|
79
|
+
);
|
|
80
|
+
hotTap.rotation.z = Math.PI / 2;
|
|
81
|
+
hotTap.position.set(-0.1, 0.845, 0.14);
|
|
82
|
+
g.add(hotTap);
|
|
83
|
+
|
|
84
|
+
// Cold tap (blue)
|
|
85
|
+
var coldTap = new THREE.Mesh(
|
|
86
|
+
new THREE.CylinderGeometry(0.018, 0.018, 0.045, 10),
|
|
87
|
+
mat(0x2266cc, { roughness: 0.4 })
|
|
88
|
+
);
|
|
89
|
+
coldTap.rotation.z = Math.PI / 2;
|
|
90
|
+
coldTap.position.set(0.1, 0.845, 0.14);
|
|
91
|
+
g.add(coldTap);
|
|
92
|
+
|
|
93
|
+
// Bottle collar ring (neck interface)
|
|
94
|
+
var collar = new THREE.Mesh(
|
|
95
|
+
new THREE.CylinderGeometry(0.08, 0.09, 0.06, 16),
|
|
96
|
+
mat(0x252830, { roughness: 0.5, metalness: 0.2 })
|
|
97
|
+
);
|
|
98
|
+
collar.position.y = 1.03;
|
|
99
|
+
g.add(collar);
|
|
100
|
+
|
|
101
|
+
// Water bottle (blue, translucent)
|
|
102
|
+
var bottle = new THREE.Mesh(
|
|
103
|
+
new THREE.CylinderGeometry(0.10, 0.10, 0.40, 18),
|
|
104
|
+
mat(0x3399cc, { transparent: true, opacity: 0.72, roughness: 0.08 })
|
|
105
|
+
);
|
|
106
|
+
bottle.position.y = 1.26;
|
|
107
|
+
bottle.castShadow = true;
|
|
108
|
+
g.add(bottle);
|
|
109
|
+
|
|
110
|
+
// Bottle cap
|
|
111
|
+
var cap = new THREE.Mesh(
|
|
112
|
+
new THREE.CylinderGeometry(0.045, 0.045, 0.025, 14),
|
|
113
|
+
mat(0x1155aa, { roughness: 0.4 })
|
|
114
|
+
);
|
|
115
|
+
cap.position.y = 1.473;
|
|
116
|
+
g.add(cap);
|
|
117
|
+
|
|
118
|
+
// Bottle bottom dome
|
|
119
|
+
var dome = new THREE.Mesh(
|
|
120
|
+
new THREE.SphereGeometry(0.10, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2),
|
|
121
|
+
mat(0x3399cc, { transparent: true, opacity: 0.72, roughness: 0.08 })
|
|
122
|
+
);
|
|
123
|
+
dome.rotation.x = Math.PI;
|
|
124
|
+
dome.position.y = 1.06;
|
|
125
|
+
g.add(dome);
|
|
126
|
+
|
|
127
|
+
// Water line visible inside bottle
|
|
128
|
+
var waterLine = new THREE.Mesh(
|
|
129
|
+
new THREE.CylinderGeometry(0.096, 0.096, 0.22, 18),
|
|
130
|
+
mat(0x88ccee, { transparent: true, opacity: 0.5, roughness: 0.05 })
|
|
131
|
+
);
|
|
132
|
+
waterLine.position.y = 1.15;
|
|
133
|
+
g.add(waterLine);
|
|
134
|
+
|
|
135
|
+
// 4 base feet
|
|
136
|
+
var footMat = mat(0x111111, { roughness: 0.9 });
|
|
137
|
+
var footGeo = new THREE.CylinderGeometry(0.02, 0.02, 0.02, 8);
|
|
138
|
+
[[-0.1, -0.1], [0.1, -0.1], [-0.1, 0.1], [0.1, 0.1]].forEach(function(p) {
|
|
139
|
+
var foot = new THREE.Mesh(footGeo, footMat);
|
|
140
|
+
foot.position.set(p[0], 0.01, p[1]);
|
|
141
|
+
g.add(foot);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return g;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { mat, PAL } from './materials.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 'whiteboard',
|
|
6
|
+
name: 'Whiteboard',
|
|
7
|
+
category: 'office',
|
|
8
|
+
icon: 'WB',
|
|
9
|
+
gridW: 2, gridD: 1, height: 1.5,
|
|
10
|
+
factory: function() {
|
|
11
|
+
var g = new THREE.Group();
|
|
12
|
+
|
|
13
|
+
// White writing surface
|
|
14
|
+
var surface = new THREE.Mesh(
|
|
15
|
+
new THREE.BoxGeometry(2.0, 1.15, 0.025),
|
|
16
|
+
mat(0xf5f5f0, { roughness: 0.85, metalness: 0.0 })
|
|
17
|
+
);
|
|
18
|
+
surface.position.y = 1.28;
|
|
19
|
+
surface.castShadow = true;
|
|
20
|
+
surface.receiveShadow = true;
|
|
21
|
+
g.add(surface);
|
|
22
|
+
|
|
23
|
+
// Aluminium frame — top
|
|
24
|
+
var frameMat = PAL.chromeBrushed();
|
|
25
|
+
var topFrame = new THREE.Mesh(new THREE.BoxGeometry(2.04, 0.04, 0.04), frameMat);
|
|
26
|
+
topFrame.position.set(0, 1.875, 0);
|
|
27
|
+
topFrame.castShadow = true;
|
|
28
|
+
g.add(topFrame);
|
|
29
|
+
|
|
30
|
+
// Bottom frame (also pen tray holder)
|
|
31
|
+
var botFrame = new THREE.Mesh(new THREE.BoxGeometry(2.04, 0.04, 0.04), frameMat);
|
|
32
|
+
botFrame.position.set(0, 0.705, 0);
|
|
33
|
+
botFrame.castShadow = true;
|
|
34
|
+
g.add(botFrame);
|
|
35
|
+
|
|
36
|
+
// Left frame
|
|
37
|
+
var leftFrame = new THREE.Mesh(new THREE.BoxGeometry(0.04, 1.23, 0.04), frameMat);
|
|
38
|
+
leftFrame.position.set(-1.02, 1.28, 0);
|
|
39
|
+
leftFrame.castShadow = true;
|
|
40
|
+
g.add(leftFrame);
|
|
41
|
+
|
|
42
|
+
// Right frame
|
|
43
|
+
var rightFrame = leftFrame.clone();
|
|
44
|
+
rightFrame.position.x = 1.02;
|
|
45
|
+
g.add(rightFrame);
|
|
46
|
+
|
|
47
|
+
// Pen/marker tray at bottom (extended outward)
|
|
48
|
+
var tray = new THREE.Mesh(
|
|
49
|
+
new THREE.BoxGeometry(1.96, 0.025, 0.07),
|
|
50
|
+
frameMat
|
|
51
|
+
);
|
|
52
|
+
tray.position.set(0, 0.69, 0.045);
|
|
53
|
+
g.add(tray);
|
|
54
|
+
|
|
55
|
+
// Tray back lip
|
|
56
|
+
var trayLip = new THREE.Mesh(
|
|
57
|
+
new THREE.BoxGeometry(1.96, 0.035, 0.012),
|
|
58
|
+
frameMat
|
|
59
|
+
);
|
|
60
|
+
trayLip.position.set(0, 0.707, 0.083);
|
|
61
|
+
g.add(trayLip);
|
|
62
|
+
|
|
63
|
+
// Two marker caps sitting in tray
|
|
64
|
+
var markerMat = mat(0x111111, { roughness: 0.7 });
|
|
65
|
+
[-0.3, 0.1].forEach(function(x) {
|
|
66
|
+
var marker = new THREE.Mesh(
|
|
67
|
+
new THREE.CylinderGeometry(0.008, 0.008, 0.12, 8),
|
|
68
|
+
markerMat
|
|
69
|
+
);
|
|
70
|
+
marker.rotation.z = Math.PI / 2;
|
|
71
|
+
marker.position.set(x, 0.71, 0.055);
|
|
72
|
+
g.add(marker);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Eraser block
|
|
76
|
+
var eraser = new THREE.Mesh(
|
|
77
|
+
new THREE.BoxGeometry(0.1, 0.025, 0.045),
|
|
78
|
+
mat(0x888888, { roughness: 0.9 })
|
|
79
|
+
);
|
|
80
|
+
eraser.position.set(0.5, 0.71, 0.055);
|
|
81
|
+
g.add(eraser);
|
|
82
|
+
|
|
83
|
+
// Two vertical chrome stand legs
|
|
84
|
+
var legMat = PAL.chrome();
|
|
85
|
+
var legGeo = new THREE.CylinderGeometry(0.022, 0.022, 0.72, 10);
|
|
86
|
+
var leftLeg = new THREE.Mesh(legGeo, legMat);
|
|
87
|
+
leftLeg.position.set(-0.75, 0.36, 0);
|
|
88
|
+
leftLeg.castShadow = true;
|
|
89
|
+
g.add(leftLeg);
|
|
90
|
+
|
|
91
|
+
var rightLeg = leftLeg.clone();
|
|
92
|
+
rightLeg.position.x = 0.75;
|
|
93
|
+
g.add(rightLeg);
|
|
94
|
+
|
|
95
|
+
// Horizontal crossbar
|
|
96
|
+
var crossbar = new THREE.Mesh(
|
|
97
|
+
new THREE.BoxGeometry(1.5, 0.025, 0.025),
|
|
98
|
+
legMat
|
|
99
|
+
);
|
|
100
|
+
crossbar.position.set(0, 0.42, 0);
|
|
101
|
+
g.add(crossbar);
|
|
102
|
+
|
|
103
|
+
// T-feet (horizontal base bars)
|
|
104
|
+
var footMat = PAL.chrome();
|
|
105
|
+
var leftFoot = new THREE.Mesh(new THREE.BoxGeometry(0.55, 0.022, 0.022), footMat);
|
|
106
|
+
leftFoot.position.set(-0.75, 0.015, 0);
|
|
107
|
+
g.add(leftFoot);
|
|
108
|
+
|
|
109
|
+
var rightFoot = leftFoot.clone();
|
|
110
|
+
rightFoot.position.x = 0.75;
|
|
111
|
+
g.add(rightFoot);
|
|
112
|
+
|
|
113
|
+
return g;
|
|
114
|
+
}
|
|
115
|
+
};
|
package/office/assets.js
CHANGED
|
@@ -1,431 +1,3 @@
|
|
|
1
|
-
// Asset registry
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// ===================== ASSET DEFINITIONS =====================
|
|
6
|
-
// Each asset: { name, category, icon, width, depth, height, factory }
|
|
7
|
-
// width/depth are footprint in grid units (for snap), height is visual
|
|
8
|
-
|
|
9
|
-
export const ASSET_CATEGORIES = [
|
|
10
|
-
{ id: 'structural', label: 'Structural', icon: 'S' },
|
|
11
|
-
{ id: 'furniture', label: 'Furniture', icon: 'F' },
|
|
12
|
-
{ id: 'decor', label: 'Decor', icon: 'D' },
|
|
13
|
-
{ id: 'tech', label: 'Tech', icon: 'T' },
|
|
14
|
-
{ id: 'lighting', label: 'Lighting', icon: 'L' },
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
var _matCache = {};
|
|
18
|
-
function mat(color, opts) {
|
|
19
|
-
var key = color + JSON.stringify(opts || {});
|
|
20
|
-
if (!_matCache[key]) {
|
|
21
|
-
_matCache[key] = new THREE.MeshStandardMaterial(Object.assign({ color: color }, opts || {}));
|
|
22
|
-
}
|
|
23
|
-
return _matCache[key];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const ASSETS = [
|
|
27
|
-
// ===== STRUCTURAL =====
|
|
28
|
-
{
|
|
29
|
-
id: 'wall',
|
|
30
|
-
name: 'Wall',
|
|
31
|
-
category: 'structural',
|
|
32
|
-
icon: 'W',
|
|
33
|
-
gridW: 2, gridD: 1, height: 3,
|
|
34
|
-
factory: function() {
|
|
35
|
-
var g = new THREE.Group();
|
|
36
|
-
var wall = new THREE.Mesh(new THREE.BoxGeometry(2, 3, 0.12), mat(0x2a2d35, { roughness: 0.8 }));
|
|
37
|
-
wall.position.y = 1.5;
|
|
38
|
-
wall.castShadow = true; wall.receiveShadow = true;
|
|
39
|
-
g.add(wall);
|
|
40
|
-
return g;
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
id: 'glass_wall',
|
|
45
|
-
name: 'Glass Wall',
|
|
46
|
-
category: 'structural',
|
|
47
|
-
icon: 'G',
|
|
48
|
-
gridW: 2, gridD: 1, height: 3,
|
|
49
|
-
factory: function() {
|
|
50
|
-
var g = new THREE.Group();
|
|
51
|
-
var glass = new THREE.Mesh(new THREE.BoxGeometry(2, 3, 0.06), mat(0xaaccee, { transparent: true, opacity: 0.25, roughness: 0.05 }));
|
|
52
|
-
glass.position.y = 1.5;
|
|
53
|
-
g.add(glass);
|
|
54
|
-
// Chrome frame top
|
|
55
|
-
var frame = new THREE.Mesh(new THREE.BoxGeometry(2.05, 0.04, 0.08), mat(0xcccccc, { metalness: 0.8, roughness: 0.2 }));
|
|
56
|
-
frame.position.y = 3;
|
|
57
|
-
g.add(frame);
|
|
58
|
-
return g;
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
id: 'floor_tile',
|
|
63
|
-
name: 'Floor Tile',
|
|
64
|
-
category: 'structural',
|
|
65
|
-
icon: '\u2B1B',
|
|
66
|
-
gridW: 2, gridD: 2, height: 0.02,
|
|
67
|
-
factory: function() {
|
|
68
|
-
var g = new THREE.Group();
|
|
69
|
-
var tile = new THREE.Mesh(new THREE.BoxGeometry(2, 0.02, 2), mat(0x3a3d45, { roughness: 0.85 }));
|
|
70
|
-
tile.position.y = 0.01;
|
|
71
|
-
tile.receiveShadow = true;
|
|
72
|
-
g.add(tile);
|
|
73
|
-
return g;
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: 'window',
|
|
78
|
-
name: 'Window',
|
|
79
|
-
category: 'structural',
|
|
80
|
-
icon: 'G',
|
|
81
|
-
gridW: 2, gridD: 1, height: 2,
|
|
82
|
-
factory: function() {
|
|
83
|
-
var g = new THREE.Group();
|
|
84
|
-
var glass = new THREE.Mesh(new THREE.PlaneGeometry(1.8, 2), mat(0x87CEEB, { emissive: 0x87CEEB, emissiveIntensity: 0.15, transparent: true, opacity: 0.6 }));
|
|
85
|
-
glass.position.y = 2;
|
|
86
|
-
g.add(glass);
|
|
87
|
-
// Frame
|
|
88
|
-
var frameM = mat(0xcccccc, { metalness: 0.8, roughness: 0.2 });
|
|
89
|
-
var top = new THREE.Mesh(new THREE.BoxGeometry(1.9, 0.04, 0.04), frameM);
|
|
90
|
-
top.position.y = 3; g.add(top);
|
|
91
|
-
var bot = new THREE.Mesh(new THREE.BoxGeometry(1.9, 0.04, 0.04), frameM);
|
|
92
|
-
bot.position.y = 1; g.add(bot);
|
|
93
|
-
return g;
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 'door',
|
|
98
|
-
name: 'Door',
|
|
99
|
-
category: 'structural',
|
|
100
|
-
icon: 'Dr',
|
|
101
|
-
gridW: 1, gridD: 1, height: 2.5,
|
|
102
|
-
factory: function() {
|
|
103
|
-
var g = new THREE.Group();
|
|
104
|
-
var door = new THREE.Mesh(new THREE.BoxGeometry(1, 2.5, 0.08), mat(0x5c3a1e, { roughness: 0.6 }));
|
|
105
|
-
door.position.y = 1.25;
|
|
106
|
-
door.castShadow = true;
|
|
107
|
-
g.add(door);
|
|
108
|
-
// Handle
|
|
109
|
-
var handle = new THREE.Mesh(new THREE.BoxGeometry(0.03, 0.15, 0.06), mat(0xcccccc, { metalness: 0.8 }));
|
|
110
|
-
handle.position.set(0.35, 1.1, 0.06);
|
|
111
|
-
g.add(handle);
|
|
112
|
-
return g;
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
// ===== FURNITURE =====
|
|
117
|
-
{
|
|
118
|
-
id: 'desk',
|
|
119
|
-
name: 'Desk',
|
|
120
|
-
category: 'furniture',
|
|
121
|
-
icon: 'Dk',
|
|
122
|
-
gridW: 2, gridD: 1, height: 0.8,
|
|
123
|
-
factory: function() {
|
|
124
|
-
var g = new THREE.Group();
|
|
125
|
-
var deskMat = mat(0x1a1a2e, { roughness: 0.3, metalness: 0.1 });
|
|
126
|
-
var legMat = mat(0x111111, { roughness: 0.4, metalness: 0.2 });
|
|
127
|
-
// Top
|
|
128
|
-
var top = new THREE.Mesh(new THREE.BoxGeometry(2, 0.05, 0.9), deskMat);
|
|
129
|
-
top.position.y = 0.76; top.castShadow = true;
|
|
130
|
-
g.add(top);
|
|
131
|
-
// Legs
|
|
132
|
-
var positions = [[-0.85, -0.35], [-0.85, 0.35], [0.85, -0.35], [0.85, 0.35]];
|
|
133
|
-
for (var i = 0; i < 4; i++) {
|
|
134
|
-
var leg = new THREE.Mesh(new THREE.BoxGeometry(0.06, 0.76, 0.06), legMat);
|
|
135
|
-
leg.position.set(positions[i][0], 0.38, positions[i][1]);
|
|
136
|
-
g.add(leg);
|
|
137
|
-
}
|
|
138
|
-
return g;
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
id: 'chair',
|
|
143
|
-
name: 'Chair',
|
|
144
|
-
category: 'furniture',
|
|
145
|
-
icon: 'Ch',
|
|
146
|
-
gridW: 1, gridD: 1, height: 1.1,
|
|
147
|
-
factory: function() {
|
|
148
|
-
var g = new THREE.Group();
|
|
149
|
-
var seatM = mat(0x333340, { roughness: 0.65 });
|
|
150
|
-
var chromeM = mat(0x888888, { metalness: 0.6, roughness: 0.3 });
|
|
151
|
-
// Seat
|
|
152
|
-
var seat = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.05, 0.4), seatM);
|
|
153
|
-
seat.position.y = 0.45; g.add(seat);
|
|
154
|
-
// Back
|
|
155
|
-
var back = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.4, 0.04), seatM);
|
|
156
|
-
back.position.set(0, 0.7, 0.18); g.add(back);
|
|
157
|
-
// Post
|
|
158
|
-
var post = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 0.4, 6), chromeM);
|
|
159
|
-
post.position.y = 0.22; g.add(post);
|
|
160
|
-
// Base
|
|
161
|
-
var base = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.17, 0.03, 12), chromeM);
|
|
162
|
-
base.position.y = 0.02; g.add(base);
|
|
163
|
-
return g;
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
id: 'sofa',
|
|
168
|
-
name: 'Sofa',
|
|
169
|
-
category: 'furniture',
|
|
170
|
-
icon: 'So',
|
|
171
|
-
gridW: 3, gridD: 1, height: 0.9,
|
|
172
|
-
factory: function() {
|
|
173
|
-
var g = new THREE.Group();
|
|
174
|
-
var sofaM = mat(0x2a2a3e, { roughness: 0.75 });
|
|
175
|
-
// Base
|
|
176
|
-
var base = new THREE.Mesh(new THREE.BoxGeometry(3, 0.35, 0.9), sofaM);
|
|
177
|
-
base.position.y = 0.2; g.add(base);
|
|
178
|
-
// Back
|
|
179
|
-
var back = new THREE.Mesh(new THREE.BoxGeometry(3, 0.5, 0.2), sofaM);
|
|
180
|
-
back.position.set(0, 0.55, -0.35); g.add(back);
|
|
181
|
-
// Arms
|
|
182
|
-
var armL = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.3, 0.9), sofaM);
|
|
183
|
-
armL.position.set(-1.4, 0.4, 0); g.add(armL);
|
|
184
|
-
var armR = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.3, 0.9), sofaM);
|
|
185
|
-
armR.position.set(1.4, 0.4, 0); g.add(armR);
|
|
186
|
-
return g;
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
id: 'bookshelf',
|
|
191
|
-
name: 'Bookshelf',
|
|
192
|
-
category: 'furniture',
|
|
193
|
-
icon: 'Bk',
|
|
194
|
-
gridW: 1, gridD: 1, height: 2.2,
|
|
195
|
-
factory: function() {
|
|
196
|
-
var g = new THREE.Group();
|
|
197
|
-
var woodM = mat(0x5a3e28, { roughness: 0.7 });
|
|
198
|
-
// Back
|
|
199
|
-
var back = new THREE.Mesh(new THREE.BoxGeometry(0.08, 2.2, 1.2), woodM);
|
|
200
|
-
back.position.y = 1.1; g.add(back);
|
|
201
|
-
// Sides
|
|
202
|
-
var sideL = new THREE.Mesh(new THREE.BoxGeometry(0.35, 2.2, 0.04), woodM);
|
|
203
|
-
sideL.position.set(0.14, 1.1, -0.58); g.add(sideL);
|
|
204
|
-
var sideR = new THREE.Mesh(new THREE.BoxGeometry(0.35, 2.2, 0.04), woodM);
|
|
205
|
-
sideR.position.set(0.14, 1.1, 0.58); g.add(sideR);
|
|
206
|
-
// Shelves
|
|
207
|
-
for (var i = 0; i < 5; i++) {
|
|
208
|
-
var shelf = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.04, 1.2), woodM);
|
|
209
|
-
shelf.position.set(0.14, 0.05 + i * 0.55, 0);
|
|
210
|
-
g.add(shelf);
|
|
211
|
-
}
|
|
212
|
-
return g;
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
id: 'coffee_table',
|
|
217
|
-
name: 'Coffee Table',
|
|
218
|
-
category: 'furniture',
|
|
219
|
-
icon: '\u2615',
|
|
220
|
-
gridW: 1, gridD: 1, height: 0.45,
|
|
221
|
-
factory: function() {
|
|
222
|
-
var g = new THREE.Group();
|
|
223
|
-
var glassM = mat(0xccddee, { transparent: true, opacity: 0.35, roughness: 0.05 });
|
|
224
|
-
var chromeM = mat(0xcccccc, { metalness: 0.8, roughness: 0.2 });
|
|
225
|
-
var top = new THREE.Mesh(new THREE.BoxGeometry(1, 0.03, 0.5), glassM);
|
|
226
|
-
top.position.y = 0.45; g.add(top);
|
|
227
|
-
for (var i = 0; i < 4; i++) {
|
|
228
|
-
var leg = new THREE.Mesh(new THREE.CylinderGeometry(0.015, 0.015, 0.42, 6), chromeM);
|
|
229
|
-
leg.position.set(((i & 1) ? 0.4 : -0.4), 0.21, ((i & 2) ? 0.2 : -0.2));
|
|
230
|
-
g.add(leg);
|
|
231
|
-
}
|
|
232
|
-
return g;
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
id: 'bar_stool',
|
|
237
|
-
name: 'Bar Stool',
|
|
238
|
-
category: 'furniture',
|
|
239
|
-
icon: 'Ch',
|
|
240
|
-
gridW: 1, gridD: 1, height: 0.8,
|
|
241
|
-
factory: function() {
|
|
242
|
-
var g = new THREE.Group();
|
|
243
|
-
var seatM = mat(0x333340, { roughness: 0.65 });
|
|
244
|
-
var chromeM = mat(0x888888, { metalness: 0.6, roughness: 0.3 });
|
|
245
|
-
var seat = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.18, 0.06, 12), seatM);
|
|
246
|
-
seat.position.y = 0.75; g.add(seat);
|
|
247
|
-
var post = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.025, 0.7, 8), chromeM);
|
|
248
|
-
post.position.y = 0.38; g.add(post);
|
|
249
|
-
var base = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.2, 0.04, 12), chromeM);
|
|
250
|
-
base.position.y = 0.04; g.add(base);
|
|
251
|
-
return g;
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
// ===== DECOR =====
|
|
256
|
-
{
|
|
257
|
-
id: 'plant',
|
|
258
|
-
name: 'Plant',
|
|
259
|
-
category: 'decor',
|
|
260
|
-
icon: 'Pl',
|
|
261
|
-
gridW: 1, gridD: 1, height: 0.8,
|
|
262
|
-
factory: function() {
|
|
263
|
-
var g = new THREE.Group();
|
|
264
|
-
var potM = mat(0x4a4a5a, { roughness: 0.8 });
|
|
265
|
-
var leafM = mat(0x2d8a4e, { roughness: 0.8 });
|
|
266
|
-
var pot = new THREE.Mesh(new THREE.CylinderGeometry(0.25, 0.2, 0.5, 12), potM);
|
|
267
|
-
pot.position.y = 0.25; g.add(pot);
|
|
268
|
-
for (var i = 0; i < 5; i++) {
|
|
269
|
-
var angle = (i / 5) * Math.PI * 2;
|
|
270
|
-
var leaf = new THREE.Mesh(new THREE.SphereGeometry(0.15, 8, 6), leafM);
|
|
271
|
-
leaf.position.set(Math.cos(angle) * 0.12, 0.6, Math.sin(angle) * 0.12);
|
|
272
|
-
leaf.scale.set(1, 0.7, 1);
|
|
273
|
-
g.add(leaf);
|
|
274
|
-
}
|
|
275
|
-
var topLeaf = new THREE.Mesh(new THREE.SphereGeometry(0.12, 8, 6), leafM);
|
|
276
|
-
topLeaf.position.y = 0.75; g.add(topLeaf);
|
|
277
|
-
return g;
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
id: 'indoor_tree',
|
|
282
|
-
name: 'Indoor Tree',
|
|
283
|
-
category: 'decor',
|
|
284
|
-
icon: 'Tr',
|
|
285
|
-
gridW: 1, gridD: 1, height: 3.5,
|
|
286
|
-
factory: function() {
|
|
287
|
-
var g = new THREE.Group();
|
|
288
|
-
var planterM = mat(0x3a3a4a, { roughness: 0.8 });
|
|
289
|
-
var trunkM = mat(0x5c3a1e, { roughness: 0.8 });
|
|
290
|
-
var leafM = mat(0x228B22, { roughness: 0.7 });
|
|
291
|
-
var planter = new THREE.Mesh(new THREE.CylinderGeometry(0.4, 0.35, 0.6, 12), planterM);
|
|
292
|
-
planter.position.y = 0.3; g.add(planter);
|
|
293
|
-
var trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.1, 2.5, 8), trunkM);
|
|
294
|
-
trunk.position.y = 1.85; g.add(trunk);
|
|
295
|
-
var sizes = [0.6, 0.5, 0.35];
|
|
296
|
-
var ys = [2.8, 3.2, 3.5];
|
|
297
|
-
for (var i = 0; i < 3; i++) {
|
|
298
|
-
var canopy = new THREE.Mesh(new THREE.SphereGeometry(sizes[i], 12, 10), leafM);
|
|
299
|
-
canopy.position.y = ys[i]; g.add(canopy);
|
|
300
|
-
}
|
|
301
|
-
return g;
|
|
302
|
-
}
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
id: 'beanbag',
|
|
306
|
-
name: 'Beanbag',
|
|
307
|
-
category: 'decor',
|
|
308
|
-
icon: 'So',
|
|
309
|
-
gridW: 1, gridD: 1, height: 0.5,
|
|
310
|
-
factory: function() {
|
|
311
|
-
var g = new THREE.Group();
|
|
312
|
-
var colors = [0xe53e3e, 0x3b82f6, 0x22c55e, 0xa855f7];
|
|
313
|
-
var color = colors[Math.floor(Math.random() * colors.length)];
|
|
314
|
-
var botM = mat(color, { roughness: 0.9 });
|
|
315
|
-
var bot = new THREE.Mesh(new THREE.SphereGeometry(0.4, 16, 12), botM);
|
|
316
|
-
bot.position.y = 0.2; bot.scale.set(1, 0.5, 1); g.add(bot);
|
|
317
|
-
var darkColor = (color & 0xfefefe) >> 1; // darken
|
|
318
|
-
var topM = new THREE.MeshStandardMaterial({ color: darkColor, roughness: 0.9 });
|
|
319
|
-
var topBag = new THREE.Mesh(new THREE.SphereGeometry(0.35, 16, 12), topM);
|
|
320
|
-
topBag.position.set(-0.05, 0.4, 0); topBag.scale.set(1, 0.6, 1); g.add(topBag);
|
|
321
|
-
return g;
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
|
|
325
|
-
// ===== TECH =====
|
|
326
|
-
{
|
|
327
|
-
id: 'monitor',
|
|
328
|
-
name: 'Monitor',
|
|
329
|
-
category: 'tech',
|
|
330
|
-
icon: 'Mo',
|
|
331
|
-
gridW: 1, gridD: 1, height: 0.5,
|
|
332
|
-
factory: function() {
|
|
333
|
-
var g = new THREE.Group();
|
|
334
|
-
var body = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.35, 0.04), mat(0x1a1a2e, { roughness: 0.3 }));
|
|
335
|
-
body.position.y = 0.35; g.add(body);
|
|
336
|
-
var screen = new THREE.Mesh(new THREE.PlaneGeometry(0.44, 0.28), mat(0x333333, { emissive: 0x111122, emissiveIntensity: 0.3 }));
|
|
337
|
-
screen.position.set(0, 0.35, 0.025); g.add(screen);
|
|
338
|
-
var stand = new THREE.Mesh(new THREE.BoxGeometry(0.06, 0.18, 0.06), mat(0x4a5568, { roughness: 0.7 }));
|
|
339
|
-
stand.position.y = 0.09; g.add(stand);
|
|
340
|
-
return g;
|
|
341
|
-
}
|
|
342
|
-
},
|
|
343
|
-
{
|
|
344
|
-
id: 'pc_tower',
|
|
345
|
-
name: 'PC Tower',
|
|
346
|
-
category: 'tech',
|
|
347
|
-
icon: 'PC',
|
|
348
|
-
gridW: 1, gridD: 1, height: 0.45,
|
|
349
|
-
factory: function() {
|
|
350
|
-
var g = new THREE.Group();
|
|
351
|
-
var caseMesh = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.45, 0.45), mat(0x111111, { roughness: 0.4 }));
|
|
352
|
-
caseMesh.position.y = 0.23; g.add(caseMesh);
|
|
353
|
-
var panel = new THREE.Mesh(new THREE.PlaneGeometry(0.18, 0.4), mat(0x58a6ff, { emissive: 0x58a6ff, emissiveIntensity: 0.3, transparent: true, opacity: 0.4 }));
|
|
354
|
-
panel.position.set(0.115, 0.23, 0); panel.rotation.y = Math.PI / 2; g.add(panel);
|
|
355
|
-
return g;
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
|
|
359
|
-
// ===== LIGHTING =====
|
|
360
|
-
{
|
|
361
|
-
id: 'floor_lamp',
|
|
362
|
-
name: 'Floor Lamp',
|
|
363
|
-
category: 'lighting',
|
|
364
|
-
icon: 'Lt',
|
|
365
|
-
gridW: 1, gridD: 1, height: 1.8,
|
|
366
|
-
factory: function() {
|
|
367
|
-
var g = new THREE.Group();
|
|
368
|
-
var metalM = mat(0x333333, { metalness: 0.3, roughness: 0.5 });
|
|
369
|
-
var base = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.18, 0.04, 12), metalM);
|
|
370
|
-
base.position.y = 0.02; g.add(base);
|
|
371
|
-
var pole = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 1.6, 8), metalM);
|
|
372
|
-
pole.position.y = 0.84; g.add(pole);
|
|
373
|
-
var shade = new THREE.Mesh(new THREE.ConeGeometry(0.18, 0.25, 12, 1, true), mat(0xddd5c0, { roughness: 0.8, side: THREE.DoubleSide }));
|
|
374
|
-
shade.position.y = 1.72; shade.rotation.x = Math.PI; g.add(shade);
|
|
375
|
-
var light = new THREE.PointLight(0xffeedd, 0.3, 4);
|
|
376
|
-
light.position.y = 1.6; g.add(light);
|
|
377
|
-
return g;
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
id: 'pendant_light',
|
|
382
|
-
name: 'Pendant Light',
|
|
383
|
-
category: 'lighting',
|
|
384
|
-
icon: 'Lt',
|
|
385
|
-
gridW: 1, gridD: 1, height: 2,
|
|
386
|
-
factory: function() {
|
|
387
|
-
var g = new THREE.Group();
|
|
388
|
-
var wire = new THREE.Mesh(new THREE.CylinderGeometry(0.008, 0.008, 1.5, 4), mat(0x333333, { roughness: 0.5 }));
|
|
389
|
-
wire.position.y = 2.25; g.add(wire);
|
|
390
|
-
var shade = new THREE.Mesh(new THREE.SphereGeometry(0.12, 12, 10), mat(0xffeedd, { emissive: 0xffeedd, emissiveIntensity: 0.4, transparent: true, opacity: 0.8 }));
|
|
391
|
-
shade.position.y = 1.5; g.add(shade);
|
|
392
|
-
var light = new THREE.PointLight(0xffeedd, 0.25, 6);
|
|
393
|
-
light.position.y = 1.4; g.add(light);
|
|
394
|
-
return g;
|
|
395
|
-
}
|
|
396
|
-
},
|
|
397
|
-
];
|
|
398
|
-
|
|
399
|
-
// Get asset by ID
|
|
400
|
-
export function getAsset(id) {
|
|
401
|
-
for (var i = 0; i < ASSETS.length; i++) {
|
|
402
|
-
if (ASSETS[i].id === id) return ASSETS[i];
|
|
403
|
-
}
|
|
404
|
-
return null;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Get assets by category
|
|
408
|
-
export function getAssetsByCategory(cat) {
|
|
409
|
-
return ASSETS.filter(function(a) { return a.category === cat; });
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Create a ghost (transparent preview) of an asset
|
|
413
|
-
export function createGhost(assetId) {
|
|
414
|
-
var asset = getAsset(assetId);
|
|
415
|
-
if (!asset) return null;
|
|
416
|
-
var group = asset.factory();
|
|
417
|
-
// Make all children transparent green
|
|
418
|
-
group.traverse(function(child) {
|
|
419
|
-
if (child.isMesh) {
|
|
420
|
-
child.material = new THREE.MeshStandardMaterial({
|
|
421
|
-
color: 0x44ff88,
|
|
422
|
-
transparent: true,
|
|
423
|
-
opacity: 0.35,
|
|
424
|
-
depthWrite: false,
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
group.userData.isGhost = true;
|
|
429
|
-
group.userData.assetId = assetId;
|
|
430
|
-
return group;
|
|
431
|
-
}
|
|
1
|
+
// Asset registry — re-exports from assets/ folder
|
|
2
|
+
// Individual asset files live in ./assets/*.js for maintainability
|
|
3
|
+
export { ASSET_CATEGORIES, ASSETS, getAsset, getAssetsByCategory, createGhost } from './assets/index.js';
|