AI SERVER STUDIO · ACADEMYCurso práctico de interfaces 3D
Curso basado en el proyecto real

Construye un configurador web 3D realista e interactivo

Aprende a crear una experiencia como el comparador de servidores: modelos procedurales, materiales PBR, iluminación controlada, raycasting, etiquetas, fichas de producto, cotizaciones dinámicas, animaciones y diseño responsive.

10módulos progresivos
26lecciones prácticas
8–12 hduración sugerida
1configurador final funcional
0%

Tu avance

0 de 26 lecciones completadas

Módulo 0

Qué vas a construir

Un sitio comercial con una escena 3D navegable y una interfaz de producto conectada a datos reales.

0.1 Resultado final y alcance

Tu proyecto tendrá un configurador tridimensional con cámara orbital, piezas seleccionables, vista explosionada, materiales realistas, precios, enlaces de compra y varias configuraciones.

HTML + CSSInterfaz y paneles
Three.jsEscena WebGL
Datos JSProductos y precios

0.2 Requisitos

HTML, CSS y JavaScript básicos
Chrome o Edge actualizado
Editor como VS Code
Python o Node para servidor local
No necesitas saber Blender. En este curso construiremos el equipo con geometrías procedurales de Three.js. Después podrás sustituir piezas por modelos GLB/GLTF.
Módulo 1

Arquitectura y preparación

Organiza los archivos para que la escena 3D, la interfaz y los datos puedan crecer sin convertirse en un solo bloque inmanejable.

1.1 Estructura mínima

mi-configurador-3d/
├── index.html
├── styles.css
├── app.js
├── curso.html
└── assets/
    ├── models/
    └── textures/

El proyecto entregado sigue esta separación: index.html contiene la interfaz, styles.css el sistema visual y app.js toda la escena.

1.2 Import map y módulos ES

index.html
<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.185.1/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.1/examples/jsm/"
  }
}
</script>
<script type="module" src="app.js"></script>
Los módulos ES suelen requerir un servidor local. Ejecuta python -m http.server 8080 y abre http://localhost:8080.
Módulo 2

Escena, cámara y renderizado

Construye el núcleo WebGL, configura color, sombras y controles orbitales.

2.1 Inicializar Three.js

app.js
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x070a10);
scene.fog = new THREE.FogExp2(0x070a10, 0.018);

const camera = new THREE.PerspectiveCamera(36, 1, 0.05, 100);
camera.position.set(14.5, 10.2, 15.5);

const renderer = new THREE.WebGLRenderer({
  antialias: true,
  powerPreference: 'high-performance'
});
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.shadowMap.enabled = true;

2.2 OrbitControls y resize

controles y tamaño
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.055;
controls.target.set(0, 4.35, 0);
controls.minDistance = 7;
controls.maxDistance = 34;

function resize() {
  const rect = viewport.getBoundingClientRect();
  camera.aspect = rect.width / rect.height;
  camera.updateProjectionMatrix();
  renderer.setSize(rect.width, rect.height, false);
}
new ResizeObserver(resize).observe(viewport);

El objetivo es que la escena ocupe únicamente el área central, no toda la ventana. Por eso se mide el contenedor viewport.

Módulo 3

Iluminación PBR sin sobreexposición

Aprende a conservar reflejos y RGB sin convertir las superficies claras en manchas blancas.

3.1 La cadena de exposición

El brillo final no depende de una sola luz. Es el resultado de la suma de luces directas, entorno, emisivos, exposición y bloom.

Luces físicasKey, fill, rim, RGB
Tone mappingACES + exposure
PostprocesoBloom selectivo
Síntoma: si el piso, la fuente o la GPU pierden textura y quedan blancos, primero reduce luces y exposición. No intentes resolverlo solo oscureciendo materiales.

3.2 Preset equilibrado

preset usado en la versión corregida
const LIGHTING_PRESETS = {
  balanced: {
    exposure: 0.72,
    hemi: 0.72,
    key: 1.85,
    rim: 24,
    fill: 14,
    accent: 3.2,
    secondary: 1.5,
    emissive: 0.34,
    floor: 0.09,
    bloomHigh: 0.11
  }
};

renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.72;

Los números no son universales, pero sirven como punto de partida consistente para una escena pequeña con materiales metálicos y vidrio.

3.3 Bloom controlado

UnrealBloomPass
const bloomPass = new UnrealBloomPass(
  new THREE.Vector2(1, 1),
  0.11, // fuerza
  0.28, // radio
  0.92  // threshold: solo altas luces
);
Regla práctica: usa un threshold alto para que el bloom afecte las tiras RGB y no toda la carcasa. La versión del configurador incluye tres presets: equilibrada, suave y presentación.
Módulo 4

Modelado procedimental por componentes

Construye gabinete, GPU, motherboard y ventiladores a partir de cajas, cilindros, toros y grupos.

4.1 Un componente = un Group

fábrica de GPU
function createGPU(accent, isSecond = false) {
  const gpu = new THREE.Group();
  gpu.name = isSecond ? 'GPU 2' : 'GPU 1';

  const body = new THREE.Mesh(
    new THREE.BoxGeometry(5.45, 0.95, 2.20),
    new THREE.MeshStandardMaterial({
      color: 0x202a38,
      metalness: 0.78,
      roughness: 0.27
    })
  );
  gpu.add(body);
  return gpu;
}

Cada grupo conserva posición base, posición objetivo de explosión, identificador de producto y un punto de anclaje para la etiqueta HTML.

4.2 Reutilizar primitivas

Rounded boxes

Carcasas, heatsinks, módulos RAM y fuente.

Cylinders

Ventiladores, tornillos, capacitores y plataforma.

Torus

Anillos RGB y bordes luminosos.

Curves + TubeGeometry

Cables de alimentación y heatpipes.

4.3 Jerarquía y pivotes

Para abrir el panel de vidrio, el grupo debe tener su pivote cerca de la bisagra. Para girar un ventilador, solo se anima el rotor, no todo el marco.

Diseña la jerarquía pensando primero en qué parte se va a mover. Un modelo visualmente correcto pero con pivotes equivocados será difícil de animar.
Módulo 5

Materiales, vidrio y etiquetas

Da identidad visual a las piezas sin depender de texturas descargadas.

5.1 MeshStandardMaterial y MeshPhysicalMaterial

material físico para vidrio
const glass = new THREE.MeshPhysicalMaterial({
  color: 0x8fdce8,
  transmission: 0.82,
  transparent: true,
  opacity: 0.24,
  roughness: 0.12,
  metalness: 0,
  thickness: 0.18,
  ior: 1.45,
  side: THREE.DoubleSide
});

El vidrio debe seguir permitiendo leer los componentes. Demasiada opacidad o iluminación interna intensa produce una caja lechosa.

5.2 CanvasTexture para marcas y PCB

etiqueta generada con Canvas 2D
function labelTexture(title, subtitle) {
  const canvas = document.createElement('canvas');
  canvas.width = canvas.height = 1024;
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#111821';
  ctx.fillRect(0, 0, 1024, 1024);
  ctx.fillStyle = '#f7fafc';
  ctx.font = '900 78px system-ui';
  ctx.fillText(title, 92, 390);
  ctx.font = '700 29px system-ui';
  ctx.fillText(subtitle, 96, 445);
  return new THREE.CanvasTexture(canvas);
}
Módulo 6

Productos y cotizaciones basadas en datos

Separa la información comercial de la geometría para poder crear varias propuestas con el mismo motor 3D.

6.1 Modelo de datos

producto
const products = [
  {
    id: 'gpu1',
    name: 'RTX 3090 · GPU principal',
    model: 'NVIDIA GeForce RTX 3090 · 24 GB',
    price: 24500,
    phase: 1,
    retailer: 'Mercado Libre',
    url: 'https://...',
    specs: [
      ['VRAM', '24 GB'],
      ['Consumo', '350 W']
    ]
  }
];

6.2 Perfiles de cotización

dos equipos, una interfaz
const quoteProfiles = {
  full: {
    name: 'Servidor IA completo',
    products: fullProducts,
    tags: ['LLM', 'Imagen', 'Video']
  },
  compact: {
    name: 'Servidor LLM + imagen',
    products: compactProducts,
    tags: ['Qwen', 'DeepSeek', 'ComfyUI']
  }
};

Al cambiar de perfil, reconstruyes el modelo, actualizas la lista y recalculas el total. La interfaz no necesita duplicarse.

Módulo 7

Selección, raycasting y hotspots

Conecta el clic sobre una geometría con su ficha comercial en el DOM.

7.1 Identificar cada malla

metadata de selección
mesh.userData.componentId = 'gpu1';

function pickAt(clientX, clientY) {
  const rect = renderer.domElement.getBoundingClientRect();
  pointer.x = ((clientX - rect.left) / rect.width) * 2 - 1;
  pointer.y = -((clientY - rect.top) / rect.height) * 2 + 1;
  raycaster.setFromCamera(pointer, camera);

  const hits = raycaster.intersectObject(modelRoot, true);
  return hits.find(hit => hit.object.userData.componentId);
}

7.2 Etiquetas HTML proyectadas

3D → coordenadas de pantalla
const point = anchor.getWorldPosition(new THREE.Vector3());
point.project(camera);

const x = (point.x * 0.5 + 0.5) * viewport.clientWidth;
const y = (-point.y * 0.5 + 0.5) * viewport.clientHeight;

label.style.left = `${x}px`;
label.style.top = `${y}px`;

Los hotspots son HTML, así que pueden tener textos nítidos, tooltips, accesibilidad y eventos normales. Three.js únicamente calcula dónde colocarlos.

Módulo 8

Animación, enfoque y experiencia de usuario

Añade movimiento solo donde comunica algo: ensamblaje, apertura, rotación y foco.

8.1 Vista explosionada

interpolación de posiciones
function setExploded(enabled) {
  for (const group of componentGroups.values()) {
    const base = group.userData.basePosition.clone();
    const offset = enabled
      ? group.userData.explode
      : new THREE.Vector3();
    group.userData.targetPosition = base.add(offset);
  }
}

// En el loop:
group.position.lerp(group.userData.targetPosition, 0.105);

8.2 Enfocar un componente

Calcula el Box3 de la pieza, obtiene centro y tamaño, y anima cámara y target. El encuadre debe ajustarse al volumen real, no usar una distancia fija.

8.3 UI responsive

Escritorio

Lista izquierda, escena central e inspector derecho.

Tablet

Inspector flotante y escena con más espacio.

Móvil

Lista lateral deslizable e inspector inferior.

Accesibilidad

Botones, etiquetas, foco y contenido equivalente fuera del canvas.

Módulo 9

Rendimiento, pruebas y publicación

Entrega una experiencia estable en diferentes GPUs y navegadores.

9.1 Tres niveles de calidad

  • Alta: DPR hasta 2, sombras y bloom.
  • Media: DPR 1.35, sombras y bloom reducido.
  • Baja: DPR 1, sin bloom y sombras simplificadas.
Reducir el pixel ratio suele producir más mejora que eliminar pequeños objetos. En pantallas 4K, DPR 2 puede multiplicar mucho la carga.

9.2 Pruebas indispensables

Chrome, Edge y Firefox
Pantalla 1366×768
Teléfono vertical
GPU integrada
RGB encendido y apagado
Modo de calidad baja
Todos los enlaces de compra
Totales de cada cotización

9.3 Publicación

El sitio puede publicarse como contenido estático en Vercel, Netlify, GitHub Pages, Cloudflare Pages o un hosting convencional. Si usas modelos GLB, activa compresión y cache de larga duración.

servidor local
# Python
python -m http.server 8080

# Node.js
npx serve .
Proyecto final

Crea tu propio configurador comercial 3D

Elige un producto distinto y aplica la misma arquitectura de principio a fin.

Entrega obligatoria

Dos configuraciones del producto
Cinco componentes seleccionables
Materiales PBR legibles
Iluminación sin clipping
Panel de información
Precio total dinámico
Vista explosionada
Diseño móvil funcional

Ideas de proyecto

Estudio de grabación

Micrófono, interfaz, monitores y acústica.

Kit fotovoltaico

Paneles, inversor, baterías y protecciones.

Cocina modular

Muebles, cubierta, electrodomésticos y acabados.

Rack de homelab

Router, switch, servidor, NAS y UPS.

Criterio de éxito: un visitante debe entender qué está comprando, qué cambia entre configuraciones y cuánto cuesta sin leer documentación externa.
Código copiado