Todos los artículos

Visualizando 86K Estrellas de GitHub como Langostas Procedurales

Construí una visualización 3D en tiempo real que renderiza cada una de las 86.546 estrellas de GitHub de moltbot como una langosta generada proceduralmente. Así es como logré 80K+ instancias a 60 FPS en un solo día.

Godot Optimization Procedural WebGL

Quería celebrar que un proyecto alcanzara 86.000 estrellas en GitHub. Un contador me parecía aburrido. Un sistema de partículas, genérico. Así que rendericé cada estrella como una langosta 3D generada proceduralmente.

Todo el proyecto me llevó unas seis horas.

2.557 langostas procedurales dispuestas en una esfera de Fibonacci

¿Por qué langostas?

El proyecto que estaba visualizando—moltbot—tiene una temática de muda/langosta integrada en su identidad. En lugar de ignorarlo, lo aproveché. Cada estrella de GitHub se convierte en una langosta en un enjambre creciente que los usuarios pueden orbitar, atravesar con zoom y recorrer en el tiempo.

Es memorable de una forma que “86.546 estrellas” como texto nunca podría ser.

El problema de las 80K instancias

Renderizar 86.000 nodos individuales en Godot destruiría el rendimiento. Incluso con un nodo por langosta, gastarías todo tu presupuesto de frame en la sobrecarga del árbol de escenas antes de dibujar nada.

La solución es GPU instancing mediante MultiMesh. En lugar de 86.000 nodos, tienes un nodo con una sola llamada de dibujo. La GPU se encarga de la replicación.

var multimesh = MultiMesh.new()
multimesh.mesh = lobster_mesh
multimesh.transform_format = MultiMesh.TRANSFORM_3D
multimesh.use_custom_data = true
multimesh.instance_count = 100000  # Pre-asignar una vez

Pre-asigno 100.000 instancias al inicio. Añadir una nueva langosta solo significa actualizar su transform y hacerla visible—sin asignación de memoria, sin creación de nodos, sin picos de rendimiento.

Malla de langosta procedural

La langosta se genera completamente mediante código. Sin software de modelado 3D. Aproximadamente 340 triángulos por instancia:

ComponenteDetalles
CuerpoElipsoide alargado (8 segmentos × 5 anillos)
Cola5 placas segmentadas + abanico de 3 placas
PinzasDos pinzas articuladas (tamaño asimétrico)
Patas6 pares de apéndices articulados
AntenasDos sensores curvados

La generación procedural significa que podía iterar el diseño en código sin pasar por Blender. También mantiene la exportación web pequeña—sin archivos de malla externos que cargar.

Evitando el ejército de clones

80.000 langostas idénticas parecerían un salvapantallas de 1998. El shader añade variación mediante datos personalizados empaquetados en cada instancia:

  • Canales RGB: Tintado de color (tono del cuerpo, acento de pinza, claridad del vientre)
  • Canal Alpha: Desfase de fase de animación

Cada langosta se balancea en una onda sinusoidal, pero con un desfase de fase único. El resultado es movimiento orgánico—ninguna langosta se mueve sincronizada con otra.

float phase = INSTANCE_CUSTOM.a * TAU;
float bob = sin(TIME * 2.0 + phase) * 0.1;
VERTEX.y += bob;

Distribución en esfera de Fibonacci

¿Dónde colocas 86.000 puntos en una esfera para que no parezcan una cuadrícula ni estén amontonados?

La espiral del ángulo dorado. Es el mismo patrón que usan las semillas de girasol—matemáticamente probado para evitar patrones visibles a cualquier escala.

const GOLDEN_ANGLE = PI * (3.0 - sqrt(5.0))  # ≈ 2.39996

func get_position(index: int, total: int) -> Vector3:
    var y = 1.0 - (float(index) / (total - 1)) * 2.0
    var radius_at_y = sqrt(1.0 - y * y)
    var theta = GOLDEN_ANGLE * index
    return Vector3(
        cos(theta) * radius_at_y,
        y,
        sin(theta) * radius_at_y
    ) * sphere_radius

Con 86K instancias, puedes hacer zoom en cualquier parte y la distribución sigue pareciendo natural.

Interfaz de viaje en el tiempo

La visualización no es estática. Una línea de tiempo te permite recorrer el historial de estrellas del proyecto—desde 13 estrellas el primer día hasta 86.546 en el presente.

El pipeline de datos obtiene las marcas de tiempo de las estrellas mediante la API GraphQL de GitHub (la API REST tiene un límite de 40K estrellas), las agrega en conteos diarios y exporta como JSON. Aproximadamente 270 puntos de datos cubriendo 62 días de crecimiento.

La búsqueda binaria encuentra el conteo correcto para cualquier fecha: O(log n) para 270 puntos es efectivamente instantáneo.

Decisiones pensadas para web

El objetivo eran los navegadores web, lo que condicionó varias decisiones:

Renderer GL Compatibility. El Forward+ de Godot se ve mejor pero requiere WebGPU, que carece de soporte en navegadores. GL Compatibility apunta a WebGL 2.0—funciona en todas partes.

Renderizado sin iluminación. Sin sombras, sin iluminación compleja. Rendimiento consistente en todos los dispositivos y un estilo visual más limpio.

Controles táctiles. Pellizcar para zoom y arrastrar para orbitar funcionan junto con la entrada del ratón.

Cámara con auto-zoom. A medida que el enjambre crece, la cámara se aleja automáticamente para mantener todo visible. Los usuarios pueden anularlo manualmente.

En qué se fue el tiempo

Seis horas suena rápido. Aquí está el desglose aproximado:

FaseTiempo
Configuración de MultiMesh + controles de cámara1 hora
Generación procedural de malla de langosta2 horas
Shader para variación instanciada1 hora
Pipeline de datos + UI de línea de tiempo1.5 horas
Pulido (auto-zoom, colores, exportación web)0.5 horas

La malla procedural fue la parte más laboriosa. Conseguir que una langosta parezca una langosta mediante código—no Blender—requirió iteración. El resto fue aplicar técnicas conocidas.

Lo que aprendí

GPU instancing es la respuesta. Cada vez que necesites miles de objetos similares, recurre a MultiMesh (o equivalente en otros motores). La diferencia de rendimiento no es incremental—es categórica.

La generación procedural paga interés compuesto. Construir la malla en código se sintió más lento inicialmente, pero eliminó el pipeline artístico por completo. Los cambios eran instantáneos. La exportación web se mantuvo pequeña.

Las espirales de Fibonacci son mágicas. Ya había usado distribución de ángulo dorado antes, pero ver cómo aguanta con 86K puntos fue igualmente satisfactorio. Las matemáticas simplemente funcionan.

Las restricciones web clarifican. Apuntar al navegador me obligó a mantener las cosas simples: sombreado sin iluminación, sin post-procesado, tamaños de archivo mínimos. El resultado fue un proyecto más limpio.

¿Lo haría de nuevo?

Ya estoy pensando en ello. La misma técnica podría visualizar cualquier dato de series temporales—commits, descargas, registros de usuarios—con objetos 3D temáticos en lugar de gráficos.

Las langostas hicieron este proyecto memorable. El instancing lo hizo posible.

Código fuente

El código fuente completo está disponible en GitHub, incluyendo el workflow de Claude que usé para construirlo.