morfeo 0.6.4 → 0.6.5

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.
@@ -0,0 +1,761 @@
1
+ // Segundo lote de piezas hechas en código: ciencia y cuerpo, accesorios de consola, servicios de casa y ciudad,
2
+ // vehículos y objetos de escuela. Son los huecos que quedaban al buscar en todas las bibliotecas libres.
3
+ // {tipo: 'modelo', forma: 'atomo'} {tipo: 'recurso', buscar: 'tanque de gas'}
4
+ // Cada pieza mide ~2 unidades, viene centrada y solo depende de `t`.
5
+ import React, {useMemo} from 'react';
6
+ import * as THREE from 'three';
7
+ import {ACERO, Aro, Aspas, C, COBRE, E, Helice, LATON, Mat, ORO, Tubo, Y, type M, type V3} from './objetos-ingenieria';
8
+
9
+ export const OBJETOS_CIENCIA = [
10
+ // ciencia y cuerpo
11
+ 'atomo', 'molecula', 'adn', 'celula', 'virus', 'cerebro', 'neurona', 'pulmon', 'ojo', 'diente', 'hueso', 'jeringa', 'matraz', 'telescopio', 'iman',
12
+ 'sol', 'tierra', 'volcan', 'tornado', 'iceberg', 'agujero_negro',
13
+ // consola y tecnología
14
+ 'disco', 'usb', 'tarjeta_sd', 'cable_hdmi', 'microfono', 'visor_vr', 'cargador', 'dron',
15
+ // casa y ciudad
16
+ 'tanque_gas', 'calentador_solar', 'termostato', 'detector_humo', 'camara_seguridad', 'antena_celular', 'presa', 'torre_enfriamiento', 'ascensor', 'fusible', 'fibra_optica', 'buzon',
17
+ // transporte
18
+ 'autobus', 'helicoptero', 'submarino', 'bicicleta',
19
+ // escuela y objetos
20
+ 'lapiz', 'regla', 'dado', 'ancla', 'paraguas',
21
+ ] as const;
22
+
23
+ /** Esfera aplastada o estirada. `s` = escala por eje. */
24
+ const Ov: React.FC<{p?: V3; s: V3; rad?: number; c: string; m?: number; r?: number; e?: number; o?: number; rot?: V3}> = ({p = [0, 0, 0], s, rad = 1, rot, ...mat}) => (
25
+ <mesh position={p} scale={s} rotation={rot}>
26
+ <sphereGeometry args={[rad, 28, 18]} />
27
+ <Mat {...mat} />
28
+ </mesh>
29
+ );
30
+ /** Cono de pie. */
31
+ const Cono: React.FC<{p?: V3; rad: number; h: number; c: string; m?: number; r?: number; e?: number; o?: number; rot?: V3; seg?: number}> = ({p = [0, 0, 0], rad, h, rot, seg = 28, ...mat}) => (
32
+ <mesh position={p} rotation={rot}>
33
+ <coneGeometry args={[rad, h, seg]} />
34
+ <Mat {...mat} />
35
+ </mesh>
36
+ );
37
+ const azar = (n: number) => {
38
+ const x = Math.sin(n * 127.1) * 43758.5453;
39
+ return x - Math.floor(x);
40
+ };
41
+ /** Puntos repartidos sobre una esfera (espiral de Fibonacci). */
42
+ const enEsfera = (n: number, rad: number): V3[] =>
43
+ Array.from({length: n}, (_, i) => {
44
+ const y = 1 - (i / (n - 1)) * 2;
45
+ const r = Math.sqrt(1 - y * y);
46
+ const a = i * 2.39996;
47
+ return [Math.cos(a) * r * rad, y * rad, Math.sin(a) * r * rad];
48
+ });
49
+
50
+ export const ObjetoCiencia: React.FC<{forma: string; t: number; opciones?: Record<string, any>} & M> = ({forma, t, opciones: o = {}, color}) => {
51
+ const giro = t * (o.velocidad ?? 1) * Math.PI * 2;
52
+ const k = (c: string) => color ?? c;
53
+ const pico = useMemo(() => enEsfera(26, 0.78), []);
54
+ switch (forma) {
55
+ // ------------------------------------------------------------ ciencia y cuerpo
56
+ case 'atomo':
57
+ return (
58
+ <group>
59
+ {[[0.12, 0.05, 0], [-0.1, 0.08, 0.05], [0, -0.12, 0.06], [0.03, 0.02, -0.13]].map((p, i) => (
60
+ <E key={i} p={p as V3} rad={0.17} c={i % 2 ? '#3D7BFF' : k('#E5484D')} r={0.3} />
61
+ ))}
62
+ {[0, 1, 2].map((i) => (
63
+ <group key={i} rotation={[Math.PI / 2, 0, 0]}>
64
+ <group rotation={[0, (i * Math.PI) / 3, 0]}>
65
+ <group rotation={[1.15, 0, 0]}>
66
+ <Aro rad={0.95} tubo={0.015} c="#C9D3E3" m={0.5} r={0.3} />
67
+ <E p={[Math.cos(giro * 0.5 + i * 2.1) * 0.95, Math.sin(giro * 0.5 + i * 2.1) * 0.95, 0]} rad={0.08} c="#FFD23F" e={0.6} r={0.2} />
68
+ </group>
69
+ </group>
70
+ </group>
71
+ ))}
72
+ </group>
73
+ );
74
+ case 'molecula':
75
+ return (
76
+ <group rotation={[0, 0, 0]}>
77
+ <E rad={0.55} c={k('#E5484D')} r={0.25} />
78
+ {[-1, 1].map((l) => (
79
+ <group key={l} rotation={[0, 0, l * 0.92]}>
80
+ <Y p={[0, -0.6, 0]} rad={0.08} h={0.6} c="#D9DEE6" r={0.4} />
81
+ <E p={[0, -0.95, 0]} rad={0.36} c="#F4F6F8" r={0.25} />
82
+ </group>
83
+ ))}
84
+ </group>
85
+ );
86
+ case 'adn':
87
+ return (
88
+ <group rotation={[0, giro * 0.15, 0.25]}>
89
+ {Array.from({length: 14}, (_, i) => {
90
+ const a = i * 0.55;
91
+ const y = -1.05 + i * 0.16;
92
+ return (
93
+ <group key={i} position={[0, y, 0]} rotation={[0, a, 0]}>
94
+ <E p={[0.42, 0, 0]} rad={0.1} c={k('#3D7BFF')} r={0.3} />
95
+ <E p={[-0.42, 0, 0]} rad={0.1} c="#E5484D" r={0.3} />
96
+ <Y eje="x" p={[0.2, 0, 0]} rad={0.035} h={0.4} c={['#FFD23F', '#3DDC84'][i % 2]} r={0.4} />
97
+ <Y eje="x" p={[-0.2, 0, 0]} rad={0.035} h={0.4} c={['#3DDC84', '#FFD23F'][i % 2]} r={0.4} />
98
+ </group>
99
+ );
100
+ })}
101
+ </group>
102
+ );
103
+ case 'celula':
104
+ return (
105
+ <group>
106
+ <Ov s={[1, 0.85, 0.9]} c={k('#7FD4C1')} r={0.2} o={0.45} />
107
+ <E p={[0.1, 0.05, 0]} rad={0.36} c="#7A4FD6" r={0.35} />
108
+ <E p={[0.16, 0.1, 0.2]} rad={0.14} c="#4B2FA0" r={0.35} />
109
+ {[[-0.5, 0.3, 0.2], [-0.45, -0.3, 0.1], [0.55, -0.35, 0.15], [0.5, 0.45, -0.1]].map((p, i) => (
110
+ <Ov key={i} p={p as V3} s={[0.2, 0.1, 0.1]} rot={[0, 0, i * 0.9]} c="#FF8A3D" r={0.4} />
111
+ ))}
112
+ {[[-0.1, -0.5, 0.3], [0.3, -0.1, 0.55], [-0.3, 0.5, -0.2]].map((p, i) => (
113
+ <E key={i} p={p as V3} rad={0.07} c="#FFD23F" r={0.4} />
114
+ ))}
115
+ </group>
116
+ );
117
+ case 'virus':
118
+ return (
119
+ <group rotation={[0, giro * 0.1, 0]}>
120
+ <E rad={0.7} c={k('#3DBE7B')} r={0.55} />
121
+ {pico.map((p, i) => (
122
+ <group key={i} position={p} quaternion={new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), new THREE.Vector3(...p).normalize())}>
123
+ <Y p={[0, 0.06, 0]} rad={0.035} h={0.22} c="#E5484D" r={0.5} seg={8} />
124
+ <E p={[0, 0.2, 0]} rad={0.08} c="#E5484D" r={0.45} />
125
+ </group>
126
+ ))}
127
+ </group>
128
+ );
129
+ case 'cerebro':
130
+ return (
131
+ <group>
132
+ {[-1, 1].map((l) => (
133
+ <group key={l} position={[l * 0.36, 0.1, 0]}>
134
+ <Ov s={[0.5, 0.62, 0.85]} c={k('#F2A0B0')} r={0.5} />
135
+ {Array.from({length: 22}, (_, i) => (
136
+ <Ov key={i} p={[(azar(i * 3.1) - 0.5) * 0.55, (azar(i * 5.7) - 0.3) * 0.8, (azar(i * 7.9) - 0.5) * 1.3]} s={[0.22, 0.16, 0.26]} rot={[azar(i) * 3, azar(i * 2) * 3, 0]} c={k(['#F2A0B0', '#EC8FA2', '#F6B3C0'][i % 3])} r={0.5} />
137
+ ))}
138
+ </group>
139
+ ))}
140
+ <Ov p={[0, -0.5, -0.45]} s={[0.4, 0.28, 0.4]} c="#E88A9C" r={0.5} />
141
+ <Y p={[0, -0.75, -0.25]} rot={[0.3, 0, 0]} rad={[0.13, 0.09]} h={0.45} c="#F0C9B8" r={0.5} />
142
+ </group>
143
+ );
144
+ case 'neurona':
145
+ return (
146
+ <group position={[-0.5, 0.2, 0]}>
147
+ <E rad={0.34} c={k('#7A8CFF')} r={0.35} />
148
+ <E rad={0.15} p={[0.05, 0.05, 0.25]} c="#4B58C7" r={0.35} />
149
+ {[0.6, 1.5, 2.4, 3.3, 4.2, 5.2].map((a, i) => (
150
+ <Tubo key={i} pts={[[Math.cos(a) * 0.3, Math.sin(a) * 0.3, 0], [Math.cos(a + 0.2) * 0.6, Math.sin(a + 0.2) * 0.6, 0.05], [Math.cos(a - 0.15) * 0.85, Math.sin(a - 0.15) * 0.85, -0.05]]} rad={0.04} c={k('#7A8CFF')} r={0.4} />
151
+ ))}
152
+ <Tubo pts={[[0.3, -0.1, 0], [0.8, -0.3, 0], [1.3, -0.25, 0], [1.75, -0.5, 0]]} rad={0.05} c={k('#7A8CFF')} r={0.4} />
153
+ {[0.75, 1.1, 1.45].map((x, i) => (
154
+ <Ov key={x} p={[x, -0.29 - i * 0.02, 0]} s={[0.16, 0.1, 0.1]} c="#FFD23F" r={0.4} />
155
+ ))}
156
+ {[-0.3, 0, 0.3].map((d) => (
157
+ <E key={d} p={[1.9, -0.55 + d, 0]} rad={0.07} c="#FF8A3D" e={0.3 + 0.5 * Math.max(0, Math.sin(t * 5 + d * 4))} />
158
+ ))}
159
+ </group>
160
+ );
161
+ case 'pulmon':
162
+ return (
163
+ <group>
164
+ <Y p={[0, 0.75, 0]} rad={0.1} h={0.6} c="#F0D7CC" r={0.5} />
165
+ {[-1, 1].map((l) => (
166
+ <group key={l}>
167
+ <Y p={[l * 0.18, 0.4, 0]} rot={[0, 0, l * -0.9]} rad={0.07} h={0.42} c="#F0D7CC" r={0.5} />
168
+ <Ov p={[l * 0.52, -0.15, 0]} s={[0.42 * (1 + 0.04 * Math.sin(t * 2)), 0.85 * (1 + 0.03 * Math.sin(t * 2)), 0.4]} rot={[0, 0, l * 0.12]} c={k('#E8798A')} r={0.5} />
169
+ <Ov p={[l * 0.42, -0.6, 0.05]} s={[0.36, 0.42, 0.36]} c={k('#DE6B7D')} r={0.5} />
170
+ </group>
171
+ ))}
172
+ </group>
173
+ );
174
+ case 'ojo':
175
+ return (
176
+ <group rotation={[0, Math.sin(t * 1.3) * 0.25, 0]}>
177
+ <E rad={0.9} c="#F7F5F0" r={0.2} />
178
+ <Ov p={[0, 0, 0.62]} s={[0.46, 0.46, 0.3]} c={k('#3D8BD6')} r={0.25} />
179
+ <Ov p={[0, 0, 0.82]} s={[0.22, 0.22, 0.12]} c="#101114" r={0.2} />
180
+ <E p={[0.14, 0.16, 0.9]} rad={0.05} c="#FFFFFF" e={0.6} />
181
+ </group>
182
+ );
183
+ case 'diente':
184
+ return (
185
+ <group>
186
+ <Ov p={[0, 0.35, 0]} s={[0.68, 0.55, 0.55]} c={k('#FAF8F2')} r={0.2} />
187
+ {[-0.3, 0.3].map((x) => (
188
+ <E key={x} p={[x, 0.78, 0]} rad={0.24} c={k('#FAF8F2')} r={0.2} />
189
+ ))}
190
+ {[-1, 1].map((l) => (
191
+ <Cono key={l} p={[l * 0.3, -0.5, 0]} rot={[Math.PI, 0, l * 0.12]} rad={0.26} h={1.2} c="#F1EBDD" r={0.35} />
192
+ ))}
193
+ </group>
194
+ );
195
+ case 'hueso':
196
+ return (
197
+ <group rotation={[0, 0, 0.6]}>
198
+ <Y rad={0.15} h={1.5} c={k('#F4EFE3')} r={0.5} />
199
+ {[-1, 1].map((ly) => [-1, 1].map((lx) => <E key={`${ly}${lx}`} p={[lx * 0.17, ly * 0.82, 0]} rad={0.24} c={k('#F4EFE3')} r={0.5} />))}
200
+ </group>
201
+ );
202
+ case 'jeringa': {
203
+ const lleno = Math.max(0, Math.min(1, o.nivel ?? 0.6));
204
+ return (
205
+ <group rotation={[0, 0, -0.7]}>
206
+ <Y rad={0.24} h={1.3} c="#EAF4FF" r={0.1} o={0.35} />
207
+ <Y p={[0, -0.65 + 0.6 * lleno, 0]} rad={0.21} h={1.2 * lleno} c={k('#5AC8FA')} r={0.2} o={0.8} />
208
+ <Y p={[0, -0.6 + 1.2 * lleno, 0]} rad={0.22} h={0.1} c="#22242A" />
209
+ <Y p={[0, 0.25 + 0.6 * lleno, 0]} rad={0.05} h={1.3 - 1.2 * (1 - lleno) * 0} c="#DDE3EA" r={0.4} />
210
+ <Y p={[0, 0.95 + 0.6 * lleno, 0]} rad={0.26} h={0.06} c="#DDE3EA" r={0.4} />
211
+ <Y p={[0, 0.67, 0]} rad={0.36} h={0.05} c="#DDE3EA" r={0.4} />
212
+ <Y p={[0, -0.75, 0]} rad={[0.1, 0.05]} h={0.2} c="#3D7BFF" r={0.4} />
213
+ <Y p={[0, -1.15, 0]} rad={0.014} h={0.6} {...ACERO} />
214
+ </group>
215
+ );
216
+ }
217
+ case 'matraz': {
218
+ const c = k('#3DDC84');
219
+ return (
220
+ <group position={[0, -0.1, 0]}>
221
+ <Cono p={[0, -0.25, 0]} rad={0.85} h={1.3} c="#EAF4FF" r={0.08} o={0.28} />
222
+ <Y p={[0, -0.62, 0]} rad={[0.5, 0.82]} h={0.5} c={c} r={0.2} o={0.85} e={0.15} />
223
+ <Y p={[0, 0.65, 0]} rad={0.2} h={0.7} c="#EAF4FF" r={0.08} o={0.28} />
224
+ <Aro p={[0, 1.0, 0]} rot={[Math.PI / 2, 0, 0]} rad={0.21} tubo={0.035} c="#EAF4FF" r={0.1} o={0.5} />
225
+ {[0, 1, 2].map((i) => {
226
+ const f = (t * 0.5 + i / 3) % 1;
227
+ return <E key={i} p={[-0.2 + i * 0.2, -0.75 + f * 0.6, 0.1]} rad={0.05 + i * 0.012} c="#FFFFFF" o={0.7 * (1 - f)} />;
228
+ })}
229
+ </group>
230
+ );
231
+ }
232
+ case 'telescopio':
233
+ return (
234
+ <group>
235
+ <group position={[0, 0.35, 0]} rotation={[0, 0, 0.6]}>
236
+ <Y eje="x" rad={0.22} h={1.5} c={k('#F2F3F5')} r={0.35} />
237
+ <Y eje="x" p={[0.8, 0, 0]} rad={0.26} h={0.14} c="#22242A" r={0.4} />
238
+ <Y eje="x" p={[-0.9, 0, 0]} rad={0.12} h={0.35} c="#22242A" r={0.4} />
239
+ <Y eje="x" p={[0.1, 0.3, 0]} rad={0.06} h={0.6} c="#22242A" r={0.4} />
240
+ </group>
241
+ {[0, 1, 2].map((i) => (
242
+ <Y key={i} p={[Math.cos((i * Math.PI * 2) / 3) * 0.33, -0.5, Math.sin((i * Math.PI * 2) / 3) * 0.33]} rot={[Math.sin((i * Math.PI * 2) / 3) * 0.4, 0, -Math.cos((i * Math.PI * 2) / 3) * 0.4]} rad={0.035} h={1.4} {...ACERO} />
243
+ ))}
244
+ <E p={[0, 0.2, 0]} rad={0.1} c="#22242A" />
245
+ </group>
246
+ );
247
+ case 'iman':
248
+ return (
249
+ <group rotation={[0, 0, Math.PI]}>
250
+ <Aro p={[0, -0.2, 0]} rot={[0, 0, 0]} rad={0.6} tubo={0.22} arco={Math.PI} c={k('#D7372F')} r={0.35} />
251
+ {[-1, 1].map((l) => (
252
+ <group key={l}>
253
+ <Y p={[l * 0.6, -0.5, 0]} rad={0.22} h={0.6} c={k('#D7372F')} r={0.35} />
254
+ <Y p={[l * 0.6, -0.95, 0]} rad={0.22} h={0.3} c="#DDE3EA" m={0.7} r={0.3} />
255
+ </group>
256
+ ))}
257
+ </group>
258
+ );
259
+ case 'sol':
260
+ return (
261
+ <group>
262
+ <E rad={0.72} c={k('#FFC93C')} e={0.9} r={0.4} />
263
+ {Array.from({length: 12}, (_, i) => (
264
+ <group key={i} rotation={[0, 0, (i / 12) * Math.PI * 2 + giro * 0.05]}>
265
+ <Cono p={[0, 0.98 + 0.04 * Math.sin(t * 3 + i), 0]} rad={0.1} h={i % 2 ? 0.3 : 0.44} c="#FFB020" e={0.8} seg={10} />
266
+ </group>
267
+ ))}
268
+ </group>
269
+ );
270
+ case 'tierra':
271
+ return (
272
+ <group rotation={[0.3, giro * 0.08, 0.2]}>
273
+ <E rad={0.95} c={k('#2F7FD6')} r={0.45} />
274
+ {[[0.3, 0.5, 0.74, 0.42, 0.3], [-0.5, 0.2, 0.78, 0.3, 0.42], [0.1, -0.45, 0.83, 0.26, 0.34], [-0.75, -0.3, -0.5, 0.36, 0.3], [0.6, 0.1, -0.73, 0.4, 0.5], [0.1, 0.75, -0.57, 0.3, 0.22], [-0.2, -0.7, -0.6, 0.28, 0.24]].map(([x, y, z, a, b], i) => (
275
+ <Ov key={i} p={[x, y, z]} s={[a, b, a]} rad={0.5} c="#3DBE6A" r={0.6} />
276
+ ))}
277
+ <Ov p={[0, 0.93, 0]} s={[0.4, 0.12, 0.4]} rad={1} c="#F4F8FB" r={0.4} />
278
+ <Ov p={[0, -0.93, 0]} s={[0.36, 0.12, 0.36]} rad={1} c="#F4F8FB" r={0.4} />
279
+ </group>
280
+ );
281
+ case 'volcan':
282
+ return (
283
+ <group position={[0, -0.2, 0]}>
284
+ <Y p={[0, -0.2, 0]} rad={[0.32, 1.15]} h={1.4} c={k('#5A4A42')} r={0.9} seg={9} />
285
+ <Y p={[0, 0.48, 0]} rad={[0.26, 0.33]} h={0.08} c="#FF5A1F" e={0.9} seg={9} />
286
+ {[0.3, 1.6, 3.1, 4.5].map((a, i) => (
287
+ <Tubo key={i} pts={[[Math.cos(a) * 0.28, 0.46, Math.sin(a) * 0.28], [Math.cos(a) * 0.5, 0.05, Math.sin(a) * 0.5], [Math.cos(a + 0.2) * 0.75, -0.45, Math.sin(a + 0.2) * 0.75]]} rad={0.06} c="#FF5A1F" e={0.8} />
288
+ ))}
289
+ {[0, 1, 2, 3].map((i) => {
290
+ const f = (t * 0.35 + i / 4) % 1;
291
+ return <E key={i} p={[Math.sin(i * 2.3) * 0.25 * f, 0.65 + f * 0.9, Math.cos(i * 1.7) * 0.15 * f]} rad={0.18 + f * 0.2} c="#8C8782" r={1} o={0.65 * (1 - f)} />;
292
+ })}
293
+ </group>
294
+ );
295
+ case 'tornado':
296
+ return (
297
+ <group>
298
+ {Array.from({length: 9}, (_, i) => {
299
+ const y = -1 + i * 0.25;
300
+ const r = 0.14 + i * 0.1;
301
+ return <Aro key={i} p={[Math.sin(t * 2 + i * 0.6) * 0.06 * i * 0.3, y, Math.cos(t * 2 + i * 0.6) * 0.04]} rot={[Math.PI / 2, 0, giro * 0.6 + i]} rad={r} tubo={0.07 + i * 0.006} arco={Math.PI * 1.75} c={k('#9AA4B2')} r={0.9} o={0.85} />;
302
+ })}
303
+ </group>
304
+ );
305
+ case 'iceberg':
306
+ return (
307
+ <group>
308
+ <Cono p={[0, 0.45, 0]} rad={0.6} h={0.9} c={k('#EAF6FF')} r={0.35} seg={6} />
309
+ <Cono p={[0.35, 0.3, 0.1]} rad={0.35} h={0.6} c="#D6ECFA" r={0.35} seg={5} />
310
+ <Cono p={[0, -0.55, 0]} rot={[Math.PI, 0, 0]} rad={0.95} h={1.1} c="#8ED0F2" r={0.3} o={0.75} seg={6} />
311
+ <Y rad={1.2} h={0.02} c="#2F8FD6" r={0.15} o={0.45} seg={40} />
312
+ </group>
313
+ );
314
+ case 'agujero_negro':
315
+ return (
316
+ <group rotation={[1.15, 0, 0.25]}>
317
+ <E rad={0.5} c="#050507" r={1} />
318
+ {[0.7, 0.86, 1.02].map((r, i) => (
319
+ <Aro key={r} rot={[0, 0, giro * (0.2 - i * 0.05)]} rad={r} tubo={0.07 - i * 0.012} arco={Math.PI * 1.9} c={k(['#FFE9A8', '#FFB23F', '#FF6A1F'][i])} e={1 - i * 0.15} r={0.4} />
320
+ ))}
321
+ </group>
322
+ );
323
+ // ------------------------------------------------------------ consola y tecnología
324
+ case 'disco':
325
+ return (
326
+ <group rotation={[-0.5, giro * 0.2, 0]}>
327
+ <mesh>
328
+ <ringGeometry args={[0.16, 1, 64]} />
329
+ <meshStandardMaterial color={k('#D9DEE8')} metalness={0.95} roughness={0.12} side={THREE.DoubleSide} />
330
+ </mesh>
331
+ {[0.4, 0.62, 0.84].map((r, i) => (
332
+ <mesh key={r} position={[0, 0, 0.004]}>
333
+ <ringGeometry args={[r, r + 0.12, 64, 1, i * 1.3, 1.1]} />
334
+ <meshStandardMaterial color={['#7FD4FF', '#C79BFF', '#9BFFC4'][i]} metalness={0.9} roughness={0.15} transparent opacity={0.55} side={THREE.DoubleSide} />
335
+ </mesh>
336
+ ))}
337
+ <Aro rad={0.2} tubo={0.03} c="#F4F6F8" r={0.2} o={0.6} />
338
+ </group>
339
+ );
340
+ case 'usb':
341
+ return (
342
+ <group rotation={[0, 0, 0.5]}>
343
+ <C p={[0, -0.25, 0]} s={[0.7, 1.3, 0.26]} c={k('#22242A')} r={0.4} />
344
+ <C p={[0, 0.72, 0]} s={[0.55, 0.65, 0.2]} {...ACERO} />
345
+ {[-0.13, 0.13].map((x) => (
346
+ <C key={x} p={[x, 0.85, 0.105]} s={[0.12, 0.12, 0.01]} c="#15161A" />
347
+ ))}
348
+ <E p={[0, -0.7, 0.14]} rad={0.04} c="#3D7BFF" e={0.5 + 0.5 * Math.sin(t * 6)} />
349
+ </group>
350
+ );
351
+ case 'tarjeta_sd':
352
+ return (
353
+ <group rotation={[-0.3, 0, 0]}>
354
+ <C s={[1.3, 1.7, 0.08]} c={k('#22242A')} r={0.45} />
355
+ <C p={[0, 0.25, 0.045]} s={[1.0, 0.7, 0.005]} c="#E0352B" r={0.5} />
356
+ <C p={[0, -0.45, 0.045]} s={[1.0, 0.3, 0.005]} c="#F4F6F8" r={0.5} />
357
+ {Array.from({length: 7}, (_, i) => (
358
+ <C key={i} p={[-0.45 + i * 0.15, 0.62, -0.045]} s={[0.09, 0.36, 0.005]} {...ORO} />
359
+ ))}
360
+ </group>
361
+ );
362
+ case 'cable_hdmi':
363
+ return (
364
+ <group>
365
+ <Tubo pts={[[-0.9, -0.5, 0], [-0.5, 0.3, 0.1], [0.1, -0.3, -0.1], [0.55, 0.1, 0]]} rad={0.07} c="#1B1C22" r={0.6} />
366
+ <group position={[0.95, 0.42, 0]} rotation={[0, 0, 0.62]}>
367
+ <C s={[0.7, 0.5, 0.24]} c={k('#22242A')} r={0.45} />
368
+ <C p={[0.5, 0, 0]} s={[0.36, 0.4, 0.14]} {...ACERO} />
369
+ <C p={[0.69, 0, 0]} s={[0.01, 0.3, 0.07]} {...ORO} />
370
+ </group>
371
+ </group>
372
+ );
373
+ case 'microfono':
374
+ return (
375
+ <group>
376
+ <Ov p={[0, 0.7, 0]} s={[0.36, 0.42, 0.36]} c={k('#3A3D45')} m={0.7} r={0.5} />
377
+ {[0.55, 0.7, 0.85].map((y) => (
378
+ <Aro key={y} p={[0, y, 0]} rot={[Math.PI / 2, 0, 0]} rad={0.36 * Math.sqrt(1 - ((y - 0.7) / 0.42) ** 2)} tubo={0.015} {...ACERO} />
379
+ ))}
380
+ <Y p={[0, 0.3, 0]} rad={0.37} h={0.08} {...ACERO} />
381
+ <Y p={[0, -0.25, 0]} rad={[0.2, 0.15]} h={1.1} c="#22242A" r={0.45} />
382
+ <Y p={[0, -0.9, 0]} rad={0.06} h={0.3} {...ACERO} />
383
+ <Y p={[0, -1.05, 0]} rad={0.55} h={0.07} c="#22242A" r={0.45} />
384
+ </group>
385
+ );
386
+ case 'visor_vr':
387
+ return (
388
+ <group>
389
+ <C s={[1.7, 0.85, 0.7]} c={k('#F2F3F5')} r={0.35} />
390
+ <C p={[0, 0, 0.36]} s={[1.6, 0.75, 0.04]} c="#15161A" r={0.2} />
391
+ {[-0.4, 0.4].map((x) => (
392
+ <Y key={x} eje="z" p={[x, 0, 0.385]} rad={0.2} h={0.02} c="#2B6FD6" e={0.4} r={0.1} />
393
+ ))}
394
+ <Aro p={[0, 0, -0.75]} rot={[Math.PI / 2, 0, 0]} rad={0.85} tubo={0.06} arco={Math.PI} c="#22242A" r={0.6} />
395
+ </group>
396
+ );
397
+ case 'cargador':
398
+ return (
399
+ <group>
400
+ <C p={[0, 0.2, 0]} s={[1.0, 1.0, 0.6]} c={k('#F4F5F7')} r={0.35} />
401
+ {[-0.2, 0.2].map((x) => (
402
+ <C key={x} p={[x, 0.95, 0]} s={[0.05, 0.5, 0.22]} {...ACERO} />
403
+ ))}
404
+ <Tubo pts={[[0, -0.3, 0], [0.05, -0.7, 0.1], [0.5, -0.9, 0], [0.85, -0.6, -0.1]]} rad={0.05} c="#F4F5F7" r={0.45} />
405
+ <C p={[0.95, -0.5, -0.12]} rot={[0, 0, 0.8]} s={[0.3, 0.2, 0.1]} c="#DDE0E5" r={0.4} />
406
+ <E p={[0.35, 0.55, 0.31]} rad={0.035} c="#3DDC84" e={1} />
407
+ </group>
408
+ );
409
+ case 'dron':
410
+ return (
411
+ <group rotation={[0.25, 0, 0]} position={[0, Math.sin(t * 2.5) * 0.06, 0]}>
412
+ <C s={[0.7, 0.2, 0.5]} c={k('#22242A')} r={0.4} />
413
+ <Y eje="z" p={[0, -0.05, 0.28]} rad={0.08} h={0.1} c="#15161A" />
414
+ {[-1, 1].map((lx) =>
415
+ [-1, 1].map((lz) => (
416
+ <group key={`${lx}${lz}`}>
417
+ <C p={[lx * 0.5, 0, lz * 0.4]} rot={[0, lx * lz * -0.67, 0]} s={[0.75, 0.06, 0.08]} c="#3A3D45" r={0.5} />
418
+ <Y p={[lx * 0.82, 0.08, lz * 0.66]} rad={0.07} h={0.16} c="#3A3D45" />
419
+ <group position={[lx * 0.82, 0.18, lz * 0.66]} rotation={[Math.PI / 2, 0, 0]}>
420
+ <Aspas n={2} rad={0.34} giro={giro * 5 * lx * lz} c="#C9CDD4" ancho={0.14} />
421
+ </group>
422
+ </group>
423
+ )),
424
+ )}
425
+ </group>
426
+ );
427
+ // ------------------------------------------------------------ casa y ciudad
428
+ case 'tanque_gas':
429
+ return (
430
+ <group>
431
+ <Y eje="x" rad={0.55} h={1.4} c={k('#E9E6E0')} r={0.4} seg={36} />
432
+ {[-0.7, 0.7].map((x) => (
433
+ <Ov key={x} p={[x, 0, 0]} s={[0.3, 0.55, 0.55]} c={k('#E9E6E0')} r={0.4} />
434
+ ))}
435
+ <Y p={[0, 0.6, 0]} rad={0.12} h={0.16} {...LATON} />
436
+ <Y p={[0, 0.72, 0]} rad={0.16} h={0.05} c="#D7372F" r={0.4} />
437
+ {[-0.5, 0.5].map((x) => (
438
+ <C key={x} p={[x, -0.62, 0]} s={[0.12, 0.2, 0.8]} c="#6B727C" r={0.5} />
439
+ ))}
440
+ <C p={[0, 0, 0.552]} s={[0.5, 0.2, 0.01]} c="#D7372F" />
441
+ </group>
442
+ );
443
+ case 'calentador_solar':
444
+ return (
445
+ <group rotation={[0, -0.3, 0]}>
446
+ <Y eje="x" p={[0, 0.65, -0.45]} rad={0.26} h={1.7} c={k('#C9CDD4')} m={0.8} r={0.3} />
447
+ {Array.from({length: 8}, (_, i) => (
448
+ <Y key={i} p={[-0.7 + i * 0.2, 0, 0]} rot={[-0.75, 0, 0]} rad={0.055} h={1.5} c="#16233F" r={0.15} m={0.4} />
449
+ ))}
450
+ <C p={[0, -0.55, 0.52]} s={[1.7, 0.08, 0.12]} {...ACERO} />
451
+ {[-0.8, 0.8].map((x) => (
452
+ <C key={x} p={[x, -0.1, -0.5]} s={[0.05, 1.2, 0.05]} {...ACERO} />
453
+ ))}
454
+ </group>
455
+ );
456
+ case 'termostato':
457
+ return (
458
+ <group>
459
+ <Y eje="z" rad={0.9} h={0.22} c={k('#F4F5F7')} r={0.3} seg={48} />
460
+ <Y eje="z" p={[0, 0, 0.12]} rad={0.72} h={0.02} c="#15161A" r={0.15} seg={48} />
461
+ <Aro p={[0, 0, 0.13]} rot={[0, 0, Math.PI * 0.75]} rad={0.58} tubo={0.035} arco={Math.PI * 1.5 * (o.nivel ?? 0.6)} c="#FF8A3D" e={0.9} />
462
+ <C p={[0, 0.05, 0.135]} s={[0.4, 0.26, 0.005]} c="#F4F6F8" e={0.6} />
463
+ </group>
464
+ );
465
+ case 'detector_humo':
466
+ return (
467
+ <group rotation={[-0.6, 0, 0]}>
468
+ <Y eje="z" rad={0.9} h={0.22} c={k('#F4F5F7')} r={0.4} seg={48} />
469
+ <Y eje="z" p={[0, 0, 0.14]} rad={0.6} h={0.1} c="#ECEDEF" r={0.4} seg={48} />
470
+ {Array.from({length: 10}, (_, i) => (
471
+ <C key={i} p={[Math.cos((i / 10) * Math.PI * 2) * 0.72, Math.sin((i / 10) * Math.PI * 2) * 0.72, 0.115]} rot={[0, 0, (i / 10) * Math.PI * 2]} s={[0.16, 0.04, 0.01]} c="#9AA1AB" />
472
+ ))}
473
+ <E p={[0, 0.3, 0.2]} rad={0.045} c="#E0352B" e={Math.sin(t * 4) > 0.6 ? 1 : 0.1} />
474
+ </group>
475
+ );
476
+ case 'camara_seguridad':
477
+ return (
478
+ <group rotation={[0, -0.5, 0]}>
479
+ <C p={[-0.9, 0.5, 0]} s={[0.12, 0.7, 0.5]} c="#DDE0E5" r={0.4} />
480
+ <Tubo pts={[[-0.85, 0.5, 0], [-0.5, 0.55, 0], [-0.3, 0.3, 0]]} rad={0.06} c="#DDE0E5" r={0.4} />
481
+ <group rotation={[0, Math.sin(t * 0.8) * 0.35, -0.25]} position={[0.1, 0.05, 0]}>
482
+ <Y eje="x" rad={0.3} h={1.1} c={k('#F4F5F7')} r={0.35} />
483
+ <C p={[0.1, 0.3, 0]} s={[1.3, 0.05, 0.7]} c="#F4F5F7" r={0.35} />
484
+ <Y eje="x" p={[0.56, 0, 0]} rad={0.24} h={0.04} c="#15161A" r={0.1} />
485
+ <Y eje="x" p={[0.58, 0, 0]} rad={0.12} h={0.04} c="#1F3F8F" r={0.05} />
486
+ <E p={[0.57, 0.17, 0.12]} rad={0.03} c="#E0352B" e={1} />
487
+ </group>
488
+ </group>
489
+ );
490
+ case 'antena_celular':
491
+ return (
492
+ <group>
493
+ <Y rad={[0.05, 0.09]} h={2.3} {...ACERO} c={k(ACERO.c)} />
494
+ {[0, 1, 2].map((i) => (
495
+ <group key={i} rotation={[0, (i * Math.PI * 2) / 3, 0]}>
496
+ <C p={[0, 0.75, 0.2]} s={[0.18, 0.7, 0.08]} c="#F4F5F7" r={0.4} />
497
+ <C p={[0, 0.1, 0.16]} s={[0.14, 0.4, 0.06]} c="#F4F5F7" r={0.4} />
498
+ </group>
499
+ ))}
500
+ <Y p={[0, 0.35, 0]} rad={0.24} h={0.03} {...ACERO} />
501
+ <Y eje="z" p={[0.2, -0.3, 0.05]} rad={0.2} h={0.08} c="#DDE0E5" r={0.4} />
502
+ <E p={[0, 1.18, 0]} rad={0.05} c="#E0352B" e={Math.sin(t * 3) > 0 ? 1 : 0.1} />
503
+ </group>
504
+ );
505
+ case 'presa':
506
+ return (
507
+ <group rotation={[0, -0.45, 0]}>
508
+ <mesh rotation={[0, 0, 0]}>
509
+ <cylinderGeometry args={[1.3, 1.3, 1.4, 36, 1, true, Math.PI * 0.8, Math.PI * 0.6]} />
510
+ <meshStandardMaterial color={k('#C9C5BC')} roughness={0.9} side={THREE.DoubleSide} />
511
+ </mesh>
512
+ <C p={[0, -0.72, -0.4]} s={[2.6, 0.05, 2.2]} c="#6E6A60" r={0.95} />
513
+ <C p={[0, 0.35, -1.0]} s={[2.2, 0.03, 1.0]} c="#2F8FD6" r={0.1} o={0.8} />
514
+ {[-0.3, 0.3].map((x) => (
515
+ <C key={x} p={[x * 0.9, -0.2, -1.32 + Math.abs(x) * 0.08]} rot={[0.05, x * 0.5, 0]} s={[0.18, 0.95, 0.03]} c="#DFF2FF" o={0.8} e={0.2} />
516
+ ))}
517
+ </group>
518
+ );
519
+ case 'torre_enfriamiento':
520
+ return (
521
+ <group>
522
+ <Y p={[0, -0.55, 0]} rad={[0.55, 0.85]} h={1.0} c={k('#D9D6CE')} r={0.9} seg={36} />
523
+ <Y p={[0, 0.3, 0]} rad={[0.66, 0.55]} h={0.7} c={k('#D9D6CE')} r={0.9} seg={36} />
524
+ <Aro p={[0, 0.65, 0]} rot={[Math.PI / 2, 0, 0]} rad={0.66} tubo={0.03} c="#C73A32" r={0.6} />
525
+ {[0, 1, 2].map((i) => {
526
+ const f = (t * 0.25 + i / 3) % 1;
527
+ return <E key={i} p={[Math.sin(i * 2.1) * 0.2 * f, 0.8 + f * 0.7, 0]} rad={0.28 + f * 0.25} c="#F4F6F8" r={1} o={0.7 * (1 - f)} />;
528
+ })}
529
+ </group>
530
+ );
531
+ case 'ascensor': {
532
+ const y = Math.sin(t * (o.velocidad ?? 0.6)) * 0.45;
533
+ return (
534
+ <group>
535
+ {[-0.6, 0.6].map((x) => (
536
+ <C key={x} p={[x, 0, -0.5]} s={[0.06, 2.3, 0.06]} {...ACERO} />
537
+ ))}
538
+ <C p={[0, 1.12, -0.25]} s={[1.4, 0.08, 0.7]} {...ACERO} />
539
+ <Y p={[0, 0.6 + y / 2, 0]} rad={0.015} h={1.0 - y} c="#15161A" />
540
+ <group position={[0, -0.25 + y, 0]}>
541
+ <C s={[1.0, 1.1, 0.9]} c={k('#C9CDD4')} m={0.7} r={0.35} />
542
+ {[-0.24, 0.24].map((x) => (
543
+ <C key={x} p={[x, -0.03, 0.455]} s={[0.44, 0.95, 0.02]} c="#AEB6C2" m={0.8} r={0.25} />
544
+ ))}
545
+ <C p={[0, 0.5, 0.455]} s={[0.3, 0.07, 0.02]} c="#3DDC84" e={0.8} />
546
+ </group>
547
+ </group>
548
+ );
549
+ }
550
+ case 'fusible':
551
+ return (
552
+ <group rotation={[0, 0, 0.5]}>
553
+ <Y eje="x" rad={0.3} h={1.3} c="#EAF4FF" r={0.08} o={0.3} />
554
+ {[-0.75, 0.75].map((x) => (
555
+ <Y key={x} eje="x" p={[x, 0, 0]} rad={0.32} h={0.36} {...ACERO} />
556
+ ))}
557
+ {o.fundido ? (
558
+ <>
559
+ <Y eje="x" p={[-0.42, 0, 0]} rad={0.02} h={0.36} {...COBRE} />
560
+ <Y eje="x" p={[0.42, 0, 0]} rad={0.02} h={0.36} {...COBRE} />
561
+ <E rad={0.12} c="#3A3D45" o={0.5} />
562
+ </>
563
+ ) : (
564
+ <Y eje="x" rad={0.02} h={1.2} {...COBRE} />
565
+ )}
566
+ </group>
567
+ );
568
+ case 'fibra_optica':
569
+ return (
570
+ <group>
571
+ <Tubo pts={[[-1, -0.6, 0], [-0.5, -0.2, 0.1], [0, -0.1, 0]]} rad={0.16} c={k('#22242A')} r={0.6} />
572
+ {Array.from({length: 9}, (_, i) => {
573
+ const a = (i / 9) * Math.PI * 2;
574
+ const fin: V3 = [0.75 + azar(i) * 0.25, 0.25 + Math.sin(a) * 0.55, Math.cos(a) * 0.5];
575
+ return (
576
+ <group key={i}>
577
+ <Tubo pts={[[0, -0.1, 0], [0.4, 0.05 + Math.sin(a) * 0.2, Math.cos(a) * 0.2], fin]} rad={0.018} c="#DFF2FF" r={0.1} o={0.7} />
578
+ <E p={fin} rad={0.045} c={['#5AC8FA', '#FFD23F', '#FF6AD5'][i % 3]} e={0.6 + 0.4 * Math.sin(t * 5 + i)} />
579
+ </group>
580
+ );
581
+ })}
582
+ </group>
583
+ );
584
+ case 'buzon':
585
+ return (
586
+ <group>
587
+ <Y rad={0.06} h={1.2} p={[0, -0.6, 0]} c="#6A4C32" r={0.9} />
588
+ <C p={[0, 0.2, 0]} s={[0.7, 0.45, 1.2]} c={k('#D7372F')} r={0.4} />
589
+ <Y eje="z" p={[0, 0.42, 0]} rad={0.35} h={1.2} c={k('#D7372F')} r={0.4} />
590
+ <C p={[0, 0.3, 0.605]} s={[0.5, 0.55, 0.01]} c="#B92D26" r={0.4} />
591
+ <C p={[0.38, 0.55, 0.2]} s={[0.03, 0.4, 0.06]} c="#F2C230" r={0.4} />
592
+ <C p={[0.38, 0.72, 0.28]} s={[0.03, 0.14, 0.2]} c="#F2C230" r={0.4} />
593
+ </group>
594
+ );
595
+ // ------------------------------------------------------------ transporte
596
+ case 'autobus':
597
+ return (
598
+ <group rotation={[0, -0.5, 0]}>
599
+ <C p={[0, 0.1, 0]} s={[2.3, 0.95, 0.85]} c={k('#F2C230')} r={0.4} />
600
+ <C p={[0, 0.28, 0]} s={[2.1, 0.36, 0.87]} c="#1B2A44" r={0.15} />
601
+ {[-0.7, -0.2, 0.3].map((x) => (
602
+ <C key={x} p={[x, 0.28, 0]} s={[0.04, 0.4, 0.88]} c={k('#F2C230')} r={0.4} />
603
+ ))}
604
+ <C p={[1.13, 0.2, 0]} s={[0.06, 0.5, 0.75]} c="#1B2A44" r={0.15} />
605
+ <C p={[0, -0.33, 0]} s={[2.32, 0.1, 0.87]} c="#22242A" r={0.5} />
606
+ {[-0.72, 0.72].map((x) =>
607
+ [-1, 1].map((l) => <Y key={`${x}${l}`} eje="z" p={[x, -0.42, l * 0.38]} rad={0.2} h={0.14} c="#15161A" r={0.7} />),
608
+ )}
609
+ {[-1, 1].map((l) => (
610
+ <E key={l} p={[1.15, -0.15, l * 0.28]} rad={0.06} c="#FFF3C4" e={0.9} />
611
+ ))}
612
+ </group>
613
+ );
614
+ case 'helicoptero':
615
+ return (
616
+ <group rotation={[0, -0.6, 0]}>
617
+ <Ov s={[0.75, 0.5, 0.5]} c={k('#D7372F')} r={0.35} />
618
+ <Ov p={[0.38, 0.05, 0]} s={[0.4, 0.36, 0.42]} c="#9FD4FF" r={0.1} o={0.7} />
619
+ <Y eje="x" p={[-1.0, 0.08, 0]} rad={[0.05, 0.14]} h={1.1} c={k('#D7372F')} r={0.35} />
620
+ <C p={[-1.5, 0.3, 0]} s={[0.2, 0.45, 0.04]} c={k('#D7372F')} r={0.35} />
621
+ <group position={[-1.5, 0.2, 0.08]}>
622
+ <Aspas n={3} rad={0.24} giro={giro * 5} c="#22242A" ancho={0.2} />
623
+ </group>
624
+ <Y p={[0, 0.55, 0]} rad={0.04} h={0.2} {...ACERO} />
625
+ <group position={[0, 0.66, 0]} rotation={[Math.PI / 2, 0, 0]}>
626
+ <Aspas n={3} rad={1.15} giro={giro * 3} c="#22242A" ancho={0.07} />
627
+ </group>
628
+ {[-1, 1].map((l) => (
629
+ <group key={l}>
630
+ <Y eje="x" p={[0, -0.65, l * 0.35]} rad={0.03} h={1.2} {...ACERO} />
631
+ {[-0.3, 0.3].map((x) => (
632
+ <Y key={x} p={[x, -0.52, l * 0.3]} rad={0.02} h={0.28} {...ACERO} />
633
+ ))}
634
+ </group>
635
+ ))}
636
+ </group>
637
+ );
638
+ case 'submarino':
639
+ return (
640
+ <group rotation={[0, -0.5, 0]}>
641
+ <Ov s={[1.2, 0.42, 0.42]} c={k('#F2C230')} r={0.35} />
642
+ <C p={[0.1, 0.5, 0]} s={[0.5, 0.4, 0.26]} c={k('#F2C230')} r={0.35} />
643
+ <Y p={[0.2, 0.85, 0]} rad={0.03} h={0.4} {...ACERO} />
644
+ <C p={[0.26, 1.03, 0]} s={[0.14, 0.05, 0.05]} {...ACERO} />
645
+ {[-0.3, 0.15, 0.6].map((x) => (
646
+ <group key={x}>
647
+ <Y eje="z" p={[x, 0.05, 0.4 * Math.sqrt(1 - (x / 1.2) ** 2)]} rad={0.11} h={0.04} {...ACERO} />
648
+ <Y eje="z" p={[x, 0.05, 0.4 * Math.sqrt(1 - (x / 1.2) ** 2) + 0.015]} rad={0.08} h={0.03} c="#9FD4FF" r={0.1} />
649
+ </group>
650
+ ))}
651
+ <C p={[-1.0, 0, 0]} s={[0.3, 0.6, 0.04]} c="#D9A91A" r={0.4} />
652
+ <C p={[-1.0, 0, 0]} s={[0.3, 0.04, 0.6]} c="#D9A91A" r={0.4} />
653
+ <group position={[-1.22, 0, 0]} rotation={[0, Math.PI / 2, 0]}>
654
+ <Aspas n={4} rad={0.22} giro={giro * 2} c="#8E959F" ancho={0.4} />
655
+ </group>
656
+ </group>
657
+ );
658
+ case 'bicicleta':
659
+ return (
660
+ <group rotation={[0, -0.35, 0]}>
661
+ {[-0.7, 0.7].map((x) => (
662
+ <group key={x} position={[x, -0.35, 0]}>
663
+ <Aro rad={0.5} tubo={0.04} c="#15161A" r={0.7} />
664
+ <Aro rad={0.45} tubo={0.012} {...ACERO} />
665
+ <group rotation={[0, 0, -giro * 0.3]}>
666
+ {[0, 1, 2, 3].map((i) => (
667
+ <C key={i} rot={[0, 0, (i * Math.PI) / 4]} s={[0.9, 0.008, 0.008]} {...ACERO} />
668
+ ))}
669
+ </group>
670
+ </group>
671
+ ))}
672
+ {(
673
+ [
674
+ [[-0.7, -0.35, 0], [-0.25, 0.3, 0]],
675
+ [[-0.25, 0.3, 0], [0.45, 0.35, 0]],
676
+ [[0.45, 0.35, 0], [0.7, -0.35, 0]],
677
+ [[-0.25, 0.3, 0], [-0.05, -0.35, 0]],
678
+ [[-0.05, -0.35, 0], [0.45, 0.35, 0]],
679
+ [[-0.7, -0.35, 0], [-0.05, -0.35, 0]],
680
+ ] as [V3, V3][]
681
+ ).map((par, i) => (
682
+ <Tubo key={i} pts={[par[0], [(par[0][0] + par[1][0]) / 2, (par[0][1] + par[1][1]) / 2, 0], par[1]]} rad={0.035} c={k('#2B6FD6')} m={0.4} r={0.35} />
683
+ ))}
684
+ <C p={[-0.28, 0.46, 0]} s={[0.36, 0.06, 0.14]} c="#15161A" r={0.6} />
685
+ <Y p={[-0.26, 0.38, 0]} rad={0.025} h={0.16} {...ACERO} />
686
+ <Y p={[0.47, 0.5, 0]} rad={0.025} h={0.3} {...ACERO} />
687
+ <Y eje="z" p={[0.47, 0.65, 0]} rad={0.025} h={0.6} c="#15161A" />
688
+ <Y eje="z" p={[-0.05, -0.35, 0]} rad={0.1} h={0.04} {...ACERO} />
689
+ </group>
690
+ );
691
+ // ------------------------------------------------------------ escuela y objetos
692
+ case 'lapiz':
693
+ return (
694
+ <group rotation={[0, 0, -0.7]}>
695
+ <Y rad={0.16} h={1.5} seg={6} c={k('#F2C230')} r={0.45} />
696
+ <Cono p={[0, -0.95, 0]} rot={[Math.PI, 0, 0]} rad={0.16} h={0.4} seg={6} c="#E8C9A0" r={0.6} />
697
+ <Cono p={[0, -1.09, 0]} rot={[Math.PI, 0, 0]} rad={0.05} h={0.13} seg={8} c="#22242A" r={0.5} />
698
+ <Y p={[0, 0.82, 0]} rad={0.165} h={0.16} {...ACERO} />
699
+ <Y p={[0, 1.0, 0]} rad={0.15} h={0.22} c="#F28BA0" r={0.6} />
700
+ </group>
701
+ );
702
+ case 'regla':
703
+ return (
704
+ <group rotation={[0, 0, 0.35]}>
705
+ <C s={[2.3, 0.5, 0.04]} c={k('#F2C230')} r={0.4} o={0.9} />
706
+ {Array.from({length: 23}, (_, i) => (
707
+ <C key={i} p={[-1.1 + i * 0.1, 0.25 - (i % 5 === 0 ? 0.11 : 0.06), 0.022]} s={[0.012, i % 5 === 0 ? 0.22 : 0.12, 0.004]} c="#22242A" />
708
+ ))}
709
+ </group>
710
+ );
711
+ case 'dado': {
712
+ const caras: [V3, [number, number][]][] = [
713
+ [[0, 0, 0], [[0, 0]]],
714
+ [[0, Math.PI / 2, 0], [[-0.4, 0.4], [0.4, -0.4]]],
715
+ [[-Math.PI / 2, 0, 0], [[-0.4, 0.4], [0, 0], [0.4, -0.4]]],
716
+ [[Math.PI / 2, 0, 0], [[-0.4, 0.4], [0.4, 0.4], [-0.4, -0.4], [0.4, -0.4]]],
717
+ [[0, -Math.PI / 2, 0], [[-0.4, 0.4], [0.4, 0.4], [0, 0], [-0.4, -0.4], [0.4, -0.4]]],
718
+ [[0, Math.PI, 0], [[-0.4, 0.4], [0.4, 0.4], [-0.4, 0], [0.4, 0], [-0.4, -0.4], [0.4, -0.4]]],
719
+ ];
720
+ return (
721
+ <group rotation={[0.5, 0.6 + giro * 0.1, 0.2]}>
722
+ <C s={[1.5, 1.5, 1.5]} c={k('#F7F5F0')} r={0.3} />
723
+ {caras.map(([rot, pts], i) => (
724
+ <group key={i} rotation={rot}>
725
+ {pts.map(([x, y], j) => (
726
+ <Y key={j} eje="z" p={[x, y, 0.752]} rad={0.13} h={0.01} c="#15161A" />
727
+ ))}
728
+ </group>
729
+ ))}
730
+ </group>
731
+ );
732
+ }
733
+ case 'ancla':
734
+ return (
735
+ <group>
736
+ <Y rad={0.08} h={1.7} {...ACERO} c={k('#5A6472')} />
737
+ <Aro p={[0, 1.0, 0]} rad={0.17} tubo={0.05} {...ACERO} c={k('#5A6472')} />
738
+ <Y eje="x" p={[0, 0.6, 0]} rad={0.06} h={0.9} {...ACERO} c={k('#5A6472')} />
739
+ <Aro p={[0, -0.25, 0]} rot={[0, 0, Math.PI]} rad={0.7} tubo={0.08} arco={Math.PI} {...ACERO} c={k('#5A6472')} />
740
+ {[-1, 1].map((l) => (
741
+ <Cono key={l} p={[l * 0.72, -0.15, 0]} rot={[0, 0, l * 0.5]} rad={0.16} h={0.36} seg={4} c={k('#5A6472')} m={0.85} r={0.3} />
742
+ ))}
743
+ </group>
744
+ );
745
+ case 'paraguas':
746
+ return (
747
+ <group rotation={[0, 0, 0.25]}>
748
+ <mesh position={[0, 0.25, 0]}>
749
+ <sphereGeometry args={[1.05, 8, 8, 0, Math.PI * 2, 0, Math.PI * 0.42]} />
750
+ <meshStandardMaterial color={k('#E5484D')} roughness={0.6} side={THREE.DoubleSide} flatShading />
751
+ </mesh>
752
+ <Y p={[0, 0.2, 0]} rad={0.03} h={2.1} {...ACERO} />
753
+ <Y p={[0, 1.33, 0]} rad={[0.01, 0.04]} h={0.16} {...ACERO} />
754
+ <Aro p={[0.12, -0.85, 0]} rot={[0, 0, Math.PI]} rad={0.12} tubo={0.04} arco={Math.PI} c="#22242A" r={0.5} />
755
+ </group>
756
+ );
757
+ default:
758
+ return null;
759
+ }
760
+ };
761
+ void Helice;