← Commit history

Match Colby's viewer ground and sky exactly (per his current native /viewer/3d build): the sky is the 3d-viewer-design steel-blue (clearColor #2a3340, environmentIntensity 1.0, no skybox mesh) and the ground is his soft radial-fade circle (256px groundFadeTex, alpha 0.2 ALPHABLEND, PBR baseColor 0.15) instead of our opaque grey rectangle. Updates the characterization-page hero viewer and the README embed.

AravK ·874c0bf5fd ·3mo ago ·parent 4cd2855
2 files changed +78
IN-S42ATR-viewer.html+39
@@ -101,6 +101,44 @@   const scene = viewer.getScene();   scene.animationGroups.slice().forEach(g => g.dispose());   // we drive our own motion +  // Match Colby's CURRENT viewer EXACTLY (native /viewer/3d/, build ?v=20260717e). The shipped bundle+  // is older and differs two ways, both verified live against his native scene:+  //   SKY   — ships a flat grey (clearColor + skybox primaryColor 0.75, environmentIntensity 1.5) plus a+  //           BackgroundSkybox mesh. His current build has NO skybox mesh: just clearColor = SKILL_BG_BOTTOM+  //           (#2a3340) + environmentIntensity 1.0 + the studio env for PBR reflections.+  //   GROUND — ships an opaque square shadowGround (the "grey rectangle"). His is the same square GroundMesh+  //           + PBR groundMat (baseColor 0.15) but with a 256px radial-fade baseTexture + alpha 0.2+  //           (ALPHABLEND), so it reads as a soft CIRCLE. We rebuild that fade texture here.+  const bgBot = new B.Color3(0.165, 0.200, 0.251);             // SKILL_BG_BOTTOM = #2a3340+  const Color4 = scene.clearColor && scene.clearColor.constructor;   // Color4 isn't on the bundle's B — harvest it+  let _groundFade = null;+  const groundFadeTex = () => {                                // his radial fade: opaque centre -> transparent rim+    if (_groundFade) return _groundFade;+    const t = new B.DynamicTexture('groundFadeTex', 256, scene, true);+    const c = t.getContext();+    const g = c.createRadialGradient(128,128,6, 128,128,128);+    g.addColorStop(0.0, 'rgba(255,255,255,1)');+    g.addColorStop(0.55,'rgba(255,255,255,0.6)');+    g.addColorStop(1.0, 'rgba(255,255,255,0)');+    c.fillStyle = g; c.fillRect(0,0,256,256); t.update(); t.hasAlpha = true;+    _groundFade = t; return t;+  };+  const matchColby = () => {                                   // idempotent; also called after each re-frame+    if (Color4) scene.clearColor = new Color4(bgBot.r, bgBot.g, bgBot.b, 1);+    scene.environmentIntensity = 1.0;+    scene.meshes.filter(m => /^Background/.test(m.name)).forEach(m => m.setEnabled(false));   // no skybox, like his native+    const gnd = scene.getMeshByName('shadowGround');+    if (gnd && gnd.material) {+      const m = gnd.material;+      if (!(m.baseTexture && m.baseTexture.name === 'groundFadeTex')) {+        if ('baseTexture' in m) m.baseTexture = groundFadeTex();+        m.alpha = 0.2; m.transparencyMode = 2; m.backFaceCulling = false;   // his soft ALPHABLEND circle+      }+      gnd.receiveShadows = true;+    }+  };+  matchColby();+   const led     = scene.getNodeByName('IN-S42ATR');   if (led) led.rotationQuaternion = null;   // glTF sets a quaternion that would ignore rotation.z — use Euler   const ledLit  = scene.getNodeByName('LED_lit');@@ -330,6 +368,7 @@     c.alpha = 1.05; c.beta = 1.0;     if (mode === 'pnp') { c.target.copyFromFloats(0.003, 0, 0.0006); c.radius = 0.026; }     else { c.target.copyFromFloats(0, 0, -0.0002); c.radius = 0.0065; }+    matchColby();   // frameModel may rebuild the ground/skybox — re-apply his ground fade + no-skybox   }    // 6) Mode switching — ghosts are a content root only in P&P (so Static frames just the part).
README.html+39
@@ -135,6 +135,44 @@   const scene = viewer.getScene();   scene.animationGroups.slice().forEach(g => g.dispose());   // we drive our own motion +  // Match Colby's CURRENT viewer EXACTLY (native /viewer/3d/, build ?v=20260717e). The shipped bundle+  // is older and differs two ways, both verified live against his native scene:+  //   SKY   — ships a flat grey (clearColor + skybox primaryColor 0.75, environmentIntensity 1.5) plus a+  //           BackgroundSkybox mesh. His current build has NO skybox mesh: just clearColor = SKILL_BG_BOTTOM+  //           (#2a3340) + environmentIntensity 1.0 + the studio env for PBR reflections.+  //   GROUND — ships an opaque square shadowGround (the "grey rectangle"). His is the same square GroundMesh+  //           + PBR groundMat (baseColor 0.15) but with a 256px radial-fade baseTexture + alpha 0.2+  //           (ALPHABLEND), so it reads as a soft CIRCLE. We rebuild that fade texture here.+  const bgBot = new B.Color3(0.165, 0.200, 0.251);             // SKILL_BG_BOTTOM = #2a3340+  const Color4 = scene.clearColor && scene.clearColor.constructor;   // Color4 isn't on the bundle's B — harvest it+  let _groundFade = null;+  const groundFadeTex = () => {                                // his radial fade: opaque centre -> transparent rim+    if (_groundFade) return _groundFade;+    const t = new B.DynamicTexture('groundFadeTex', 256, scene, true);+    const c = t.getContext();+    const g = c.createRadialGradient(128,128,6, 128,128,128);+    g.addColorStop(0.0, 'rgba(255,255,255,1)');+    g.addColorStop(0.55,'rgba(255,255,255,0.6)');+    g.addColorStop(1.0, 'rgba(255,255,255,0)');+    c.fillStyle = g; c.fillRect(0,0,256,256); t.update(); t.hasAlpha = true;+    _groundFade = t; return t;+  };+  const matchColby = () => {                                   // idempotent; also called after each re-frame+    if (Color4) scene.clearColor = new Color4(bgBot.r, bgBot.g, bgBot.b, 1);+    scene.environmentIntensity = 1.0;+    scene.meshes.filter(m => /^Background/.test(m.name)).forEach(m => m.setEnabled(false));   // no skybox, like his native+    const gnd = scene.getMeshByName('shadowGround');+    if (gnd && gnd.material) {+      const m = gnd.material;+      if (!(m.baseTexture && m.baseTexture.name === 'groundFadeTex')) {+        if ('baseTexture' in m) m.baseTexture = groundFadeTex();+        m.alpha = 0.2; m.transparencyMode = 2; m.backFaceCulling = false;   // his soft ALPHABLEND circle+      }+      gnd.receiveShadows = true;+    }+  };+  matchColby();+   const led     = scene.getNodeByName('IN-S42ATR');   if (led) led.rotationQuaternion = null;   // glTF sets a quaternion that would ignore rotation.z — use Euler   const ledLit  = scene.getNodeByName('LED_lit');@@ -364,6 +402,7 @@     c.alpha = 1.05; c.beta = 1.0;     if (mode === 'pnp') { c.target.copyFromFloats(0.003, 0, 0.0006); c.radius = 0.026; }     else { c.target.copyFromFloats(0, 0, -0.0002); c.radius = 0.0065; }+    matchColby();   // frameModel may rebuild the ground/skybox — re-apply his ground fade + no-skybox   }    // 6) Mode switching — ghosts are a content root only in P&P (so Static frames just the part).