Communitygithub.com

model-by-coding (modelado mediante código)

Úsalo cuando un objeto real deba convertirse en un modelo 3D creado con código, con un video de despiece renderizado y un GIF en bucle: mide el objeto a partir de fotografías, modélalo en código Three.js, verifica cada pose con las fotos mediante capturas de pantalla headless y renderiza la película con HyperFrames 0.9.36.

¿Qué es model-by-coding (modelado mediante código)?

Model-by-coding es un flujo de trabajo especializado para construir modelos 3D de objetos físicos reales (como ventiladores, lámparas, altavoces, cámaras o herramientas) exclusivamente mediante código, sin necesidad de software de modelado gráfico. Su característica principal es que verifica cada paso del modelado contra las fotografías originales del objeto, garantizando que el modelo final corresponda fielmente a lo fotografiado y no sea simplemente un modelo genérico. El flujo consta de cinco etapas: medición del objeto a partir de fotografías, modelado en Three.js con una API de estado puro, verificación visual mediante comparaciones lado a lado con capturas headless, renderizado de un video de despiece usando HyperFrames, y creación de un GIF animado para su uso en READMEs o publicaciones. Soporta Node.js, Python, ffmpeg y Chrome headless, y está diseñado para ser ejecutado en una terminal, con todas las herramientas empaquetadas o indicadas en el propio skill. Es ideal para creadores de contenido técnico, documentación de productos y demos de ingeniería inversa.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Mng12345/model-by-coding/tree/main

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace model-by-coding (modelado mediante código)?

Construye un modelo 3D de un objeto físico a partir de fotografías, completamente en código, y luego conviértelo en una película de despiece y en un GIF. El flujo es estricto en una cosa: el modelo se verifica contra las fotos en cada paso, por lo que la película muestra el objeto que fue fotografiado, no algo solo parecido.

Cuándo usarlo

  • Un producto de superficie dura (ventilador, lámpara, altavoz, cámara, herramienta, electrodoméstico de cocina) debe ser explicado o mostrado por partes en un video corto;
  • El objeto existe físicamente y se puede fotografiar desde varios ángulos;
  • El resultado es un clip de despiece en bucle para un README, una publicación o una demo;
  • Un conjunto de fotos existente debe convertirse en un modelo editable y rerenderizable, no en una malla escaneada.

Cuándo no usarlo

  • Se necesitan activos fotorrealistas: usa fotogrametría o un escáner;
  • El objeto es orgánico, blando o se deforma (tela, plantas, rostros);
  • No se dispone de fotografías, o el objeto solo es visible en un video;
  • Una sola imagen fija es suficiente: los pasos de HyperFrames entonces son innecesarios;
  • El tema es una animación de texto/UI: este flujo se basa en geometría.

Flujo

pasoproducirpuerta de aceptación
1. Mediruna dimensión de referencia, una tabla de proporciones, un objeto DIMproporciones verificadas en ≥2 fotos, cada suposición marcada como inferida
2. Modelaruna escena Three.js construida en código, un paquete IIFE, la página visorel estado ensamblado no tiene huecos; p = 1 separa cada pieza
3. Verificarseis láminas foto/render en la misma posesilueta y proporciones de características dentro de tolerancia en las seis
4. Filmaruna composición HyperFrames, informe check, MP4 finalok: true, sin errores, duración coincide con data-duration
5. Cortarun GIF en buclecomienza y termina en poses estables, menos de ~1 MB

Un presupuesto realista para un objeto es de unas horas a dos días, la mayor parte en los pasos 2–3. Saltarse el paso 3 es lo que convierte una semana de modelado en un modelo incorrecto entregado a tiempo.

Paso 1 — Medir a partir de las fotos

Reúne seis poses (frontal, lateral real, trasera, trasera 3/4, superior, inferior), elige una dimensión grande como referencia, mídela con un escaneo radial y expresa todo lo demás como proporción de ella. Cuenta las características discretas (nervaduras, aspas, radios) por su periodo angular en lugar de a ojo. Mantén cada número en un objeto DIM con un comentario que indique su foto de origen y si es medido o inferido; el tamaño real absoluto es una decisión, no una medición.

Profundidad: references/01-modeling.md §0–2.

Paso 2 — Modelar en código

Un módulo de escena con una API de estado puro: create, setView, setExplode, setExplodeMap, setSpin, setHeadTilt, setLift, render, getAnchors, resize, dispose. Convención del mundo: el objeto mira hacia +Z, la base en y = 0, metros. Construye las carcasas como perfiles torneados, la rejilla como cintas planas (no tubos redondos), las aspas como láminas paramétricas y registra cada pieza a través de una función que almacena su posición ensamblada, desplazamiento de explosión y desplazamiento de anclaje. Nombra las piezas una vez; la película, las etiquetas, los anclajes y el sonido se basan en esos nombres.

Profundidad: references/01-modeling.md §3–6.

Paso 3 — Verificar contra las fotos

Compila el paquete con esbuild, renderiza un fotograma por pose en Chrome headless y compara cada render con su foto como una lámina lado a lado recortada al cuadro delimitador del objeto. Lee las proporciones y la ubicación de las piezas como fracciones del cuadro de cada objeto; no ajustes círculos a bordes sobre un fondo ocupado — el ajuste se engancha a arcos del fondo. Seis poses, algunas iteraciones cada una.

Profundidad: references/03-verify.md.

Paso 4 — Renderizar la película

Construye la composición según el contrato de HyperFrames: un elemento raíz de composición con data-duration, una línea de tiempo GSAP pausada en window.__timelines["main"], Three.js redibujado solo desde hf-seek (nunca desde rAF/timers), medios con su propia temporización marcados como class="clip" con data-start/data-duration, una mezcla de audio como clip de audio, texto a 28 px o más grande, y el paquete grande como assets/vendor/*.min.js. Escribe la lista de planos antes de animar; controla la cámara, la explosión y las etiquetas desde un único script de dirección para que las señales de audio puedan compartir sus constantes. Ejecuta check, lee el informe, luego render --quality delivery.

Profundidad: references/02-render.md.

Paso 5 — Cortar el GIF

Elige un segmento estable de 3–4 s (normalmente la pausa de explosión), córtalo con gif-master (ancho 480, 12 fps, bucle) o con el comando de paleta de dos pasos de ffmpeg, y verifica el tamaño, el número de fotogramas y el bucle antes de publicar. Profundidad: references/04-gif.md, scripts/make_gif.md.

Restricciones estrictas

Estas son las reglas que rompen el flujo cuando se violan; no son preferencias de estilo.

  1. Contrato primero. El objeto mira hacia +Z, base en y = 0, metros, cámara target + dist * (sin(yaw)cos(pitch), sin(pitch), cos(yaw)cos(pitch)), yaw/pitch en grados. Cada script y la película lo comparten.
  2. Estado puro. La API de la escena debe renderizar el mismo estado a los mismos píxeles. Sin bucle de animación, sin reloj de pared, sin Math.random() en el código del que dependa el fotograma.
  3. Fotograma = f(t). La cámara, la explosión, el giro, las etiquetas, las tarjetas y el sonido son funciones del tiempo de la película; nada más.
  4. Contrato de composición. data-composition-id, data-start, data-duration, data-width, data-height en el elemento raíz; línea de tiempo pausada registrada como window.__timelines["<id>"]; redibujado dentro de hf-seek usando e.detail.time.
  5. Clips. Los medios con su propio inicio y duración (audio, video, inserciones) llevan class="clip", data-start, data-duration; el audio además data-track-index. El DOM animado por la línea de tiempo no necesita atributos de clip.
  6. Legibilidad. Nada informativo por debajo de 28 px a 1080p (el umbral de tipo del verificador es 28 px = 2.6% del lado corto).
  7. Pesos empaquetados. three.js y GSAP como .min.js en assets/vendor/; fuentes locales; sin red durante el renderizado.
  8. Los scripts son genéricos. Sin nombre de objeto, sin ruta absoluta, sin directorio personal en scripts/; cada script debe ejecutarse desde un checkout limpio.
  9. Comandos de verificación. Cada comando y parámetro escrito en docs, scripts o la película debe ejecutarse una vez contra las versiones fijas antes de ser confiado.

Enrutamiento de referencias

tarealeer
medición, proporciones, perfiles torneados, parámetros de rejilla/aspas, piezas, explosión, anclajesreferences/01-modeling.md
contrato de composición, dirección/guion gráfico, sincronización de audio, comandos y salidas de HyperFramesreferences/02-render.md
bucle de capturas de pantalla, láminas de comparación, lectura de ángulos, error de ajuste de círculoreferences/03-verify.md
tarjeta de operación de gif-master, créditos, receta ffmpeg para GIFreferences/04-gif.md
repositorio, lanzamiento en GitHub, PR de lista comunitaria, YouTube/Xreferences/05-publish.md
catálogo de síntoma → causa → solución (iluminación, sombras, nervaduras, tipo, paquetes, Chrome)references/06-gotchas.md

Herramientas incluidas con este skill:

archivofunción
scripts/view.htmlvisor de un solo fotograma; pose y paquete desde parámetros de consulta
scripts/verify_sheet.pylámina lado a lado foto-vs-render (--photo --render --out --bbox)
scripts/hf_read_check.pyresume un informe de verificación de HyperFrames; --fail-on-error para CI
scripts/make_gif.mdtarjeta de operación del navegador/ffmpeg para el GIF

Secuencia ejecutable mínima

Los comandos se ejecutan desde la raíz del repositorio contra el ejemplo trabajado en examples/fan/; para un objeto nuevo, sustituye src/scene.js, photos/ y video/. Los archivos de trabajo van a %TEMP% para que el checkout se mantenga limpio. Mantén los parámetros — son los verificados. Ejecuta en PowerShell.

$work = Join-Path $env:TEMP "mbc-verify"; New-Item -ItemType Directory -Force $work | Out-Null

# 1. empaquetar la escena (plantilla para un objeto nuevo; necesita tener instalado `three`).
#    El ejemplo incluye su paquete en examples/fan/video/assets/vendor/fan.bundle.min.js,
#    por lo que este paso se puede omitir para el ejemplo.
npx --yes [email protected] src/scene.js --bundle --format=iife --global-name=Scene `
  --minify --target=chrome120 --outfile=dist/scene.bundle.min.js

# 2. capturar una pose de verificación del ejemplo (1920x1080, perfil nuevo por ejecución)
$chrome = "C:\Program Files\Google\Chrome\Application\chrome.exe"
$png = Join-Path $work "front.png"
$udd = Join-Path $env:TEMP ("view-" + [guid]::NewGuid().ToString("N"))
& $chrome --headless=new --use-angle=d3d11 --window-size=1920,1080 `
  --hide-scrollbars --virtual-time-budget=12000 `
  --screenshot=$png --user-data-dir=$udd `
  "file:///$(($PWD.Path).Replace('\','/'))/scripts/view.html?bundle=../examples/fan/video/assets/vendor/fan.bundle.min.js&yaw=-10&pitch=12&dist=0.85&ty=0.185&fov=30&noshadow=1"

# 3. comparar ese render con la fotografía frontal en la misma pose
python scripts/verify_sheet.py --photo examples/fan/reference/fan.jpg --render $png `
  --out (Join-Path $work "front-sheet.png") --bbox "130,245,1195,1455"

# 4. verificar la película contra el contrato de HyperFrames, luego leer el informe
Set-Location examples/fan/video
# necesita assets/audio/mix.wav (activo del lanzamiento; ver examples/fan/README.md)
npx --yes [email protected] check --at 21.15,27.6,35.18
$report = Get-ChildItem .hyperframes/artifacts/checks/*.json |
  Sort-Object LastWriteTime | Select-Object -Last 1
python ../../../scripts/hf_read_check.py $report.FullName --fail-on-error
npx --yes [email protected] snapshot --at 29.6

# 5. renderizar el master de entrega
npx --yes [email protected] render --quality delivery
Set-Location ../../..

# 6. cortar el GIF con ffmpeg (ruta del navegador: scripts/make_gif.md)
$mp4 = (Get-ChildItem examples/fan/video/renders/*.mp4 | Sort-Object LastWriteTime | Select-Object -Last 1).FullName
ffmpeg -hide_banner -loglevel error -y `
  -ss 29.6 -t 3.8 -i "$mp4" `
  -vf "fps=12,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=sierra2_4a" `
  -loop 0 (Join-Path $work "teardown.gif")

El paso 3 imprime los dos cuadros de recorte; la ejecución verificada imprime saved ...\front-sheet.png 1112x702 | photo (130, 245, 1195, 1455) | render (652, 264, 1252, 1080).

Salidas esperadas: check escribe video/.hyperframes/artifacts/checks/<uuid>.json; snapshot escribe video/.hyperframes/artifacts/snapshots/<uuid>/frame-00-at-29.6s.png; render escribe video/renders/video_<YYYY-MM-DD>_<HH-MM-SS>.mp4 (aproximadamente 36 MB para 43.5 s a 1920×1080/30 fps, aproximadamente 2.5 minutos de captura con una GPU de hardware).

Requisitos

  • Node.js (probado 22.19.0) con npx; esbuild 0.24.2 vía npx.
  • Python 3.11 (probado 3.11.1) con Pillow para la lámina; numpy opcional.
  • ffmpeg en PATH (probado con una compilación git del 2025-12-28).
  • Chrome para capturas de pantalla headless (probado 157.0.8103.40); la ruta anterior es la predeterminada de Windows.
  • HyperFrames fijado en 0.9.36 mediante npx --yes [email protected].
  • check y render ejecutan Chrome headless con --browser-gpu en automático: GPU de hardware cuando está presente, software (SwiftShader) en caso contrario; preview funciona mejor con una GPU.

Definición de terminado

  • seis láminas de comparación se leen aceptablemente, con las desviaciones listadas y explicadas;
  • hf_read_check.py --fail-on-error sale con 0 en el informe de verificación final;
  • el MP4 de entrega existe y su duración es igual al data-duration de la composición;
  • el GIF se repite limpiamente y es lo suficientemente pequeño para publicar;
  • cada comando de este skill se ha ejecutado una vez en un checkout limpio.

Skills relacionados