Diario
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Progreso
Sección titulada «Progreso»- three 0.186.0,
@types/three0.186.0, Vite 8.3.0, TypeScript 7.0.2, Playwright 1.63.0 y glTF Transform 4.5.0 fijados en el propiopackage.jsondel curso y en su archivo de bloqueo -
check.sh: comprobación de tipos, los scripts de Node.js, cada página de lección sondeada en Chromium sin interfaz, la compilación de producción, comparados conexpected/ - CI en Ubuntu, Windows y macOS
- Lección 1: escena, cámara, renderizador
- Lección 2: geometrías, materiales, luces y sombras
- Lección 3: color, mapeo de tonos y entornos HDR
- Lección 4: modelos glTF y animaciones
- Lección 5: interacción,
Raycastery controles de cámara - Lección 6: TSL y materiales de nodos
- Lección 7: posprocesado con
RenderPipeline - Lección 8: rendimiento, medido
- Lección 9: React Three Fiber y drei
- Lección 10: física con Rapier en WebAssembly
- Lección 11: WebXR, emulado
- Lección 12: pruebas y CI
- Lección 13: proyecto, el mástil de guitarra 3D de GuitarAlchemist
- Lección 14: laboratorio, Guitar Alchemist en 3D, quince experimentos medidos
- Curso completo
- Demos en vivo: cada página de lección y cinco escenas completas, publicadas en el sitio con un panel Try it
three.js r186 y las bibliotecas de su entorno son software de otros; esta tabla recoge lo que las lecciones encontraron en ellas, no en las páginas que el curso escribe. Casi todo viene del paso a WebGPURenderer, lo bastante reciente como para que a menudo sea la costumbre de WebGL la que se equivoca. Nada se ha reportado aguas arriba, salvo donde la columna Estado nombra una incidencia existente.
| Esperado | Lo que pasa | Dónde | Medición | Estado |
|---|---|---|---|---|
WebGPURenderer informa las llamadas de dibujo que tiene la escena, como WebGLRenderer |
Con tone mapping, o con un espacio de color de salida distinto del de trabajo, renderiza a un destino y lo dibuja en una pasada de salida | three.js r186 WebGPURenderer |
2 llamadas de dibujo y 13 triángulos para un cubo, frente a 1 en WebGL; además los dos objetos info no tienen la misma forma |
Reproducido 2026-09-16 |
@types/three describe toJSON() tal como lo escribe el runtime |
En 0.186.0 Object3DJSON declara children como cadenas y no tiene ni geometries ni materials; el runtime escribe objetos y ambos arreglos |
@types/three 0.186.0 |
Los errores del compilador se conservan en errors/l01_tojson_types.ts |
Reproducido. Ninguna incidencia aguas arriba buscada ni abierta 2026-09-16 |
PCFSoftShadowMap funciona en WebGPURenderer |
Retirado en r186, y avisa. R3F lo pone para cualquier shadows verdadero y recibe el mismo aviso en cada render de <Canvas> |
three.js r186, @react-three/fiber 9.7.0 | LunarLanderEngine.ts y MinimalThreeInstrument.tsx de GA lo siguen combinando con WebGPURenderer |
Reproducido 2026-09-16 · 2026-09-16 · Todavía no en GA, que fija three 0.180.0, donde sigue funcionando; 2026-09-24 |
| Una luz puntual y un foco convierten lúmenes a candelas igual | SpotLight.power usa π en lugar de 4π y no cambia con el ángulo del cono |
three.js SpotLight.power |
800 lm dan 63,66 cd en una puntual y 254,65 en un foco | Reproducido 2026-09-16 |
| Construir un entorno equirectangular cuesta más o menos una pasada | El PMREM cuesta 17 renders: 1 en el primer nivel y luego 2 por cada uno de los 8 restantes, incluso para una textura equirectangular simple | three.js PMREMGenerator |
17 renders para un entorno de 256 por 128 | Reproducido, por diseño 2026-09-16 |
| El empaquetador incluye los decodificadores Draco que el navegador carga | Desde r185 DRACOLoader los resuelve con import.meta.url, así que Vite copia los cinco |
three.js r185+ DRACOLoader, Vite |
1,31 MB empaquetados donde un navegador carga dos archivos; el build además avisa de que three.webgpu pasa de 500 kB |
Reproducido, comportamiento cambiado desde r184 2026-09-16 |
| La compresión conserva todos los vértices de la geometría | Draco y meshopt eliminan ambos los dos vértices polares que crea SphereGeometry y que ningún triángulo usa; el weld() de Draco además fusiona las esquinas del cuerpo no indexado |
Draco, meshopt, glTF Transform 4.5.0 | Los recuentos de vértices antes y después, en expected/ |
Reproducido, defendible 2026-09-16 |
El <Text> de drei se dibuja en WebGPURenderer igual que en WebGL |
Dibuja un quad en blanco: troika-three-text inyecta su shader con onBeforeCompile, que el renderer de nodos nunca llama |
drei 10.7.8 | Quad en blanco | Reproducido. Sigue abierto: si existe un troika-three-text listo para WebGPU 2026-09-16 |
setColorAt colorea las instancias sin importar qué hizo el primer render |
Un InstancedMesh lo ignora si su primer render no tenía colores de instancia |
three.js InstancedMesh |
Los marcadores del mástil siguieron blancos hasta que el atributo se reservó de antemano | Reproducido, sorteado 2026-09-16 |
WebXR sobre WebGPURenderer se comporta como sobre WebGLRenderer |
Necesita XRGPUBinding y la característica webgpu; su mensaje de error nombra un VRButtonGPU que no existe; WebGLXRFallback intercambia los renderers pero los controles tomados del primero dejan de recibir eventos |
three.js r186, WebXR sobre WebGPU | Solo el WebGLRenderer clásico dibujó ambos ojos bajo IWER |
Reproducido 2026-09-16 |
InstancedMesh funciona con morph targets |
Falla con una sola instancia, porque morphTargetInfluences nunca se crea, y de otra forma con varias, en UniformArrayNode.updateBuffer. Además necesita geometry.morphTargetsRelative = true, sin decirlo |
three.js r186 | Dos fallos distintos, uno por cantidad de instancias | Reproducido 2026-09-17 |
BatchedMesh agrupa en pocas llamadas de dibujo en todos los backends |
En WebGPU dibuja una llamada por objeto | three.js r186 BatchedMesh, backend WebGPU |
44 llamadas para un mástil frente a 3 en WebGL 2, que usa WEBGL_multi_draw |
Reproducido 2026-09-17 |
renderer.info.memory.texturesSize cuenta las texturas comprimidas |
Cuenta 0 bytes para las texturas KTX2, y cuenta los destinos de render en su lugar | three.js r186 renderer.info.memory |
0 bytes para el juego de maderas comprimido, lo que impidió terminar el experimento 6 | Reproducido. Sigue abierto: medir la memoria GPU de KTX2 con una herramienta de GPU 2026-09-17 |
powerPreference elige una GPU |
Chromium en Windows lo ignora y avisa; los demás sistemas no | Chromium 153 | check.sh filtra la línea |
Conocido aguas arriba, incidencia de Chromium 369219127 2026-09-16 |
El addon RapierPhysics de three.js sigue una versión actual de Rapier |
El de r186 sigue cargando 0.17.3 desde skypack.dev, mientras que el curso usa 0.20.0 | three.js r186 examples/jsm/physics/RapierPhysics |
Dos versiones menores de diferencia | Reproducido, el curso no usa el addon 2026-09-16 |
| El build WebGPU de R3F solo incluye el punto de entrada WebGPU | Importa three junto a three/webgpu, así que el núcleo WebGL también se empaqueta |
@react-three/fiber 9.7.0 | 565 kB gzip frente a 210 kB para la misma escena sin React | Reproducido. Sigue abierto: apuntar three a three/webgpu con un alias 2026-09-17 |
Experimentos
Sección titulada «Experimentos»La lección 14 llevó a cabo quince experimentos en el laboratorio 3D de Guitar Alchemist. Cada hipótesis y sus predicciones numéricas se registraron el 16 de septiembre, el día antes de las mediciones: eso es lo que permite que una fila diga refutada. De las 61 predicciones, 19 fallaron total o parcialmente y 2 no se pudieron medir. Medido en una RTX 5080 con Chromium 153, tiempos de GPU con consultas de marca de tiempo de WebGPU. El detalle está en la lección 14.
| Pregunta | Hipótesis | Resultado | Veredicto |
|---|---|---|---|
| Qué forma de dibujar 16 mástiles de guitarra cuesta menos: la de GA, instanciada, en lote o fusionada | Las llamadas de dibujo mandan en el tiempo de CPU; la GPU apenas se mueve entre ellas | La versión en lote sobre WebGPU sacó 44 llamadas, no las 4 o menos previstas. Los 16 mástiles de GA cuestan 2,9 ms de CPU, no los 10 ms o más previstos | Refutada en su mayor parte |
| Reescribir los vértices de una cuerda que vibra en la CPU frente a hacerlo en TSL, hasta 600 cuerdas | A 600 cuerdas la reescritura en CPU cuesta más, y el coste de GPU es parecido | CPU 1,8 ms frente a TSL 0,36 ms, un factor de 5, como se predijo. Pero TSL costó 1,7 veces el tiempo de GPU de la versión CPU | Confirmada en CPU, refutada en GPU |
Señalar una nota entre 10 000: Raycaster frente a una pasada de identificadores en GPU |
La selección por GPU gana con 10 000 objetos | Raycaster 0,465 ms frente a 3,395 ms de la selección por GPU |
Refutada |
| Transponer 49 152 brazaletes de clases de altura, en CPU frente a TSL | La CPU paga reconstruir 49 152 matrices por fotograma: 4 ms o más | CPU 2,455 ms, por debajo de lo previsto. TSL 0,29 ms, como se predijo | Confirmada para TSL, refutada para la CPU |
| Una nube de puntos OPTIC-K hasta 1 000 000 de puntos, y si el cómputo TSL exige WebGPU | Los puntos siguen siendo baratos hasta el millón; el compute shader no corre en WebGL 2 | Los puntos aguantaron. El compute shader sí corrió en WebGL 2, por transform feedback, a 2,8 ms de GPU | Confirmada en los puntos, refutada en el backend |
| Cuánto cuestan las texturas de madera sin comprimir, y cuánto ahorra KTX2 | RGBA8 cuesta unos 22 MB; KTX2 en BC7 cuesta alrededor de un cuarto | 21,33 MB confirmados. La cifra de KTX2 no se pudo leer: renderer.info cuenta 0 para texturas comprimidas |
Mitad confirmada, mitad no medible |
Una rejilla de materiales PBR: cuántos programas de shader, y qué añade MeshPhysicalMaterial |
Un programa por tipo de material, compartido en la rejilla; el material físico cuesta más tiempo de GPU | 16 programas en ambos casos, como se predijo. El material físico costó 1,46 veces el tiempo de GPU | Confirmada |
| Cuánto cuesta un mapa de sombras dinámico frente a uno horneado | Un mapa dinámico duplica más o menos las llamadas de dibujo | 13 llamadas frente a 8, un factor de 1,6. El horneado tardó 398 ms, como se predijo | Confirmada a grandes rasgos |
| Cuánto cuesta el bloom a 1080p | Entre 0,5 y 1,5 ms de GPU | 0,135 ms, cuatro veces por debajo de la predicción más baja | Refutada |
| Un muro de 1000 guitarras con LOD y frustum culling | El LOD divide los triángulos por unos 10 | Por 11,2 | Confirmada |
| Si el CCD de Rapier impide que una púa cinemática atraviese una cuerda | El CCD impide la travesía | La púa atravesó a 30 y a 60 pasos por segundo, con CCD activado o no | Refutada |
| Si un diapasón está a escala 1:1 en WebXR, bajo la emulación de IWER | De la cejuela al traste doce se miden 0,324 m | 0,324 m | Confirmada |
| Con cuánta antelación hay que programar una nota para que WebAudio y el fotograma coincidan | La antelación ingenua vale más o menos la suma de las latencias, 50 ms, con un fotograma de margen | 31,8 ms, 18 ms menos que la suma | Refutada |
| Cuánto cuesta React Three Fiber frente a three.js a secas, para la misma escena | Barato por fotograma, caro al arrancar (+30 a 150 ms) y en el bundle (+50 a 90 kB) | Barato por fotograma, como se predijo. Primer fotograma +430 ms y bundle +195 kB, ambos muy por encima | Confirmada por fotograma, refutada en ambos costes |
| Si una proporción de píxeles adaptativa se estabiliza en una GPU débil | El tiempo de GPU es proporcional al número de píxeles, y el regulador se estabiliza en menos de 60 fotogramas | Se estabilizó en 0,655 en menos de 60 fotogramas | Confirmada |
2026-09-16 — Versiones
Sección titulada «2026-09-16 — Versiones»npm view threeda 0.186.0, publicada el 8 de septiembre de 2026, y@types/three0.186.0. El curso las fija de forma exacta encode/threejs/package.json, con Vite 8.3.0, TypeScript 7.0.2, Playwright 1.63.0 y su Chromium 153, glTF Transform 4.5.0,draco3dgltf1.5.7,meshoptimizer1.2.0 ypngjs7.0.0, sobre Node.js 24.21.0 en CI.- La versión r186 es la versión npm
0.186.0. Las lecciones citan el código fuente en la etiquetar186de mrdoob/three.js. require('three/package.json')falla: el mapaexportsdel paquete no lo incluye. La comprobación de versión decheck.shlee el archivo confsen su lugar.- Las páginas de la documentación están en
https://threejs.org/docs/pages/<Class>.htmlyhttps://threejs.org/manual/pages/<page>.html; las lecciones enlazan esas URL, todas comprobadas.
2026-09-16 — Medir páginas en un navegador sin interfaz
Sección titulada «2026-09-16 — Medir páginas en un navegador sin interfaz»- Cada página de lección informa de lo que hizo el renderizador mediante una promesa
window.probe, yscripts/probe.mjsarranca Vite, abre la página con Playwright a 800 por 450 píxeles y una relación de píxeles de 1, e imprime el informe. Las páginas que se animan usan pasos fijos cuando se sondean, así que el tercer fotograma es el mismo en todas las máquinas. - Mi primera sonda se colgaba en la página de
WebGLRenderer: la página reemplazabawindow.probedespués de quepage.evaluatehubiera empezado a esperar la promesa antigua. Ahora las páginas resuelven una promesa creada una sola vez, ensrc/probe.ts, yprobe.mjsse rinde a los 30 segundos. - Los colores se leen de la captura de pantalla, en las posiciones que indica la página.
- El modo sin interfaz predeterminado de Playwright en Windows da WebGPU en la RTX 5080 del autor (“nvidia, blackwell”).
chromium-headless-shell, la compilación más ligera, no tiene adaptador WebGPU:WebGPURendererrecurre a WebGL 2, sobre SwiftShader.check.shejecuta la lección 1 en ambos.
2026-09-16 — Con qué renderizan los runners de CI
Sección titulada «2026-09-16 — Con qué renderizan los runners de CI»- La primera ejecución de CI, 35114590607, falló en los tres sistemas operativos, por tres motivos: el
coordinateSystemque informa la página depende del backend; algunos colores difieren en uno respecto a la GPU del autor; y en macOS, el aviso de Vite, en stderr, llegaba antes que sus líneas de stdout. Ahora las sondas filtran las líneas que dependen del backend,compare.mjsacepta una diferencia de 2 por canal en los colores, y el stderr de la compilación se imprime después de su stdout. - La ejecución 35115118564 pasó. Sus registros muestran con qué dibuja cada runner.
ubuntu-24.04ywindows-2025-vs2026no tienen GPU: WebGPU no está disponible, y tantoWebGPURenderercomoforceWebGLejecutan WebGL 2 sobre SwiftShader (Subzero).macos-26-arm64tiene WebGPU, en un adaptador “apple”, y WebGL 2 en “ANGLE Metal Renderer: Apple Paravirtual device”; su headless shell usa SwiftShader (LLVM 10.0.0). - Dos colores difieren en uno en los runners: ACES convierte el lineal 0.18 en 127 en la GPU del autor y en 128 en CI, y Neutral convierte 0.05 en 33 y en 34.
- Así que una ejecución de CI en verde demuestra que las escenas se construyen, se cargan y producen los mismos contadores y colores, con un margen de 2, en un rasterizador por software y en la GPU de Apple. No demuestra nada sobre WebGPU en Windows o Linux.
2026-09-16 — Sorpresas
Sección titulada «2026-09-16 — Sorpresas»WebGPURenderercuenta una llamada de dibujo más de las que tiene la escena. Con mapeo de tonos, o con un espacio de color de salida distinto del espacio de trabajo, renderiza la escena en un destino y dibuja el resultado en una pasada de salida: 2 llamadas de dibujo y 13 triángulos para un cubo.WebGLRendererconvierte en cada shader e informa 1. Los objetosinfode los dos renderizadores tampoco tienen la misma forma.@types/threedescribe maltoJSON(). En 0.186.0,Object3DJSONdeclarachildrencomo cadenas y no tienegeometriesnimaterials, mientras que en tiempo de ejecución se escriben objetos y ambos arreglos. La lección 1 guarda los errores del compilador enerrors/l01_tojson_types.ts. No he buscado si ya existe una incidencia en three-types/three-ts-types, ni he abierto una.WebGPURendererlee la caja de la cámara de sombras una sola vez.ShadowNodellama aupdateProjectionMatrix()cuando construye la sombra; un cambio posterior necesita tu propia llamada.PCFSoftShadowMapya no existe enWebGPURendereren r186 y emite un aviso.LunarLanderEngine.tsyMinimalThreeInstrument.tsxde GA todavía lo usan conWebGPURenderer.- Una luz puntual de 800 lúmenes son 63.66 candelas, y una luz focal de 800 lúmenes 254.65:
SpotLight.powerusa π, no 4π, y no cambia con el ángulo del cono. - El PMREM cuesta 17 renderizados para un entorno de 256 por 128: 1 en el primer nivel, y luego 2 por cada uno de los otros 8. Ocurre incluso cuando
scene.environmentes una simple textura equirrectangular. - Desde r185,
DRACOLoaderencuentra sus decodificadores conimport.meta.url, algo que r184 no hacía. Vite copia entonces los cinco archivos de decodificador en la compilación, 1.31 MB, cuando un navegador carga dos. La compilación también avisa de quethree.webgpusupera los 500 kB. - Draco y meshopt descartan vértices. Los dos descartan los dos vértices de los polos que crea
SphereGeometryy que ningún triángulo usa; elweld()de Draco además fusiona las esquinas del cuerpo no indexado. - El
meshopt()de glTF Transform imprime líneasprune: Removed types... Accessoren stdout; están enexpected/tal cual.
2026-09-16 — GuitarAlchemist/ga
Sección titulada «2026-09-16 — GuitarAlchemist/ga»El curso lee GA en el commit 05c8eda, que usa three 0.180. 139 archivos bajo directorios src importan three; 33 de ellos llaman a requestAnimationFrame, 3 a setAnimationLoop; 29 crean un WebGLRenderer y 8 un WebGPURenderer; 15 usan Clock, obsoleto desde r183. Nada de lo que sigue se ha comunicado a GA.
ThreeFretboard.tsxespera queWebGPURendererlance una excepción cuando falta WebGPU, y dice “Using WebGPU renderer” en todas las máquinas, ya que el renderizador recurre a WebGL 2 en su lugar (lección 1). Sus sombras solo se activan para unWebGLRenderer, así que la ruta alternativa no tiene ninguna (lección 2).ThreeFretboard.tsxpidesamples: 8; la especificación de WebGPU permite 1 o 4 muestras para una textura. Qué hace r180 con 8 en cada backend está por verificar.- Su luz puntual de 0.6 cd con
distance: 20da alrededor del 5 % de la luz principal donde está más cerca del mástil (lección 2), y una única textura de canvas sirve como mapa de color, de rugosidad, de normales y de relieve. - Su textura de madera no tiene
colorSpace, así que se ve más clara de como se pintó, y su entorno es un degradado de 8 bits cuyo PMREM el renderizador construye de todos modos (lección 3). Cuánto difiere en pantalla el color de la madera está por verificar en un navegador. Guitar3D.tsxconstruye un entorno negro confromScenesobre una escena que solo contiene una luz ambiental, y anuncia compatibilidad con KTX2 y meshopt sin configurar ninguno de los dos decodificadores (lecciones 3 y 4).Ocean.tsxcarga los decodificadores de Draco desde gstatic.com;DemerzelFaceOverlay.tsxoculta los errores de KTX2 reemplazandoconsole.errordurante una carga;HandAnimationTest.tsxactualiza unAnimationMixerque no tiene ninguna acción (lección 4).Experiments/ThreeJS-BSP-LoaderimportaWebGPURendererdesde una ruta eliminada en r167; el visor de embeddings del panel quita un listener de redimensionado con un nuevobind, lo que no quita nada.ThreeHeadstock.tsxañade un listener de clic al mismo canvas en cada ejecución de su efecto y nunca lo quita;TonalOrbit.tsxyMinimalThreeInstrument.tsxlanzan un rayo en cada evento de ratón, el segundo con unRaycasternuevo cada vez;InteractionHandler.ts, de Prime Radiant, lo hace como la lección; 4 de los 25 archivos que usanOrbitControlsnunca los liberan (lección 5).- El cielo GLSL de
Sunburst3D.tsx, copiado enImmersiveMusicalWorld.tsx, no puede ejecutarse enWebGPURenderer;FresnelGlowTSL.tsfija la intensidad y el color de su corona en el shader como constantes;MoebiusPassTSL.tses unShaderPassGLSL a pesar de su nombre (lección 6). Ocean.tsxyLunarLanderEngine.tsusanPostProcessing, renombradoRenderPipelineen r183, yOcean.tsxnunca libera el pipeline ni sus nodos;ForceRadiant.tsxse ejecuta enWebGPURenderersin los efectos de bloom yShaderPassde su camino WebGL, una “tarea de seguimiento”; los 10 archivos conEffectComposerlo usan correctamente para WebGL (lección 7).ThreeFretboard.tsxcrea una geometría y un material por traste y por marcador, reconstruye su escena cada vez que su proppositionses un array nuevo, incluido el[]por defecto, y no libera sus 29 sprites;NodeInstancer.tsinstancia bien sus nodos, con el culling desactivado; GA no usa niBatchedMeshniTHREE.LOD(lección 8).
2026-09-16 — Lecciones 5 a 8: punteros, shaders, efectos, recuentos
Sección titulada «2026-09-16 — Lecciones 5 a 8: punteros, shaders, efectos, recuentos»- Eventos de puntero reales en una página headless.
scripts/probe.mjsahora realiza los movimientos y arrastres que una página enumera, con el ratón de Playwright, y pregunta a la página qué vio después de cada uno. Chromium los convierte en eventospointermove,pointerdownypointerup, queOrbitControlsgestiona como los de un usuario: un arrastre de 120 píxeles giró la cámara 96°. - Una cámara fuera de la escena tiene una matriz desactualizada en un script. La primera versión de
l05-raycaster.tsproyectaba un punto a un NDC de −3.6: renderizar actualiza la matriz de mundo de la cámara, y un script de Node.js no renderiza.camera.updateMatrixWorld()lo arregló. - Una hoja de estilos compartida forma parte del hash de cada chunk. Añadir las reglas de maquetación de la lección 5 a
page.csscambió el nombre de todos los chunks del build, incluido el04-gltf-CCDSPzCq.jsque cita la lección 4. La lección 5 recibió su propia hoja de estilos, ycheck.shconstruye primero solo las páginas de las lecciones 1 a 4, con un filtroPAGES, antes de construirlo todo: con las páginas de las lecciones 5 a 8, Rolldown llamathree.tslal chunk WebGPU compartido en lugar dethree.webgpu. PostProcessingesRenderPipelinedesde r183, ypipeline.dispose()libera un solo material. Los 11 render targets del bloom y el de la pasada de escena siguen ahí hasta que se liberan los propios nodos.DirectRenderPipeline.renderrecibe la escena y la cámara, a diferencia deRenderPipeline.render(), así que TypeScript lo rechaza en una variableRenderPipeline; y dibuja un fondo liso como una esfera de 1 984 triángulos.renderer.info.renderse acumula entre las llamadas arender()de un mismo fotograma de animación. Una página que renderizaba 60 fotogramas en un bucle para cronometrarlos informaba de 610 061 draw calls; la lección 8 lee primero los recuentos.
2026-09-16 — Los runners de CI y las lecciones 5 a 8
Sección titulada «2026-09-16 — Los runners de CI y las lecciones 5 a 8»- La ejecución 35123228046 pasó en macOS (WebGPU sobre el adaptador “apple”) y falló en Linux y Windows, donde
WebGPURendererrecurre a WebGL 2 sobre SwiftShader. Cuatro diferencias, todas reales:- Las cadenas de bloom cuentan un programa más en WebGL 2: 14 en lugar de 13, 16 en lugar de 15.
- Con FXAA, el píxel del halo en SwiftShader es 135, 176, 197, donde la GPU del autor da 132, 174, 195 en ambos backends: 3 más de lo que acepta
compare.mjs. - Un
BatchedMeshse dibuja conWEBGL_multi_drawy cuenta como 2 draw calls, no 10 001. - El archivo de shader de WebGPU contiene GLSL, ya que la página se ejecutó en WebGL 2.
- Las páginas de la lección 8 con 800 000 triángulos agotaban el tiempo: el resultado de la sonda llegaba, pero la captura de pantalla de Playwright esperaba más de 30 segundos detrás de los 60 fotogramas cronometrados que seguían en cola en el rasterizador por software.
- La solución:
check.shcompara una sonda conexpected/<name>.webgl.txtcuando ese archivo existe y la página se ejecutó en WebGL 2. Los cinco archivos vienen dechromium-headless-shellen la máquina del autor, cuyo SwiftShader dio los mismos valores que los runners. Se compara la línea GLSL, y la línea WGSL solo se imprime. La lección 8 cronometra 20 fotogramas, y sus sondas esperan hasta 240 segundos (PROBE_TIMEOUT). La ejecución 35124756498 pasó en los tres sistemas operativos.
2026-09-16 — Lecciones 9 a 13: versiones
Sección titulada «2026-09-16 — Lecciones 9 a 13: versiones»- React 19.3.0 salió el 9 de septiembre de 2026, pero
@react-three/fiber9.7.0 declarareact>=19 <19.3: el curso fija React 19.2.8, con drei 10.7.8. R3F 10 y drei 11 son versiones alfa.@react-three/test-renderer9.1.1 y Vitest 5.0.1 prueban los componentes. - Rapier 0.20.0 se publicó el 8 de agosto de 2026. El addon
RapierPhysicsde three.js r186 todavía carga 0.17.3 desde skypack.dev, y@react-three/rapier2.2.0 fija 0.19.2. El curso usa tanto@dimforge/rapier3d-compatcomo@dimforge/rapier3d-deterministic-compat; sus clases tienen miembros privados, así que TypeScript rechaza el tipo de un módulo donde espera el del otro sin un cast. - IWER 2.4.0 emula unas Quest 3; pixelmatch 7.2.0 compara capturas de pantalla.
2026-09-16 — Lecciones 9 a 13: lo que encontraron las páginas
Sección titulada «2026-09-16 — Lecciones 9 a 13: lo que encontraron las páginas»- R3F 9.7.0 emite avisos con
WebGPURenderersin que nadie se lo pida. Elshadowsde<Canvas>valefalsepor defecto, y R3F establecePCFSoftShadowMappara cualquier booleano;WebGPURendererlo restablece con un aviso, una vez por render de<Canvas>. Su store también crea unTHREE.Clockobsoleto. - El
<Text>de drei dibuja un quad vacío enWebGPURenderer: troika-three-text inyecta su shader medianteonBeforeCompile, al que el renderizador basado en nodos nunca llama. - Los recuentos de renders dependen de la máquina. En
chromium-headless-shell, 10 actualizaciones de estado separadas por un fotograma dieron 6 renders en lugar de 11, y un movimiento de ratón de 5 pasos menos renders que en la GPU: React agrupa las actualizaciones y el navegador fusiona los eventos de puntero cuando los fotogramas son lentos. Las páginas usanflushSync, y no informan de recuentos tras acciones de puntero. - Chromium en Windows avisa de que
powerPreferencese ignora cada vez que R3F lo pasa; los otros sistemas operativos no.check.shfiltra la línea. - Las compilaciones determinista y estándar de Rapier dieron el mismo hash de estado en Windows x64, en Node.js y en el navegador. Con un paso variable entre 1/144 y 1/30 s, 16 de 24 selecciones cayeron en otro sitio y una atravesó un suelo de 20 cm. Una bola rápida cruzó una pared dinámica fina sin CCD, pero no una fija.
- IWER necesita
forceInstallen Chromium, que ya tiene unnavigator.xr, ystereoEnabled, o el viewport del ojo derecho mide 0 píxeles de ancho. - La primera sonda WebXR se colgó durante diez minutos mientras retenía el bloqueo de GPU compartido: el backend WebGL 2 lanzaba una excepción en cada fotograma XR, la página esperaba fotogramas indefinidamente, y la ejecución se detuvo a mano. La causa es el
XRWebGLLayer.framebufferde IWER,null, usado como clave de unWeakMapenWebGLState.drawBuffers. La página ahora captura los errores de render y acota sus esperas, yprobe.mjstermina por sí solo tras el doble de su tiempo límite más 30 segundos. - En r186,
WebGPURendererentra en una sesión WebXR sobre WebGPU solo conXRGPUBindingy la funcionalidadwebgpu; su mensaje de error menciona unVRButtonGPUque no existe.WebGLXRFallbackcambia de renderizador, pero los controladores que la página tomó del primer renderizador dejan de recibir eventos. Solo elWebGLRendererclásico renderizó ambos ojos con IWER. - Un
InstancedMeshignorasetColorAtsi su primer render no tenía colores de instancia: los marcadores del port se veían blancos hasta que el atributo se reservó de antemano. @react-three/test-renderernecesitaIS_REACT_ACT_ENVIRONMENT, o React avisa en cada actualización y R3F libera más tarde; su compilación CommonJS cargathree.cjsjunto a la compilación de módulos ES, sin dividir las clases que usa la escena.- Píxeles: la misma página dos veces dio bytes idénticos; WebGPU frente a ANGLE en la misma GPU difirió en 294 píxeles, frente a SwiftShader en 10 330, ninguno por encima del umbral por defecto de pixelmatch una vez excluido el antialiasing.
- Una imagen importada por una lección debe existir antes que la página: la lección 11 importó una vez una captura aún no convertida, y la compilación de Astro del árbol de trabajo compartido falló para las otras sesiones que trabajaban en él hasta que se añadió la imagen.
2026-09-16 — Lecciones 9 a 13 en los runners de CI
Sección titulada «2026-09-16 — Lecciones 9 a 13 en los runners de CI»- La ejecución 35175914560 pasó en los tres sistemas operativos a la primera. La compilación estándar de Rapier dio el hash de estado
68235a2bdba192f1también en Linux x64 y en macOS arm64, en Node.js y en el navegador, el mismo que la compilación determinista: para esta escena, y no como garantía. - macOS ejecutó las páginas en WebGPU con el adaptador “apple”; Linux y Windows, en el WebGL 2 de SwiftShader, donde el
ThreeFretboardde GA produjo sus 253 líneas de error de WebGL y R3F avisó 13 veces sobrePCFSoftShadowMapen lugar de 14. - Antes del push, la comprobación local comparaba la página alternativa de la lección 11 con su salida WebGL 2 en la GPU del autor: la página termina en WebGL 2 tras empezar en WebGPU.
check.shahora usa la salida WebGL 2 solo cuando la página se ejecutó en WebGL 2 desde el principio.
2026-09-16 — GuitarAlchemist/ga, lecciones 9 a 13
Sección titulada «2026-09-16 — GuitarAlchemist/ga, lecciones 9 a 13»Nada de lo que sigue se ha comunicado a GA.
- Los componentes React de GA usan R3F 8, drei 9 y React 18, con
WebGLRendereren los 6 archivos con<Canvas>;ThreeFretboard.tsxno usa R3F. El explorador BSP actualiza el estado de React con una copia de la posición de la cámara en cada fotograma, yGuitarAlchemistLogo3D.tsxpasa un objeto nuevo enargs, lo que reconstruye su geometría en cada render (lección 9). - Ninguna biblioteca de física: Cheese Avalanche está escrito a mano con un paso variable limitado a 1/30 s; el lunar lander usa un paso fijo de 1/120 s con un acumulador (lección 10).
- Ningún código WebXR (lección 11).
- 22 archivos de specs de Playwright, de los cuales los 7 que están fuera de la suite del panel, 6 de ellos sobre páginas 3D, no se ejecutan en ningún workflow de CI; esperas de 3 segundos para WebGPU; un
toBeTruthy()sobre el búfer de una captura; una comprobación de canvas negro que llama agetContext('2d')sobre un canvas WebGL y nunca puede pasar; 13 archivos de resultados de pruebas de una ejecución fallida guardados en el repositorio (lección 12). ThreeFretboard.tsx, reproducido y medido: 69 draw calls y 32 texturas para un mástil vacío; 10 renders de su padre con las mismas notas reconstruyen la escena 10 veces y pierden 29 texturas de sprites cada vez; un pixel ratio de hasta 6;samples: 8, que no dibuja nada en el WebGL 2 de SwiftShader; cuerdas el doble de gruesas, ya que un calibre se usa como radio; y una proponPositionClickque nunca se llama. El port dibuja el mismo mástil en 6 draw calls con 4 texturas, y selecciona notas (lección 13).
2026-09-17 — Demos en vivo
Sección titulada «2026-09-17 — Demos en vivo»- Las páginas se construyen con una segunda configuración de Vite,
vite.demos.config.ts, con la base/learn/threejs-demos/, enpublic/threejs-demos, que el sitio copia tal cual. Las fuentes de las páginas de las lecciones no cambian, ya que las lecciones 4, 8 y 13 citan su build; un plugin de esa configuración añade el panel Try it solo a las páginas construidas. Una página no se puede manejar desde fuera, así que cada control fija un parámetro de URL y recarga la página. El panel es lil-gui 0.17, la copia que three.js incluye enthree/addons/libs: ninguna dependencia nueva. - El build pesa 9.4 MB en 75 archivos. Los builds estándar y determinista de Rapier, cada uno con su WebAssembly incrustado en base64, ocupan 2.9 MB cada uno;
three.tsl0.69 MB.check.shlo vuelve a construir y lo compara con la copia confirmada (diff -r, salvo los modelos y el HDR regenerados). - Los marcos están en un
<details>cerrado, conloading="lazy": nada se carga hasta que un lector despliega uno. - La guitarra está modelada en código: no había ninguna guitarra glTF con licencia conocida. 47 405 triángulos en 32 draw calls; instanciación para los trastes, los marcadores, los polos, las selletas, las perillas y las clavijas.
- El
body.handlede Rapier es un flotante que empaqueta un índice y una generación:handle % 8no es un índice de paleta; cada púa guarda ahora el color de su número de lanzamiento. Y los colores fijados consetColorAtsolo llegaban a la GPU en un fotograma desetAnimationLoop: una sonda que llamaba arender()por su cuenta veía púas blancas. En r186,InstanceNodelos sube en su actualización por fotograma. - La página VR usa el
WebGLRendererclásico, como la lección 11 encontró necesario con IWER. Durante una sesión, su listener deresizeno debe hacer nada:WebGLRendereravisa «Can’t change size while VR device is presenting». - En una página del tamaño de un teléfono (emulación Pixel 7 de Playwright), los marcos medían al principio 150 píxeles de alto: los estilos del sitio anulan el atributo
heightdel iframe, así que la altura es ahora un estilo en línea,min(420px, 70vh). El panel empieza plegado en un marco estrecho. Con la CPU ralentizada 4 veces pero la GPU de escritorio del autor, las cinco escenas mantuvieron 60 fotogramas por segundo en WebGPU y con?webgl; en la GPU de un teléfono real de gama media está por verificar. - La primera sonda de una página que importa una dependencia nueva falló con «Execution context was destroyed»: Vite optimizó la dependencia y recargó la página. La segunda ejecución pasó.
2026-09-17 — Lección 14, el laboratorio 3D de Guitar Alchemist
Sección titulada «2026-09-17 — Lección 14, el laboratorio 3D de Guitar Alchemist»- Quince experimentos en
code/threejs/ga-lab, cada uno con una hipótesis y predicciones numéricas confirmadas en un commit el 16 de septiembre antes de su ejecución, medidos el 17 de septiembre en una RTX 5080 en Chromium 153 con consultas de marca de tiempo de WebGPU. De 61 predicciones, 19 fueron incorrectas total o parcialmente y 2 no se pudieron medir; se quedan en la lección. - Los fotogramas se renderizan en un bucle cerrado sin
requestAnimationFrame, con vsync desactivado, y la página hace avanzar ella mismarenderer._nodes.nodeFrame: sin eso, los shadow maps y el bloom no se actualizan.onSubmittedWorkDone()nunca resolvió por debajo de unos 3.5 ms, así que los tiempos de GPU vienen de las consultas de marca de tiempo. - Hallazgos de r186:
InstancedMeshcon morph targets falla con una instancia (sinmorphTargetInfluences) y con varias cuando se definen;BatchedMeshhace una llamada por objeto en WebGPU; el compute de TSL funciona en WebGL 2;renderer.info.memory.texturesSizecuenta 0 para las texturas comprimidas. - El índice OPTIC-K de GA tiene 313 047 vectores de 124 dimensiones (OPTK v4), no 112. El laboratorio lo lee en solo lectura; la CI usa un sustituto sintético.
- El CCD de Rapier no detiene una púa cinemática: atraviesa la cuerda a 30 y 60 pasos por segundo en todos los casos.
- El build de R3F incluía
threejunto athree/webgpu: 565 kB gzip frente a 210 para la misma escena sin React. - Las texturas de madera de ComfyUI están pendientes: el experimento 4 del laboratorio ComfyUI GA aún no tenía salida.
- La CI (
threejs-ga-lab.yml) compara los contadores derenderer.infoen WebGL 2 en tres sistemas operativos, nunca los tiempos. Una captura de Playwright se bloqueó 300 s una vez en macOS: el lanzador ahora conserva el resultado cuando falla una captura.
2026-09-24 — Correcciones upstream
Sección titulada «2026-09-24 — Correcciones upstream»- La fila
PCFSoftShadowMaptodavía no se aplica a GA. La retirada y su aviso son reales en r186 (Renderer.jsyShadowNode.jsdel paquetethree@0.186.0), pero GA fija three 0.180.0 y @react-three/fiber 8.18.0. En 0.180,ShadowNodetodavía asociaPCFSoftShadowMapa su filtro suave: no hay aviso, y las sombras suaves funcionan. - Los dos emparejamientos de GA con
WebGPURenderer, enLunarLanderEngine.tsyMinimalThreeInstrument.tsx, empezarán a avisar cuando GA pase a r186 o posterior. Cambiarlos ahora haría perder las sombras suaves, así que #733 los deja para esa actualización y lo dice. Leído en las fuentes del paquete, sin ejecutar (por verificar).
Por verificar
Sección titulada «Por verificar»- La memoria de GPU de los KTX2 con una herramienta de GPU.
- El primer fotograma de R3F en un build de producción.
- Un alias de
threeathree/webgpu. - El mástil a tamaño real y el desfase de cabeza de 25 mm de IWER en un visor.
- La latencia de audio con un micrófono.
powerPreferenceen un portátil con dos GPU.- La demo VR con un visor real: la entrada en la sesión, los rayos de los mandos, la nota y el pulso háptico.
- Si las púas lanzadas sin CCD atraviesan los trastes de la demo de física.
- Las cinco escenas completas en un teléfono: fotogramas por segundo, y si el shadow map de 2048 × 2048 y el bloom del estudio aguantan.
- Si una escena modelada en centímetros necesita luces 10 000 veces más fuertes para verse igual que en metros (lección 2).
- Texturas KTX2: carga, formatos de GPU elegidos en cada sistema operativo, memoria.
- Si
ThreeHeadstock.tsxllama aonTuningPegClickuna vez por cada listener obsoleto después de que su efecto se vuelva a ejecutar (lección 5). - Si
ThreeFretboard.tsxse reconstruye en cada renderizado de sus padres en las páginas de GA (lección 8). - El tiempo de GPU, no solo el de CPU, con
timestamp-queryde WebGPU (lección 8). - Draco frente a meshopt en un modelo grande y en muchos pequeños, sobre una red real (lección 4, ejercicio 3).
- WebGPU en una máquina Linux o Windows con GPU, fuera de la del autor.
XRGPUBinding: qué navegadores y cascos lo ofrecen, yWebGPURendereren una sesión WebXR real (lección 11).- El backend WebGL 2 y
WebGLXRFallbacken un casco real, cuyo framebuffer de capa no esnull(lección 11). - Tasa de fotogramas, foveation y comodidad de la página WebXR en unas Quest (lección 11).
- Si existe un troika-three-text preparado para WebGPU para el
<Text>de drei (lección 9). - Con qué frecuencia renderizan en la práctica los padres de GA
ThreeFretboardy el explorador BSP, con el profiler de React (lecciones 9 y 13). samples: 8en el WebGL 2 de GPUs reales, segúnMAX_SAMPLES(lección 13).- Por qué Rapier detuvo una bola rápida en una pared fija fina sin CCD (lección 10).