<!-- SAGA-SOLID · part 2 -->
THREE.Mesh(new THREE.CircleGeometry(8, 32),
  new THREE.MeshStandardMaterial({color:0x0a0a10, roughness:0.95}));
ground.rotation.x = -Math.PI/2; ground.receiveShadow = true; scene.add(ground);
// Faint ring around the avatar
var ring = new THREE.Mesh(new THREE.RingGeometry(1.6, 1.65, 48),
  new THREE.MeshBasicMaterial({color:0xc8a860, transparent:true, opacity:0.25, side:THREE.DoubleSide}));
ring.rotation.x = -Math.PI/2; ring.position.y = 0.01; scene.add(ring);
var current = null, idx = 0, currentView = 'front', fadeT = 1;
function show(i, view){
  idx = (i + AVATARS.length) % AVATARS.length;
  if(view) currentView = view;
  if(current){ scene.remove(current); }
  var a = AVATARS[idx];
  var av = window.EPISTLES_AVATARS.builders[a.id]();
  if(currentView==='side') av.rotation.y = Math.PI/2;
  if(currentView==='back') av.rotation.y = Math.PI;
  av.traverse(function(o){ if(o.isMesh){ o.castShadow = true; } });
  scene.add(av); current = av;
  document.getElementById('name').textContent = a.name;
  document.getElementById('words').textContent = a.words ? '\u201c ' + a.words + ' \u201d' : '';
  document.getElementById('desc').textContent = a.desc;
  document.getElementById('count').textContent = ROMAN[idx] + ' \u2014 X';
  document.querySelectorAll('.abtn').forEach(function(b, bi){
    b.classList.toggle('active', bi===idx);
  });
  document.querySelectorAll('.vbtn').forEach(function(b){
    b.classList.toggle('active', b.dataset.v===currentView);
  });
  var isFlat = (a.id==='stargazer');
  var isLow = (a.id==='keeper');
  if(isFlat){ camera.position.set(0, 4.2, 4.5); camera.lookAt(0, 0.2, -0.2); }
  else if(isLow){ camera.position.set(0, 1.8, 4.2); camera.lookAt(0, 0.8, 0); }
  else { camera.position.set(0, 1.6, 5.2); camera.lookAt(0, 1.3, 0); }
  fadeT = 0;
}
var abar = document.getElementById('avatars');
AVATARS.forEach(function(a, i){
  var b = document.createElement('button');
  b.className = 'abtn'+(i===0?' active':'');
  b.textContent = ROMAN[i];
  b.title = a.name;
  b.onclick = function(){ show(i); };
  abar.appendChild(b);
});
document.querySelectorAll('.vbtn').forEach(function(b){
  b.onclick = function(){ show(idx, b.dataset.v); };
});
document.getElementById('prev').onclick = function(){ show(idx-1); };
document.getElementById('next').onclick = function(){ show(idx+1); };
var sx = 0;
document.addEventListener('touchstart', function(e){ sx = e.touches[0].clientX; }, {passive:true});
document.addEventListener('touchend', function(e){
  var dx = e.changedTouches[0].clientX - sx;
  if(Math.abs(dx) > 60) show(idx + (dx<0?1:-1));
}, {passive:true});
document.addEventListener('keydown', function(e){
  if(e.key==='ArrowRight') show(idx+1);
  if(e.key==='ArrowLeft') show(idx-1);
});
var spin = 0;
function animate(){
  requestAnimationFrame(animate);
  spin += 0.002;
  ring.rotation.z = spin;
  if(current && currentView==='front'){
    // Gentle idle rotation only in front view
  }
  renderer.render(scene, camera);
}
setTimeout(function(){ show(0); animate(); }, 600);
</script></body></html>


===== FILE: public/saga-solid/avatar-preview.html =====
<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Avatar Preview</title>
<style>body{margin:0;background:#1a1a20;}canvas{display:block;}</style>
</head><body>
<script src="/saga/three.min.js"></script>
<script src="/saga-solid/avatars.js?v=2"></script>
<script>
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a20);
var camera = new THREE.PerspectiveCamera(50, 390/844, 0.1, 100);
camera.position.set(0, 1.5, 5);
camera.lookAt(0, 1.2, 0);
var renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(390, 844);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Lights
scene.add(new THREE.AmbientLight(0xffffff, 0.6));
var key = new THREE.DirectionalLight(0xffffff, 0.8);
key.position.set(3, 5, 4); key.castShadow = true; scene.add(key);
var rim = new THREE.DirectionalLight(0x8888ff, 0.4);
rim.position.set(-3, 2, -2); scene.add(rim);
// Ground
var ground = new THREE.Mesh(new THREE.PlaneGeometry(20,20),
  new THREE.MeshStandardMaterial({color:0x2a2a30, roughness:0.9}));
ground.rotation.x = -Math.PI/2; ground.receiveShadow = true; scene.add(ground);
// Avatar from URL param
var m = /[?&]avatar=([a-z]+)/.exec(location.search||'');
var id = (m && m[1]) || 'sentinel';
setTimeout(function(){
  if (window.EPISTLES_AVATARS && window.EPISTLES_AVATARS.builders[id]) {
    var av = window.EPISTLES_AVATARS.builders[id]();
    // Center avatar
    av.position.set(0, 0, 0);
    scene.add(av);
    document.title = av.userData.avatarName;
  }
  (function animate(){
    requestAnimationFrame(animate);
    // Slow rotation for inspection
    scene.rotation.y += 0.003;
    renderer.render(scene, camera);
  })();
}, 500);
</script>
</body></html>


===== FILE: public/saga-solid/avatar-view.html =====
<!DOCTYPE html>
