let-them-talk 4.2.0 → 5.2.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 (39) hide show
  1. package/CHANGELOG.md +640 -540
  2. package/README.md +592 -415
  3. package/cli.js +1089 -589
  4. package/conversation-templates/autonomous-feature.json +22 -0
  5. package/conversation-templates/code-review.json +21 -11
  6. package/conversation-templates/debug-squad.json +21 -11
  7. package/conversation-templates/feature-build.json +21 -11
  8. package/conversation-templates/research-write.json +21 -11
  9. package/dashboard.html +9250 -7771
  10. package/dashboard.js +1232 -29
  11. package/office/agents.js +148 -4
  12. package/office/animation.js +68 -0
  13. package/office/assets.js +431 -0
  14. package/office/builder.js +355 -0
  15. package/office/building-interior.js +261 -0
  16. package/office/campus-env.js +119 -23
  17. package/office/car-hud.js +368 -0
  18. package/office/daynight.js +221 -0
  19. package/office/economy-hud.js +432 -0
  20. package/office/economy-ui.js +238 -0
  21. package/office/environment.js +818 -808
  22. package/office/face.js +65 -0
  23. package/office/fast-travel.js +215 -0
  24. package/office/hq-building.js +295 -0
  25. package/office/index.js +1095 -423
  26. package/office/instancing.js +160 -0
  27. package/office/lod-manager.js +165 -0
  28. package/office/multiplayer-hud.js +428 -0
  29. package/office/net-client.js +299 -0
  30. package/office/particles.js +172 -0
  31. package/office/player.js +658 -436
  32. package/office/post-processing.js +82 -0
  33. package/office/sky.js +319 -0
  34. package/office/street-furniture.js +308 -0
  35. package/office/vehicle.js +455 -0
  36. package/office/world-save.js +91 -0
  37. package/package.json +59 -59
  38. package/server.js +7190 -4685
  39. package/conversation-templates/managed-team.json +0 -12
@@ -0,0 +1,238 @@
1
+ import * as THREE from 'three';
2
+ import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
3
+ import { S } from './state.js';
4
+
5
+ // ============================================================
6
+ // ECONOMY UI — 3D upgrade shop, credit display, visual upgrades
7
+ // Phase 3: In-world economy visualization
8
+ // ============================================================
9
+
10
+ var shopBuilding = null;
11
+ var creditDisplay = null;
12
+ var upgradeEffects = {};
13
+ var currentBalance = 0;
14
+
15
+ // ============================================================
16
+ // CREDIT BALANCE DISPLAY — always visible in city
17
+ // ============================================================
18
+
19
+ export function createCreditDisplay() {
20
+ if (creditDisplay) return;
21
+
22
+ var div = document.createElement('div');
23
+ div.id = 'city-credits';
24
+ div.style.cssText = 'position:absolute;top:12px;right:12px;z-index:1000;' +
25
+ 'background:linear-gradient(135deg,rgba(30,30,40,0.9),rgba(20,20,30,0.95));' +
26
+ 'border:1px solid rgba(212,175,55,0.4);border-radius:12px;padding:8px 16px;' +
27
+ 'font-family:monospace;color:#d4af37;font-size:16px;font-weight:bold;' +
28
+ 'display:flex;align-items:center;gap:8px;backdrop-filter:blur(8px);' +
29
+ 'box-shadow:0 4px 12px rgba(0,0,0,0.4);pointer-events:none;';
30
+
31
+ var icon = document.createElement('span');
32
+ icon.textContent = '\u26A1'; // lightning bolt as credit icon
33
+ icon.style.fontSize = '20px';
34
+ div.appendChild(icon);
35
+
36
+ var amount = document.createElement('span');
37
+ amount.id = 'city-credit-amount';
38
+ amount.textContent = '0';
39
+ amount.style.fontVariantNumeric = 'tabular-nums';
40
+ div.appendChild(amount);
41
+
42
+ var label = document.createElement('span');
43
+ label.textContent = 'credits';
44
+ label.style.cssText = 'color:rgba(212,175,55,0.6);font-size:10px;text-transform:uppercase;letter-spacing:1px;';
45
+ div.appendChild(label);
46
+
47
+ var container = S.container || document.getElementById('office-3d-container');
48
+ if (container) container.appendChild(div);
49
+ creditDisplay = div;
50
+ }
51
+
52
+ export function updateCreditBalance(balance) {
53
+ currentBalance = balance;
54
+ var el = document.getElementById('city-credit-amount');
55
+ if (el) {
56
+ // Animate count up/down
57
+ var current = parseInt(el.textContent) || 0;
58
+ if (current !== balance) {
59
+ var diff = balance - current;
60
+ var steps = Math.min(Math.abs(diff), 20);
61
+ var step = diff / steps;
62
+ var i = 0;
63
+ var interval = setInterval(function() {
64
+ i++;
65
+ var val = Math.round(current + step * i);
66
+ el.textContent = val.toLocaleString();
67
+ if (i >= steps) {
68
+ el.textContent = balance.toLocaleString();
69
+ clearInterval(interval);
70
+ }
71
+ }, 30);
72
+ }
73
+ }
74
+ }
75
+
76
+ export function getCreditBalance() { return currentBalance; }
77
+
78
+ // ============================================================
79
+ // UPGRADE SHOP — 3D building in the city
80
+ // ============================================================
81
+
82
+ export function buildUpgradeShop(x, z) {
83
+ var group = new THREE.Group();
84
+
85
+ // Shop building (distinctive gold/glass)
86
+ var shopGeo = new THREE.BoxGeometry(8, 5, 8);
87
+ var shopMat = new THREE.MeshStandardMaterial({
88
+ color: 0x2a2a3a, roughness: 0.3, metalness: 0.2,
89
+ emissive: 0xd4af37, emissiveIntensity: 0.15
90
+ });
91
+ var shop = new THREE.Mesh(shopGeo, shopMat);
92
+ shop.position.set(x, 2.5, z);
93
+ shop.castShadow = true;
94
+ shop.matrixAutoUpdate = false;
95
+ shop.updateMatrix();
96
+ group.add(shop);
97
+
98
+ // Gold accent roof
99
+ var roofGeo = new THREE.ConeGeometry(6, 2, 4);
100
+ var roofMat = new THREE.MeshStandardMaterial({
101
+ color: 0xd4af37, roughness: 0.3, metalness: 0.6,
102
+ emissive: 0xd4af37, emissiveIntensity: 0.3
103
+ });
104
+ var roof = new THREE.Mesh(roofGeo, roofMat);
105
+ roof.position.set(x, 6, z);
106
+ roof.rotation.y = Math.PI / 4;
107
+ roof.castShadow = true;
108
+ roof.matrixAutoUpdate = false;
109
+ roof.updateMatrix();
110
+ group.add(roof);
111
+
112
+ // Neon sign
113
+ var signDiv = document.createElement('div');
114
+ signDiv.textContent = '\u26A1 UPGRADE SHOP';
115
+ signDiv.style.cssText = 'color:#ffd700;font-size:12px;font-weight:bold;' +
116
+ 'text-shadow:0 0 10px rgba(255,215,0,0.8),0 0 20px rgba(255,215,0,0.4);' +
117
+ 'font-family:monospace;letter-spacing:2px;';
118
+ var signObj = new CSS2DObject(signDiv);
119
+ signObj.position.set(x, 8, z);
120
+ group.add(signObj);
121
+
122
+ // Rotating crystal above shop
123
+ var crystalGeo = new THREE.OctahedronGeometry(0.8);
124
+ var crystalMat = new THREE.MeshStandardMaterial({
125
+ color: 0xffd700, emissive: 0xffd700, emissiveIntensity: 0.6,
126
+ transparent: true, opacity: 0.8, roughness: 0.1, metalness: 0.5
127
+ });
128
+ var crystal = new THREE.Mesh(crystalGeo, crystalMat);
129
+ crystal.position.set(x, 9, z);
130
+ group.add(crystal);
131
+
132
+ // Store reference for animation
133
+ group.userData.crystal = crystal;
134
+ group.userData.shopPos = { x: x, z: z };
135
+
136
+ S.furnitureGroup.add(group);
137
+ shopBuilding = group;
138
+
139
+ return group;
140
+ }
141
+
142
+ // ============================================================
143
+ // BUILDING UPGRADE EFFECTS — glow when upgraded
144
+ // ============================================================
145
+
146
+ export function applyUpgradeEffect(buildingData, level) {
147
+ var key = buildingData.gridX + '_' + buildingData.gridZ;
148
+
149
+ // Find the building mesh in the scene
150
+ S.furnitureGroup.traverse(function(child) {
151
+ if (child.isMesh && child.position &&
152
+ Math.abs(child.position.x - buildingData.x) < 1 &&
153
+ Math.abs(child.position.z - buildingData.z) < 1 &&
154
+ child.position.y > 0) {
155
+
156
+ // Increase emissive glow based on upgrade level
157
+ if (child.material && child.material.emissiveIntensity !== undefined) {
158
+ child.material.emissiveIntensity = 0.1 + level * 0.15;
159
+ child.material.needsUpdate = true;
160
+ }
161
+
162
+ // Scale up slightly
163
+ var scaleBonus = 1 + level * 0.05;
164
+ child.scale.set(scaleBonus, scaleBonus, scaleBonus);
165
+ child.updateMatrix();
166
+
167
+ upgradeEffects[key] = { mesh: child, level: level };
168
+ }
169
+ });
170
+ }
171
+
172
+ // ============================================================
173
+ // SHOP ANIMATION — crystal rotation
174
+ // ============================================================
175
+
176
+ export function updateEconomyUI(dt) {
177
+ if (shopBuilding && shopBuilding.userData.crystal) {
178
+ var crystal = shopBuilding.userData.crystal;
179
+ crystal.rotation.y += dt * 1.5;
180
+ crystal.rotation.x += dt * 0.5;
181
+ crystal.position.y = 9 + Math.sin(Date.now() * 0.002) * 0.3;
182
+ }
183
+ }
184
+
185
+ // ============================================================
186
+ // FETCH & SYNC BALANCE
187
+ // ============================================================
188
+
189
+ var _balancePollInterval = null;
190
+
191
+ export function startBalancePolling(intervalMs) {
192
+ intervalMs = intervalMs || 5000;
193
+ if (_balancePollInterval) clearInterval(_balancePollInterval);
194
+
195
+ function fetchBalance() {
196
+ fetch('/api/city/economy')
197
+ .then(function(r) { return r.json(); })
198
+ .then(function(data) {
199
+ if (data && typeof data.balance === 'number') {
200
+ updateCreditBalance(data.balance);
201
+ }
202
+ })
203
+ .catch(function() {}); // silent fail
204
+ }
205
+
206
+ fetchBalance();
207
+ _balancePollInterval = setInterval(fetchBalance, intervalMs);
208
+ }
209
+
210
+ export function stopBalancePolling() {
211
+ if (_balancePollInterval) {
212
+ clearInterval(_balancePollInterval);
213
+ _balancePollInterval = null;
214
+ }
215
+ }
216
+
217
+ // ============================================================
218
+ // CLEANUP
219
+ // ============================================================
220
+
221
+ export function disposeEconomyUI() {
222
+ stopBalancePolling();
223
+
224
+ if (creditDisplay && creditDisplay.parentElement) {
225
+ creditDisplay.parentElement.removeChild(creditDisplay);
226
+ creditDisplay = null;
227
+ }
228
+
229
+ if (shopBuilding) {
230
+ shopBuilding.traverse(function(child) {
231
+ if (child.geometry) child.geometry.dispose();
232
+ if (child.material) child.material.dispose();
233
+ });
234
+ shopBuilding = null;
235
+ }
236
+
237
+ upgradeEffects = {};
238
+ }