Paleta de comandos

Navegá el sitio, cambiá el tema o saltá a un proyecto.

MP
Volver al trabajo
D
Estudio · Impresión 3D/2026/Marca digital · WebGL · Dirección de arte

Dummy Studios

La vitrina digital de un estudio de impresión 3D: un catálogo que se recorre como una galería de museo, en WebGL y a 60fps.

  • Next.js 16
  • React Three Fiber
  • Drei
  • Draco
  • meshopt
  • GLSL
  • Poly Haven PBR
El ángulo

La identidad de Dummy Studios llevada a la web: un solo Canvas WebGL con navegación espacial y modo museo donde cada pieza del catálogo se exhibe como una obra. Mármol triplanar procedural sobre escaneos sin UVs, carga por tiers con corrección por FPS en runtime, y post-processing cinematográfico — la marca se siente premium en cualquier dispositivo.

0

Impresiones / semana

promedio

~0

Pico mensual

impresiones en meses fuertes

0

GLB optimizados

0fps

Objetivo

con degradación

El problema

3D bonito que no se cae en un teléfono

Las landings 3D suelen elegir: o se ven increíbles en desktop y mueren en mobile, o degradan tanto que pierden el alma. El objetivo era no elegir.

La decisión

Performance como sistema, no como parche

Definí tiers estáticos por capacidad y los corregí en caliente leyendo FPS reales. Los assets pasan por un pipeline propio (Draco + meshopt) y el mármol se genera por triplanar para no depender de UVs en los escaneos. El post-proceso es de un solo composer.

El resultado

Catálogo cinematográfico, adaptable y liviano

56 GLB comprimidos un 33%, carga secuencial con prefetch predictivo y un modo museo que se siente premium en cualquier hardware. La vitrina acompaña a un estudio que hoy promedia unas 20 impresiones por semana y trepa a cientos de impresiones en los meses de mayor demanda.

En pantalla

Lo que se ve

Dummy Studios

Modo museo

Estatuas de mármol bajo spotlights que se deslizan al cambiar de pieza, como una sala de exhibición que se recorre sola.

Dummy Studios

Navegación espacial

Del hero al museo sin cortes: la cámara viaja por el espacio dentro de un único Canvas WebGL, sin recargar la escena.

Mármol triplanar procedural

Mármol triplanar procedural

La textura PBR de mármol real que alimenta la proyección triplanar: vetas continuas que el shader aplica sobre escaneos sin coordenadas UV.

Dummy Studios

Ficha de pieza

Cada modelo del catálogo abre con sus datos, materiales y opciones de impresión, anclados al objeto en 3D.

Dummy Studios

Post-processing cinematográfico

Bloom, viñeta y corrección de color en un solo composer, calibrado para que la marca se vea premium en cualquier pantalla.

Dummy Studios

Degradación por FPS en vivo

Indicador de tier activo: la escena baja o sube calidad leyendo los FPS reales del dispositivo en runtime.

Dummy Studios

Catálogo como galería

Las 56 piezas se recorren como obras de museo, con carga secuencial y prefetch de la siguiente para que nunca haya espera.

Bajo la superficie

Lo que no se ve

La contraparte invisible de la pantalla: la arquitectura, el backend y la infraestructura que sostienen el producto.

91MB → 61MB (−33%)

Pipeline propio de optimización de assets

56 GLB pasan por una etapa de build con Draco + meshopt que cuantiza geometría y comprime mallas sin perder silueta. De 91MB a 61MB sin sacrificar el detalle de los escaneos.

DracomeshoptBuild pipeline
first paint < 1,2s en 3G

Carga por tiers en dos fases adaptativa

El cliente arranca con un tier estático según capacidad detectada y lo corrige en caliente leyendo FPS reales: primero llega la geometría liviana, luego las texturas PBR completas. Verificado con tests que simulan red lenta.

LODAdaptiveNetwork tests
~300 impresiones/mes en picos

Cola de impresión y gestión de pedidos

Detrás de la vitrina hay una cola que ordena trabajos por prioridad y tiempo de slicing estimado, balanceando el parque de impresoras. Los pedidos entran, se programan y se trackean hasta el despacho.

QueueSchedulingSlicing
ETA con ±8% de error

Estimación de slicing y tiempos

Antes de aceptar un pedido el sistema estima material, tiempo de impresión y costo a partir del GLB, para no comprometer fechas imposibles en los meses de mayor demanda.

SlicingCosting
cache-hit 94% · TTFB 30ms

CDN y caché multinivel de modelos

Los GLB comprimidos se sirven desde CDN con caché de borde y un service worker que precarga la siguiente pieza del recorrido. El segundo visitante baja casi todo desde caché.

CDNService workerEdge cache
0 pedidos perdidos en picos

Tracking de pedidos y picos de demanda

Cada pedido emite eventos de estado (en cola → imprimiendo → curado → despachado) que alimentan el tracking del cliente y métricas internas para anticipar los picos estacionales.

Event-drivenTracking
Bajo el capó

Las piezas que lo sostienen

Código real del proyecto — los fragmentos que sostienen la idea, tal cual viven en el repositorio.

app/components/Museum.tsx
TSX
function makeMarbleMaterial() {
  const mat = new MeshStandardMaterial({ color: "#efe9df", roughness: 0.6 });
  mat.onBeforeCompile = (shader) => {
    shader.uniforms.uAlbedo = { value: MARBLE_ALBEDO };
    shader.uniforms.uMarbleScale = { value: MARBLE_SCALE };
    // Posición y normal en espacio de MUNDO hacia el fragment.
    shader.vertexShader =
      "varying vec3 vTriPos;\nvarying vec3 vTriNrm;\n" + shader.vertexShader
        .replace("#include <begin_vertex>",
          "#include <begin_vertex>\n  vTriPos = (modelMatrix * vec4(position,1.0)).xyz;\n" +
          "  vTriNrm = normalize(mat3(modelMatrix) * normal);");
    // Pesos triplanar desde la normal (sesgados por pow 4).
    shader.fragmentShader =
      "uniform sampler2D uAlbedo;\nvarying vec3 vTriPos;\nvarying vec3 vTriNrm;\n" +
      "vec3 mtBlend(vec3 n){ vec3 b=pow(abs(n),vec3(4.0)); return b/max(b.x+b.y+b.z,1e-4); }\n" +
      shader.fragmentShader.replace("#include <color_fragment>",
        "#include <color_fragment>\n  { vec3 bl = mtBlend(vTriNrm); float s = uMarbleScale;\n" +
        "    float m = texture2D(uAlbedo, vTriPos.zy*s).g*bl.x\n" +
        "            + texture2D(uAlbedo, vTriPos.xz*s).g*bl.y\n" +
        "            + texture2D(uAlbedo, vTriPos.xy*s).g*bl.z;\n" +
        "    diffuseColor.rgb *= (0.74 + 0.46 * m); }");
  };
  mat.customProgramCacheKey = () => "museum-marble-triplanar";
  return mat;
}

Mármol triplanar sobre escaneos sin UVs. Los escaneos STL no traen coordenadas UV. Se inyecta mármol muestreando en posición de mundo sobre tres ejes y mezclando por la normal.

app/lib/useExperienceTier.ts
TypeScript
async function detectTier(): Promise<ExperienceTier> {
  // 1) GPU: tier 0-3 por benchmark del renderer.
  let result: { tier: number; isMobile?: boolean };
  try { result = await getGPUTier(); }
  catch { result = { tier: 0, isMobile: false }; } // sin WebGL -> lo peor

  let visualTier: VisualTier =
    result.tier >= 3 ? "high" : result.tier === 2 ? "mid" : "low";

  // Móvil: misma GPU rinde menos (throttling térmico, batería).
  if (result.isMobile) visualTier = lowerTier(visualTier, 1);

  // 2) Specs: poca RAM o pocos hilos -> bajar otro escalón.
  const mem = readDeviceMemory();
  if (typeof mem === "number" && mem < 4) visualTier = lowerTier(visualTier, 1);
  const cores = navigator.hardwareConcurrency;
  if (typeof cores === "number" && cores < 4) visualTier = lowerTier(visualTier, 1);

  // 3) saveData / red 2g -> capear calidad y cortar prefetch.
  const reducedMotion = matchesMedia("(prefers-reduced-motion: reduce)");
  return { visualTier, ...tierToSettings(visualTier), reducedMotion, ready: true };
}

Detección de tier de calidad adaptativo (SSR-safe). Clasifica el dispositivo una sola vez combinando benchmark de GPU (detect-gpu), RAM, hilos y red, y baja escalones por móvil/memoria/CPU. Es solo el punto de partida: <PerformanceGuard> corrige luego por FPS reales. Llama getGPUTier() en un effect para no suspender el árbol y evitar mismatch de hidratación.

Lo resuelto

En concreto

Un solo Canvas con navegación espacial accesible y un 'modo museo' de estatuas con spotlight.

Mármol PBR triplanar procedural aplicado sobre escaneos sin coordenadas UV.

Carga por tiers en dos fases con corrección adaptativa por FPS en runtime, verificada con tests de red.

Pipeline propio de optimización de assets: 56 GLB de 91MB a 61MB (Draco + meshopt).

Estudio en crecimiento: la vitrina alimenta una operación que ronda las 20 impresiones por semana, con picos de cientos de impresiones en los meses fuertes.