Skill de Máquina
Construyes una máquina como lo haría un estudio de producto fotografiándola y un ingeniero explicándola: la cosa real a su tamaño real, con materiales reales, en un set de estudio limpio, funcionando con ecuaciones reales. Una línea de entrada, un archivo HTML de salida y una película en un comando.
La salida es siempre:
<nombre>.html: una página autocontenida (three.js 0.170 desde jsDelivr, el kit incrustado). Se abre desde el disco, desde cualquier servidor estático o dentro de un iframe.- Una película:
node scripts/record.mjs <nombre>.html out/<nombre>.mp4 --music freepd:<Categoría>/<Nombre>.
Abre examples/ primero. Cada ejemplo se hizo a partir de la única línea en la parte superior de su página. examples/turbofan.html es la referencia: léela de principio a fin antes de escribir nada.
El estándar
Antes de empezar, imagina el fotograma que un espectador ve después de tres segundos. Ya debe parecer una fotografía de estudio del producto real: silueta y proporciones correctas, metal que se lee como metal, una sombra suave sobre un suelo de papel, nada flotando, nada recortado, nada provisional. Luego se mueve, y cada número en pantalla está calculado.
Un resultado no está terminado mientras se cumpla alguna de estas condiciones:
- falta una pieza que un mecánico esperaría (sin toberas de combustible en un combustor, sin escape en un reloj, sin válvulas en un motor)
- algo flota, se intersecta o tiene una costura o hueco visible en una unión
- un material parece plástico cuando debería ser metal, o todo es de un solo gris
- un número en pantalla está escrito manualmente en lugar de ser calculado por el solucionador
- el corte transversal muestra carcasas huecas en lugar de caras de sección sólidas
- el primer fotograma de la película no es hermoso
Flujo de trabajo
1. Investiga la máquina real (5 minutos, sin código)
Escribe, en un bloque de comentarios al inicio del script de la máquina, basado en lo que sabes (y la web si la tienes):
- Las dimensiones reales en metros de las 5 a 10 partes que definen la silueta (un turbofán: diámetro del fan 2.85 m, longitud 4.9 m, diámetro máximo de la nacela 3.44 m).
- La lista de piezas en orden de ensamblaje, cada una con su material. Apunta a entre 15 y 40 piezas nombradas; las piezas repetidas (álabes, dientes, pernos, bobinas) cuentan individualmente.
- La física que lo hace funcionar, como 3 a 6 ecuaciones que realmente calcularás, con constantes reales y el punto de operación (un turbofán: ciclo Brayton, despegue con N1 al 100 %, OPR 42, T4 1.750 K, aproximadamente 330 kN).
- El único número que le importa al espectador: el héroe (empuje, par, latidos por hora, caudal, potencia). Recibe una gran lectura serif y una barra fina.
- La entrada que un espectador quiere controlar: un deslizador (acelerador, velocidad del viento, RPM, velocidad de bomba, tamaño de molido).
- La rotura: el fallo que preocupa a un ingeniero, y lo que el solucionador dice que ocurre (rotura de álabe del fan y la carga de desbalanceo, flotación de válvula por encima del régimen máximo, bomba estancada, sobrepresión). Esto debe ser una consecuencia calculada, no una animación.
2. Construye la página desde la plantilla
Copia kit/template.html a <nombre>.html. Tiene el mapa de importación ([email protected] fijado), las fuentes, un bloque marcado donde va el kit, y las cuatro secciones que completas:
const { THREE, Lab, MAT, GEO, heatGlow, clamp, lerp, approach, fmt } = window.LabKit
const lab = new Lab({ prompt, no, title, sub, size, view, cut }) // 1. el laboratorio
// 2. las piezas lab.mesh(GEO..., MAT..., { name, pos, explode, xray, count })
// 3. el solucionador lab.hero(...); lab.slider(...); lab.onTick((dt, lab) => { ... lab.setHero(...) })
// 4. rotura, explicación, película lab.breakIt(...); lab.how(...); lab.autoFilm(...); lab.start()
Justo después de copiar, ejecuta node <directorio del skill>/scripts/inline.mjs <nombre>.html: pega el kit en el bloque marcado para que la página sea un solo archivo autocontenido dondequiera que esté (el src="../kit/lab-kit.js" de la plantilla solo se resuelve dentro de este repositorio). Luego escribe tu máquina en el segundo bloque de script.
3. Geometría: sólidos reales a tamaño real
Trabaja en metros en el sistema de coordenadas de la máquina, con Y hacia arriba, el suelo en y = 0 a menos que definas ground. Define size con la dimensión real más larga; el kit escala la visualización para que cada máquina ocupe el mismo espacio en el set, y la barra de escala muestre el tamaño real.
- Piezas redondas (ejes, discos, carcazas, toberas, conos, spinners, pistones, biseles):
GEO.lathe([[r, y], ...])con un perfil CERRADO. Paredes:GEO.shell(perfil, grosor), tubos:GEO.tube(rExt, rInt, h), discos biselados:GEO.disc(r, h). Las esquinas se mantienen nítidas y las curvas se sombrean suavemente de forma automática. - Álabes y paletas:
GEO.rotor({ count, axis, r0, r1, chord, thick, camber, twist, pitch, sweep })construye perfiles aerodinámicos reales combados y torsionados (espesor NACA) como sólidos cerrados y los anilla. Usa arrays[raíz, punta]para chord, thick y camber. - Engranajes:
GEO.gear({ teeth, module, width, bore, helix, spokes, rim }). Acopla dos engranajes con distancia entre centros(z1 + z2) * module / 2y gíralos con la relación de dientes inversa, desfasados medio diente. - Tuberías, mangueras, cables:
GEO.pipe(puntos, r)(cerrados, con tapas). Enrútalos a lo largo de la estructura de puerto a puerto, nunca a través de una pieza. - Fijaciones:
GEO.bolts(n, R, size, h)en cada brida. Resortes:GEO.spring(R, wire, turns, len). Cajas:GEO.rbox(w, h, d, r)(siempre redondeadas, nunca afiladas). Placas con agujeros:GEO.extrude(forma, profundidad). - Masas e inercias provienen de la geometría:
GEO.volume(geo)da volumen y centroide, multiplica por la densidad real.
Reglas que lo mantienen limpio:
- Cada pieza es un sólido cerrado (perfiles de torneado cerrados, carcasas con grosor, tuberías tapadas). Eso es lo que permite que el corte transversal dibuje caras de sección sólidas. Las superficies abiertas se muestran huecas al cortar.
- Nada se intersecta visiblemente y nada flota. Cada pieza toca lo que la sostiene (una brida se asienta sobre una cara, un eje corre en un cojinete, un poste llega al suelo). Verifica las uniones en primeros planos.
- Detalle donde el ojo se fija: círculos de pernos en bridas, chaflanes, un labio, una placa de identificación, líneas de combustible, un arnés. Las áreas grandes y planas reciben una costura, una línea de panel o un acabado de textura.
- Dale una base a la máquina: un soporte, cuna, pedestal, banco o montura con patas en el suelo. Las máquinas rara vez flotan en la vida real.
- Presupuesto: hasta aproximadamente 700k triángulos y 200 mallas. Fusiona piezas estáticas repetidas con
GEO.merge/GEO.ring; mantén los grupos móviles separados.
4. Materiales: nunca un solo gris
Usa los preajustes MAT.*; llevan reflectancias medidas para que el acero, titanio, aluminio, latón y cobre se vean diferentes uno al lado del otro. Cada preajuste acepta sobreescrituras (color, roughness, clearcoat, cualquier campo de MeshPhysicalMaterial) y un finish (textura de micro-rugosidad: turned anillos en piezas torneadas, brushed rayas, cast manchas, smudge, knurl).
| Uso | Preajuste |
|---|---|
| ejes, discos, piezas mecanizadas | MAT.steel, MAT.stainless, MAT.chrome |
| carcasas, fundiciones | MAT.aluminium, MAT.castIron, MAT.steelDark |
| álabes, aeroespacial | MAT.titanium, MAT.inconel (+ heatGlow) |
| accesorios, cableado | MAT.brass, MAT.copper, MAT.gold |
| cuerpos pintados | MAT.paint({ color }), MAT.satin, MAT.anodised({ color }) |
| polímeros | MAT.plastic, MAT.rubber, MAT.carbon |
| ventanas, cristales | MAT.glass, MAT.sapphire, MAT.ruby, MAT.enamel |
| luz, llama, gas caliente | MAT.glow, heatGlow(material, kelvin) |
Elige una paleta como un diseñador industrial: principalmente metales y uno o dos colores pintados, como máximo un acento. Las piezas calientes brillan desde la temperatura del solucionador (material.userData.heat.value = T).
5. El solucionador: números reales o nada
Escribe una pequeña función pura desde la entrada y el estado a cada número que muestras, con unidades reales y constantes reales. Integra la dinámica con approach (retardo de primer orden: aceleración, masa térmica) o rk4 (resortes, escapes, péndulos). Luego guía el movimiento desde ella: una RPM del solucionador gira el eje, un caudal del solucionador mueve las partículas, una temperatura calienta el metal.
- Un héroe:
lab.hero({ label, unit, max })luegolab.setHero(valor, { state, sub, bad })en cada tick.stateson dos o tres palabras (acelerando, despegue, flujo estrangulado).subes una línea con 2 o 3 números más. - Un deslizador:
lab.slider({ id, label, min, max, value, unit, ends }). Un segundo solo si la máquina realmente lo necesita. - Las etiquetas cuelgan de piezas estáticas en puntos de los planos de sección:
lab.label(obj, 'Turbina AP', { at: [x, y, z], value: () => '12.979 rpm' }). lab.how(palabras, ecuaciones)llena "Cómo se calcula": el modelo en palabras simples y las ecuaciones tal como están escritas en el código. Di qué está simplificado.- Si un movimiento es demasiado rápido para verlo (un fan a 2.700 rpm), muéstralo ralentizado y dilo en
how("giro mostrado 1:60"). Nunca ralentices los números. - Verifica el punto de operación contra la cifra pública que anotaste en el paso 1. Si te desvías más de aproximadamente el 20 %, corrige el modelo, no el número.
6. Flujo, calor y efectos
lab.flow({ paths, count, length, color, parent }): estelas que recorren trayectorias que construyes a partir del camino de flujo real (aire a través de un conducto, sangre a través de una bomba, agua a través de una pastilla). Define.speeddesde el solucionador y.opacitydesdelab.state.cutpara que se muestren dentro del corte transversal. Colorea por una cantidad calculada (temperatura, presión).lab.plume({ radius, length, dir, color: 'rocket' | 'jet', shocks }): un escape con diamantes de Mach; define.powerdesde el solucionador.lab.sparks.emit(posMundo, n, velocidad)ylab.shed(malla, v, w)para roturas: las chispas caen con gravedad y rebotan; una pieza desprendida se convierte en un cuerpo rígido que aterriza en el suelo.
7. Modos (el kit los hace; tú los configuras)
- Explotar: cada
lab.add/lab.meshaceptaexplode: [dx, dy, dz]en el sistema de referencia del padre (metros). Mueve las piezas a lo largo de su eje de ensamblaje, las carcasas exteriores más lejos, y mantén el núcleo en su lugar. Nada debe cruzarse en el camino de salida. - Corte transversal:
cut: { a, b, center, reach }en el Lab.aybson las direcciones de la región eliminada:a = [0,0,1], b = [0,1,0]elimina el cuarto hacia el espectador y hacia arriba (mejor para cosas con un eje);b = aelimina una mitad. Las caras de sección se dibujan automáticamente para cada sólido cerrado, con un tramado tenue. - Rayos X:
xray: 'shell'en las carcasas exteriores las convierte en vidrio con bordes finos, para que el núcleo se vea mientras funciona. - Cámara lenta, etiquetas, pausa vienen gratis (teclas S, L, Espacio). Las partes interactivas son la órbita del ratón, el deslizador y los botones.
- Rómpelo:
lab.breakIt({ label, run(lab), reset(lab) }).runcambia el estado del solucionador (un álabe liberado, una válvula atascada, un sello roto) y el solucionador calcula la consecuencia. Muéstralo en el héroe (bad: true) y con chispas, escombros o sacudidas.
8. Míralo como un crítico (obligatorio)
Renderiza y LEE cada imagen que hagas. Usa los scripts:
node scripts/shot.mjs <nombre>.html out/review.png # la primera mirada
node scripts/shot.mjs <nombre>.html out/cut.png --js "lab.toggle('cut', true); lab.toggle('labels', true)"
node scripts/shot.mjs <nombre>.html out/near.png --js "lab.setView({ az: 70, el: 8, dist: 0.8, target: [x, y, z] })"
node scripts/shot.mjs <nombre>.html out/film --film 1,4,8,12,17,22,26 # fotogramas de la película
Haz al menos cuatro rondas de revisión. En cada una: vista completa, corte transversal con etiquetas, explotado, dos primeros planos de uniones, y los fotogramas de la película. Compara con la fotografía de producto real de la máquina en tu memoria: proporciones, cantidad de piezas, materiales, cómo cae la luz sobre ella. Enumera lo que está mal, arréglalo, renderiza de nuevo. Detente solo cuando la lista esté vacía. El script de captura imprime fps, cantidad de piezas y triángulos; mantén las tasas de fotogramas interactivas por encima de 30.
9. La película
lab.autoFilm({ runBeat, runSub, breakBeat, breakSub, sliderTo }) escribe la historia estándar de 28 segundos a partir de tu máquina, en compases numerados con los textos editoriales:
- Una oración es todo el resumen (la barra de prompt se escribe a sí misma).
- Claude construye la máquina (las piezas vuelan en orden de ensamblaje mientras el contador sube: "84 de 3.597 piezas").
- Funciona (un cursor arrastra el deslizador; el número héroe sube desde el solucionador).
- Ábrelo (tapas de sección, etiquetas con valores en vivo).
- Desmóntalo (explotar).
- Rómpelo (el cursor hace clic en el botón de rotura; el solucionador decide qué falla).
Bucle: la última clave de cámara vuelve a la primera. Para una película personalizada usa lab.film('nombre', { len, assemble, shots, events }): los shots son claves de cámara { t, az, el, dist, target, fov }, los eventos son { t, beat: ['07', 'Oración en negrita.', 'Oración en gris.'], set: { cut: 1 }, slider: { id, to, dur }, cursor: { to: 'slider:id:0.8' | 'button:break' | [x, y], click: true }, do(lab) {} }.
Graba (necesita Node 18+, Playwright con Chromium, ffmpeg):
node scripts/record.mjs <nombre>.html out/<nombre>.mp4 --music freepd:Classical/Easy_Lemon
node scripts/record.mjs <nombre>.html out/<nombre>-portrait.mp4 --w 1080 --h 1350
La página se ejecuta en modo película (?film=1): su reloj solo se mueve cuando el grabador lo avanza, por lo que cada fotograma está completo y la película es idéntica en cada toma. El grabador protege cada captura de pantalla contra los fotogramas magenta que una GPU sin cabeza atascada puede devolver, y escanea la película terminada; sale con código distinto de cero si algún fotograma es rosa. La música de FreePD es CC0; acredita la pista de todos modos.
Escritura en pantalla
La página es editorial, no un panel de control: una barra de prompt, un título serif con un subtítulo en cursiva, un número enorme con unidades en cursiva y una barra fina, una línea de números de apoyo, un deslizador. Escribe como un buen pie de foto: corto, concreto, sin exageraciones, unidades reales con un espacio (338 kN, 1.750 K, 4.2 L/min), miles separados. Los textos de los compases son una oración en negrita y una oración en gris.
Qué decir cuando lo entregas
Da la ruta del archivo HTML, el comando de la película, el punto de operación que alcanza el solucionador frente a la cifra pública, y cualquier cosa que hayas simplificado. Ofrece la siguiente máquina.