{"id":516,"date":"2026-07-02T20:49:45","date_gmt":"2026-07-02T20:49:45","guid":{"rendered":"https:\/\/itutu.com\/?page_id=516"},"modified":"2026-07-02T21:07:36","modified_gmt":"2026-07-02T21:07:36","slug":"nicole-mitchell-jazz-fest-idea","status":"publish","type":"page","link":"https:\/\/itutu.com\/index.php\/nicole-mitchell-jazz-fest-idea\/","title":{"rendered":"Nicole Mitchell Jazz Fest idea"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"516\" class=\"elementor elementor-516\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-6687e63 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"6687e63\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-91f534c\" data-id=\"91f534c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-7481b12 elementor-widget elementor-widget-html\" data-id=\"7481b12\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n<title>Nikki Mitchell Jazz Festival \u2014 3D Site Model<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n<style>\n  :root{\n    --ink:#efe7d6; --ink-dim:#b9b2a1; --panel:#171b23e6; --panel-line:#3a3f4a;\n    --brass:#c98a3d; --brass-soft:#e0ab6b;\n    --red:#a8433a; --navy:#3a4b6c; --cream:#eee6d4; --olive:#6b7f3f; --brown:#8a5a2b;\n  }\n  *{box-sizing:border-box;}\n  html,body{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background:#0f1420;\n    font-family:'Inter',sans-serif;}\n  #canvas-wrap{position:fixed;inset:0;}\n  canvas{display:block;width:100%;height:100%;touch-action:none;cursor:grab;}\n  canvas.dragging{cursor:grabbing;}\n\n  .hud{position:fixed;inset:0;pointer-events:none;z-index:10;}\n  .hud > *{pointer-events:auto;}\n\n  \/* ---- title ---- *\/\n  .title-block{position:absolute;top:16px;left:16px;max-width:min(78vw,420px);}\n  .title-block h1{\n    font-family:'Fraunces',serif;font-weight:600;font-optical-sizing:auto;\n    font-size:clamp(16px,3.6vw,22px);color:var(--ink);margin:0 0 3px 0;letter-spacing:.01em;\n    text-shadow:0 2px 10px rgba(0,0,0,.6);\n  }\n  .title-block p{margin:0;font-size:11.5px;color:var(--ink-dim);letter-spacing:.02em;\n    text-shadow:0 1px 6px rgba(0,0,0,.6);}\n  .title-block .rule{width:34px;height:2px;background:var(--brass);margin:8px 0 8px 0;\n    box-shadow:0 0 8px var(--brass);}\n\n  \/* ---- compass ---- *\/\n  #compass{position:absolute;top:16px;right:16px;width:46px;height:46px;border-radius:50%;\n    background:var(--panel);border:1px solid var(--panel-line);backdrop-filter:blur(6px);\n    display:flex;align-items:center;justify-content:center;}\n  #compass svg{width:26px;height:26px;transition:transform .05s linear;}\n\n  \/* ---- bottom-left: camera presets (primary, always visible) ---- *\/\n  #presets{position:absolute;left:16px;bottom:16px;display:flex;flex-direction:column;gap:8px;\n    max-width:70vw;}\n  #presets .label{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-dim);\n    margin-bottom:1px;}\n  #presets .row{display:flex;flex-wrap:wrap;gap:6px;}\n  .pill{\n    font-family:'Inter',sans-serif;font-size:12.5px;font-weight:600;color:var(--ink);\n    background:var(--panel);border:1px solid var(--panel-line);border-radius:20px;\n    padding:8px 14px;backdrop-filter:blur(6px);cursor:pointer;white-space:nowrap;\n    transition:background .15s,border-color .15s,transform .1s;\n  }\n  .pill:hover{border-color:var(--brass);}\n  .pill:active{transform:scale(.96);}\n  .pill.active{background:var(--brass);border-color:var(--brass);color:#1a1206;}\n\n  \/* ---- bottom-right: legend \/ secondary controls ---- *\/\n  #panel-toggle{position:absolute;right:16px;bottom:16px;z-index:11;}\n  #side-panel{\n    position:absolute;right:16px;bottom:16px;width:250px;max-height:min(64vh,520px);\n    background:var(--panel);border:1px solid var(--panel-line);border-radius:14px;\n    backdrop-filter:blur(8px);padding:14px 14px 12px 14px;overflow-y:auto;\n    transform-origin:bottom right;transition:transform .18s ease,opacity .18s ease;\n  }\n  #side-panel.hidden{transform:scale(.92);opacity:0;pointer-events:none;}\n  #side-panel h2{font-family:'Fraunces',serif;font-size:13px;font-weight:600;color:var(--brass-soft);\n    margin:0 0 8px 0;letter-spacing:.02em;}\n  #side-panel h2.second{margin-top:14px;}\n  .legend-item{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--ink);\n    padding:3px 0;line-height:1.25;}\n  .swatch{width:16px;height:16px;border-radius:5px;flex:none;display:flex;align-items:center;\n    justify-content:center;font-size:9px;font-weight:700;color:#fff;font-family:'Inter';}\n  .toggle-row{display:flex;align-items:center;justify-content:space-between;font-size:12px;\n    color:var(--ink);padding:6px 0;border-top:1px solid var(--panel-line);}\n  .toggle-row:first-of-type{border-top:none;}\n  .switch{position:relative;width:36px;height:20px;background:#3a3f4a;border-radius:12px;\n    cursor:pointer;flex:none;transition:background .15s;}\n  .switch.on{background:var(--brass);}\n  .switch::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;\n    border-radius:50%;background:#efe7d6;transition:left .15s;}\n  .switch.on::after{left:18px;}\n  .tod-row{display:flex;gap:6px;margin-top:4px;}\n  .tod-btn{flex:1;font-size:11px;font-weight:600;color:var(--ink);background:#20242e;\n    border:1px solid var(--panel-line);border-radius:8px;padding:6px 4px;cursor:pointer;text-align:center;}\n  .tod-btn.active{background:var(--brass);color:#1a1206;border-color:var(--brass);}\n  #close-panel{background:none;border:none;color:var(--ink-dim);font-size:16px;cursor:pointer;\n    position:absolute;top:10px;right:10px;line-height:1;}\n\n  .fab{\n    width:46px;height:46px;border-radius:50%;background:var(--panel);\n    border:1px solid var(--panel-line);backdrop-filter:blur(6px);display:flex;\n    align-items:center;justify-content:center;cursor:pointer;color:var(--brass-soft);font-size:18px;\n  }\n\n  .hint{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);\n    font-size:11px;color:var(--ink-dim);background:var(--panel);border:1px solid var(--panel-line);\n    border-radius:20px;padding:6px 14px;backdrop-filter:blur(6px);white-space:nowrap;\n    opacity:1;transition:opacity .6s ease;}\n  .hint.fade{opacity:0;}\n\n  @media (max-width:560px){\n    #side-panel{width:min(80vw,260px);}\n    .title-block{max-width:68vw;}\n    #presets{max-width:60vw;}\n  }\n<\/style>\n<\/head>\n<body>\n<div id=\"canvas-wrap\"><\/div>\n\n<div class=\"hud\">\n  <div class=\"title-block\">\n    <h1>Nikki Mitchell Jazz Festival<\/h1>\n    <div class=\"rule\"><\/div>\n    <p>150 Heartland Ln, Henderson NC \u2014 3D site model, schematic scale<br>drag to orbit \u00b7 scroll \/ pinch to zoom<\/p>\n  <\/div>\n\n  <div id=\"compass\">\n    <svg viewBox=\"0 0 100 100\">\n      <circle cx=\"50\" cy=\"50\" r=\"46\" fill=\"none\" stroke=\"#5a5748\" stroke-width=\"1.5\"\/>\n      <polygon points=\"50,10 58,50 50,42 42,50\" fill=\"#c98a3d\"\/>\n      <polygon points=\"50,90 58,50 50,58 42,50\" fill=\"#5a5748\"\/>\n      <text x=\"50\" y=\"26\" text-anchor=\"middle\" font-size=\"13\" fill=\"#efe7d6\" font-family=\"Inter\" font-weight=\"700\">N<\/text>\n    <\/svg>\n  <\/div>\n\n  <div id=\"presets\">\n    <div class=\"label\">Camera<\/div>\n    <div class=\"row\">\n      <div class=\"pill active\" data-preset=\"aerial\">Aerial<\/div>\n      <div class=\"pill\" data-preset=\"stage\">Stage-eye<\/div>\n      <div class=\"pill\" data-preset=\"crowd\">Crowd-eye<\/div>\n      <div class=\"pill\" data-preset=\"gate\">Arrival \/ Gate<\/div>\n    <\/div>\n  <\/div>\n\n  <div id=\"panel-toggle\" class=\"fab\" title=\"Legend & settings\">\u2630<\/div>\n\n  <div id=\"side-panel\" class=\"hidden\">\n    <button id=\"close-panel\">\u2715<\/button>\n    <h2>Site Key<\/h2>\n    <div id=\"legend-list\"><\/div>\n    <h2 class=\"second\">Time of Day<\/h2>\n    <div class=\"tod-row\" id=\"tod-row\">\n      <div class=\"tod-btn\" data-tod=\"noon\">Midday<\/div>\n      <div class=\"tod-btn active\" data-tod=\"golden\">Golden Hr<\/div>\n      <div class=\"tod-btn\" data-tod=\"dusk\">Dusk<\/div>\n    <\/div>\n    <h2 class=\"second\">Display<\/h2>\n    <div class=\"toggle-row\"><span>Labels<\/span><div class=\"switch on\" id=\"toggle-labels\"><\/div><\/div>\n    <div class=\"toggle-row\"><span>Crowd markers<\/span><div class=\"switch on\" id=\"toggle-crowd\"><\/div><\/div>\n    <div class=\"toggle-row\"><span>Sound throw<\/span><div class=\"switch on\" id=\"toggle-sound\"><\/div><\/div>\n  <\/div>\n\n  <div class=\"hint\" id=\"hint\">drag to look around \u00b7 scroll to zoom \u00b7 tap \u2630 for the key<\/div>\n<\/div>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"><\/script>\n<script>\n(function(){\n\n\/* ============================================================\n   LEGEND \/ KEY DATA  \u2014 matches the site-map key in the Word doc\n   ============================================================ *\/\nvar LEGEND = [\n  {k:'A', name:'Main stage',            color:0x2c2a28},\n  {k:'B', name:'FOH mix position',      color:0xc98a3d},\n  {k:'C', name:'Audience lawn',         color:0x8a9a5b},\n  {k:'D', name:'Backstage \/ trailer',   color:0x555a63},\n  {k:'E', name:'Hospitality tent',      color:0xeee6d4},\n  {k:'F', name:'Vendor & food row',     color:0x8a5a2b},\n  {k:'G', name:'Restroom clusters',     color:0xe8e2d0},\n  {k:'H', name:'Entry gate',            color:0xa8433a},\n  {k:'J', name:'First aid',             color:0xa8433a},\n  {k:'K', name:'Artist \/ prod. parking',color:0x3a4b6c},\n  {k:'L', name:'General parking',       color:0x3a4b6c},\n  {k:'M', name:'Trash \/ recycling',     color:0x6b7f3f}\n];\nvar legendList = document.getElementById('legend-list');\nLEGEND.forEach(function(item){\n  var row = document.createElement('div');\n  row.className = 'legend-item';\n  var hex = '#' + item.color.toString(16).padStart(6,'0');\n  row.innerHTML = '<div class=\"swatch\" style=\"background:'+hex+'\">'+item.k+'<\/div><div>'+item.name+'<\/div>';\n  legendList.appendChild(row);\n});\n\n\/* ============================================================\n   SCENE SETUP\n   ============================================================ *\/\nvar wrap = document.getElementById('canvas-wrap');\nvar scene = new THREE.Scene();\nvar camera = new THREE.PerspectiveCamera(48, wrap.clientWidth\/wrap.clientHeight, 0.1, 400);\nvar renderer = new THREE.WebGLRenderer({antialias:true});\nrenderer.setPixelRatio(Math.min(window.devicePixelRatio,2));\nrenderer.setSize(wrap.clientWidth, wrap.clientHeight);\nrenderer.shadowMap.enabled = true;\nrenderer.shadowMap.type = THREE.PCFSoftShadowMap;\nwrap.appendChild(renderer.domElement);\nvar canvasEl = renderer.domElement;\n\nwindow.addEventListener('resize', function(){\n  camera.aspect = wrap.clientWidth\/wrap.clientHeight;\n  camera.updateProjectionMatrix();\n  renderer.setSize(wrap.clientWidth, wrap.clientHeight);\n});\n\n\/* deterministic PRNG so the scene is stable across reloads *\/\nfunction mulberry32(a){\n  return function(){\n    a |= 0; a = a + 0x6D2B79F5 | 0;\n    var t = Math.imul(a ^ a >>> 15, 1 | a);\n    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;\n    return ((t ^ t >>> 14) >>> 0) \/ 4294967296;\n  };\n}\nvar rng = mulberry32(1337);\n\n\/* ============================================================\n   LIGHTING RIGS  (time-of-day presets)\n   ============================================================ *\/\nvar hemi = new THREE.HemisphereLight(0xffffff, 0x25201a, 0.55);\nscene.add(hemi);\nvar sun = new THREE.DirectionalLight(0xffffff, 1);\nsun.castShadow = true;\nsun.shadow.mapSize.set(1536,1536);\nsun.shadow.camera.left = -34; sun.shadow.camera.right = 34;\nsun.shadow.camera.top = 34; sun.shadow.camera.bottom = -34;\nsun.shadow.camera.near = 1; sun.shadow.camera.far = 90;\nsun.shadow.bias = -0.0015;\nscene.add(sun);\nscene.add(sun.target);\n\nvar TOD = {\n  noon:   {sunPos:[10,32,14], sunColor:0xfff2d6, sunI:1.15, hemiSky:0x8fb4d9, hemiGround:0x4a4530,\n           hemiI:0.65, top:'#7fa8c9', bottom:'#d9c9a0', fog:'#cdd6c0', fogNear:34, fogFar:95},\n  golden: {sunPos:[-26,10,6], sunColor:0xffa552, sunI:1.05, hemiSky:0x35496b, hemiGround:0x2a1f18,\n           hemiI:0.5, top:'#33456b', bottom:'#e8935a', fog:'#caa06a', fogNear:26, fogFar:80},\n  dusk:   {sunPos:[-14,4,10], sunColor:0x8aa0ff, sunI:0.35, hemiSky:0x0f1420, hemiGround:0x1a1522,\n           hemiI:0.4, top:'#0b0f18', bottom:'#3c2f42', fog:'#221c2a', fogNear:18, fogFar:62}\n};\n\nfunction skyTexture(topHex, bottomHex){\n  var c = document.createElement('canvas'); c.width = 8; c.height = 256;\n  var ctx = c.getContext('2d');\n  var g = ctx.createLinearGradient(0,0,0,256);\n  g.addColorStop(0, topHex); g.addColorStop(1, bottomHex);\n  ctx.fillStyle = g; ctx.fillRect(0,0,8,256);\n  var tex = new THREE.CanvasTexture(c);\n  tex.magFilter = THREE.LinearFilter;\n  return tex;\n}\n\nvar stageGlowLights = [];\nfunction applyTOD(name){\n  var s = TOD[name];\n  sun.position.set(s.sunPos[0], s.sunPos[1], s.sunPos[2]);\n  sun.target.position.set(0,0,0);\n  sun.color.setHex(s.sunColor); sun.intensity = s.sunI;\n  hemi.color.setHex(s.hemiSky); hemi.groundColor.setHex(s.hemiGround); hemi.intensity = s.hemiI;\n  scene.background = skyTexture(s.top, s.bottom);\n  scene.fog = new THREE.Fog(new THREE.Color(s.fog), s.fogNear, s.fogFar);\n  var glowI = name === 'dusk' ? 1.4 : (name === 'golden' ? 0.5 : 0.05);\n  stageGlowLights.forEach(function(l){ l.intensity = glowI; });\n}\n\n\/* ============================================================\n   GROUND\n   ============================================================ *\/\nvar groundGeo = new THREE.PlaneGeometry(140,140,1,1);\nvar groundMat = new THREE.MeshLambertMaterial({color:0x54622f});\nvar ground = new THREE.Mesh(groundGeo, groundMat);\nground.rotation.x = -Math.PI\/2;\nground.receiveShadow = true;\nscene.add(ground);\n\n\/* festival grounds boundary (matches the aerial-traced polygon, rescaled) *\/\nvar fieldPts = [\n  [-6,-8],[-2,-9.2],[3,-8.6],[7,-6.6],[9.2,-2],[8.4,3.2],\n  [5,6.6],[0,7.6],[-4,6],[-6.2,2],[-6.6,-3]\n];\nvar shape = new THREE.Shape(fieldPts.map(function(p){return new THREE.Vector2(p[0],p[1]);}));\nvar fieldGeo = new THREE.ShapeGeometry(shape);\nvar fieldMat = new THREE.MeshBasicMaterial({color:0xc98a3d, transparent:true, opacity:0.16, depthWrite:false});\nvar fieldFill = new THREE.Mesh(fieldGeo, fieldMat);\nfieldFill.rotation.x = -Math.PI\/2;\nfieldFill.position.y = 0.02;\nscene.add(fieldFill);\n\nfunction dashedLoop(pts, y, colorHex, dashSize, gapSize){\n  var vpts = pts.map(function(p){return new THREE.Vector3(p[0], y, p[1]);});\n  vpts.push(vpts[0].clone());\n  var geo = new THREE.BufferGeometry().setFromPoints(vpts);\n  var mat = new THREE.LineDashedMaterial({color:colorHex, dashSize:dashSize, gapSize:gapSize, linewidth:1});\n  var line = new THREE.Line(geo, mat);\n  line.computeLineDistances();\n  scene.add(line);\n  return line;\n}\ndashedLoop(fieldPts, 0.03, 0xc98a3d, 0.6, 0.35);\n\n\/* audience \"bowl\" outline, matching the hand-drawn loop on the aerial *\/\nvar bowlPts = [];\nvar bowlN = 28;\nfor(var i=0;i<bowlN;i++){\n  var a = (i\/bowlN)*Math.PI*2;\n  var rx = 5.6 + Math.sin(a*3)*0.4;\n  var rz = 5.0 + Math.cos(a*2)*0.35;\n  bowlPts.push([Math.cos(a)*rx + 1.0, Math.sin(a)*rz - 0.3]);\n}\ndashedLoop(bowlPts, 0.035, 0x2c2a28, 0.4, 0.25);\n\n\/* ============================================================\n   ROADS\n   ============================================================ *\/\nfunction roadSegment(x1,z1,x2,z2,width,color){\n  var dx = x2-x1, dz = z2-z1;\n  var len = Math.sqrt(dx*dx+dz*dz);\n  var geo = new THREE.PlaneGeometry(width, len);\n  var mat = new THREE.MeshLambertMaterial({color:color});\n  var m = new THREE.Mesh(geo, mat);\n  m.rotation.x = -Math.PI\/2;\n  m.rotation.z = -Math.atan2(dx,dz);\n  m.position.set((x1+x2)\/2, 0.01, (z1+z2)\/2);\n  m.receiveShadow = true;\n  scene.add(m);\n  return m;\n}\nroadSegment(-13,-22, -4.5,20, 3.2, 0xcabfa4);\nroadSegment(-8.6,-13.5, -5.3,-9.4, 2.2, 0xc3b79a); \/\/ driveway to residence\n\n\/* dashed centerline for Heartland Ln *\/\n(function(){\n  var steps = 22;\n  for(var i=0;i<steps;i++){\n    var t0 = i\/steps, t1 = (i+0.5)\/steps;\n    var x0 = -13 + (-4.5 - -13)*t0, z0 = -22 + (20 - -22)*t0;\n    var x1 = -13 + (-4.5 - -13)*t1, z1 = -22 + (20 - -22)*t1;\n    var geo = new THREE.PlaneGeometry(0.12, 0.9);\n    var m = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({color:0xf1e9d8}));\n    m.rotation.x = -Math.PI\/2;\n    m.rotation.z = -Math.atan2(x1-x0, z1-z0);\n    m.position.set((x0+x1)\/2, 0.02, (z0+z1)\/2);\n    scene.add(m);\n  }\n})();\n\n\/* ============================================================\n   HELPERS: trees, labels, tents, people, cars\n   ============================================================ *\/\nvar canopyColors = [0x2e3a22, 0x243019, 0x35452a, 0x2a3620];\nfunction makeTree(x,z,scale){\n  var g = new THREE.Group();\n  var trunk = new THREE.Mesh(\n    new THREE.CylinderGeometry(0.06*scale,0.09*scale,0.9*scale,6),\n    new THREE.MeshLambertMaterial({color:0x4a3a2a})\n  );\n  trunk.position.y = 0.45*scale;\n  trunk.castShadow = true;\n  g.add(trunk);\n  var cCount = 2 + Math.floor(rng()*2);\n  for(var i=0;i<cCount;i++){\n    var s = (0.55 + rng()*0.35)*scale;\n    var cone = new THREE.Mesh(\n      new THREE.ConeGeometry(0.55*s, 1.3*s, 7),\n      new THREE.MeshLambertMaterial({color:canopyColors[Math.floor(rng()*canopyColors.length)]})\n    );\n    cone.position.set((rng()-0.5)*0.3*scale, 0.9*scale + i*0.55*s, (rng()-0.5)*0.3*scale);\n    cone.castShadow = true;\n    g.add(cone);\n  }\n  g.position.set(x,0,z);\n  scene.add(g);\n  return g;\n}\n\n\/* scatter trees along the perimeter bands (north \/ south \/ east-by-pond), avoiding the field *\/\nfunction pointInPoly(x,z,pts){\n  var inside = false;\n  for(var i=0,j=pts.length-1;i<pts.length;j=i++){\n    var xi=pts[i][0], zi=pts[i][1], xj=pts[j][0], zj=pts[j][1];\n    var intersect = ((zi>z)!=(zj>z)) && (x < (xj-xi)*(z-zi)\/(zj-zi+0.00001)+xi);\n    if(intersect) inside = !inside;\n  }\n  return inside;\n}\nvar treeCount = 100, placed = 0, attempts = 0;\nwhile(placed < treeCount && attempts < 4000){\n  attempts++;\n  var tx = (rng()-0.5)*46;\n  var tz = (rng()-0.5)*46;\n  var d = Math.sqrt(tx*tx+tz*tz);\n  if(d < 11.5) continue; \/\/ keep clear of the field\n  if(d > 21) continue;   \/\/ keep within a reasonable visible band\n  makeTree(tx,tz, 0.85 + rng()*0.6);\n  placed++;\n}\n\n\/* canvas label sprite *\/\nfunction makeLabel(text, hexColor){\n  var c = document.createElement('canvas'); c.width = 96; c.height = 96;\n  var ctx = c.getContext('2d');\n  ctx.beginPath(); ctx.arc(48,48,42,0,Math.PI*2);\n  ctx.fillStyle = '#' + hexColor.toString(16).padStart(6,'0');\n  ctx.fill();\n  ctx.lineWidth = 5; ctx.strokeStyle = '#f1e9d8'; ctx.stroke();\n  ctx.fillStyle = '#ffffff';\n  ctx.font = '700 46px Inter, sans-serif';\n  ctx.textAlign = 'center'; ctx.textBaseline = 'middle';\n  ctx.fillText(text, 48, 52);\n  var tex = new THREE.CanvasTexture(c);\n  var mat = new THREE.SpriteMaterial({map:tex, depthTest:false});\n  var sprite = new THREE.Sprite(mat);\n  sprite.scale.set(0.9,0.9,0.9);\n  sprite.renderOrder = 999;\n  return sprite;\n}\nvar labelSprites = [];\nfunction addLabel(text,color,x,y,z){\n  var s = makeLabel(text,color);\n  s.position.set(x,y,z);\n  scene.add(s);\n  labelSprites.push(s);\n  return s;\n}\n\nfunction tentMesh(w,d,h,roofColor,wallColor){\n  var g = new THREE.Group();\n  var base = new THREE.Mesh(new THREE.BoxGeometry(w,h*0.55,d),\n    new THREE.MeshLambertMaterial({color:wallColor}));\n  base.position.y = h*0.275;\n  base.castShadow = true; base.receiveShadow = true;\n  g.add(base);\n  var roof = new THREE.Mesh(new THREE.ConeGeometry(Math.max(w,d)*0.72, h*0.6, 4),\n    new THREE.MeshLambertMaterial({color:roofColor}));\n  roof.rotation.y = Math.PI\/4;\n  roof.position.y = h*0.55 + h*0.3;\n  roof.castShadow = true;\n  g.add(roof);\n  return g;\n}\n\nfunction personMarker(hex){\n  var g = new THREE.Group();\n  var body = new THREE.Mesh(new THREE.CylinderGeometry(0.09,0.11,0.42,6),\n    new THREE.MeshLambertMaterial({color:hex}));\n  body.position.y = 0.21;\n  var head = new THREE.Mesh(new THREE.SphereGeometry(0.09,6,6),\n    new THREE.MeshLambertMaterial({color:0xd8b48a}));\n  head.position.y = 0.47;\n  g.add(body); g.add(head);\n  g.castShadow = true;\n  return g;\n}\n\nfunction carBlock(hex){\n  var g = new THREE.Group();\n  var body = new THREE.Mesh(new THREE.BoxGeometry(0.85,0.28,1.7),\n    new THREE.MeshLambertMaterial({color:hex}));\n  body.position.y = 0.2;\n  var cabin = new THREE.Mesh(new THREE.BoxGeometry(0.7,0.24,0.9),\n    new THREE.MeshLambertMaterial({color:0x1c1e24}));\n  cabin.position.set(0,0.42,-0.1);\n  g.add(body); g.add(cabin);\n  g.castShadow = true;\n  return g;\n}\n\n\/* ============================================================\n   RESIDENCE  (near driveway, per aerial)\n   ============================================================ *\/\n(function(){\n  var g = new THREE.Group();\n  var walls = new THREE.Mesh(new THREE.BoxGeometry(3.6,1.9,2.6),\n    new THREE.MeshLambertMaterial({color:0x5a564c}));\n  walls.position.y = 0.95; walls.castShadow = true; walls.receiveShadow = true;\n  var roof = new THREE.Mesh(new THREE.ConeGeometry(2.7,1.1,4),\n    new THREE.MeshLambertMaterial({color:0x2c2a28}));\n  roof.rotation.y = Math.PI\/4; roof.position.y = 2.45; roof.castShadow = true;\n  g.add(walls); g.add(roof);\n  g.position.set(-4.3,0,-12.4);\n  scene.add(g);\n  addLabel('HQ',0x555a63,-4.3,3.1,-12.4);\n})();\n\n\/* ============================================================\n   STAGE (A) \u2014 faces west toward the audience lawn\n   ============================================================ *\/\nvar stageGroup = new THREE.Group();\n(function(){\n  var deck = new THREE.Mesh(new THREE.BoxGeometry(4.2,0.5,3.4),\n    new THREE.MeshLambertMaterial({color:0x2c2a28}));\n  deck.position.y = 0.25; deck.castShadow = true; deck.receiveShadow = true;\n  stageGroup.add(deck);\n\n  var backWall = new THREE.Mesh(new THREE.BoxGeometry(4.2,2.6,0.15),\n    new THREE.MeshLambertMaterial({color:0x1f1d1c}));\n  backWall.position.set(0,1.8,1.55);\n  backWall.castShadow = true;\n  stageGroup.add(backWall);\n\n  \/* angled canopy roof *\/\n  var roof = new THREE.Mesh(new THREE.BoxGeometry(4.6,0.14,4.1),\n    new THREE.MeshLambertMaterial({color:0x3a3835}));\n  roof.position.set(0,3.15,0.1);\n  roof.rotation.x = 0.18;\n  roof.castShadow = true;\n  stageGroup.add(roof);\n\n  \/* support posts *\/\n  [[-2.05,-1.55],[2.05,-1.55],[-2.05,1.55],[2.05,1.55]].forEach(function(p){\n    var post = new THREE.Mesh(new THREE.CylinderGeometry(0.08,0.08,3,6),\n      new THREE.MeshLambertMaterial({color:0x2c2a28}));\n    post.position.set(p[0],1.5,p[1]);\n    post.castShadow = true;\n    stageGroup.add(post);\n  });\n\n  \/* PA stacks either side *\/\n  [-2.35,2.35].forEach(function(px){\n    var pa = new THREE.Mesh(new THREE.BoxGeometry(0.5,1.6,0.5),\n      new THREE.MeshLambertMaterial({color:0x141414}));\n    pa.position.set(px,0.8,-1.2);\n    pa.castShadow = true;\n    stageGroup.add(pa);\n  });\n\n  \/* stage lighting glow (activates at dusk) *\/\n  [-1.6,0,1.6].forEach(function(lx){\n    var pl = new THREE.PointLight(0xffb066, 0.05, 6);\n    pl.position.set(lx,2.9,-0.6);\n    stageGroup.add(pl);\n    stageGlowLights.push(pl);\n  });\n\n  stageGroup.position.set(7.5,0,-1);\n  stageGroup.rotation.y = Math.PI\/2; \/* deck & PA face west toward the audience lawn; back wall faces the trees *\/\n  scene.add(stageGroup);\n  addLabel('A',0x2c2a28,7.5,4.0,-1);\n})();\n\n\/* ============================================================\n   FOH (B)\n   ============================================================ *\/\n(function(){\n  var g = new THREE.Group();\n  var tower = new THREE.Mesh(new THREE.BoxGeometry(1.1,1.0,1.1),\n    new THREE.MeshLambertMaterial({color:0x3a3835}));\n  tower.position.y = 0.5; tower.castShadow = true;\n  var deck = new THREE.Mesh(new THREE.BoxGeometry(1.3,0.1,1.3),\n    new THREE.MeshLambertMaterial({color:0x1f1d1c}));\n  deck.position.y = 1.05;\n  g.add(tower); g.add(deck);\n  g.position.set(2,0,-1.3);\n  scene.add(g);\n  addLabel('B',0xc98a3d,2,1.6,-1.3);\n})();\n\n\/* ============================================================\n   AUDIENCE LAWN + CROWD MARKERS (C)\n   ============================================================ *\/\nvar crowdGroup = new THREE.Group();\n(function(){\n  var pClothes = [0x6b5b4a,0x4a5a6b,0x5a4a5b,0x6b6a4a,0x3d4a3a,0x555049];\n  var n = 55, tries=0, made=0;\n  while(made<n && tries<2000){\n    tries++;\n    var a = rng()*Math.PI*2;\n    var rx = rng()*5.0, rz = rng()*4.4;\n    var x = Math.cos(a)*rx + 1.0;\n    var z = Math.sin(a)*rz - 0.3;\n    if(Math.sqrt((x-7.5)*(x-7.5)+(z+1)*(z+1)) < 3.2) continue; \/* keep off the stage *\/\n    var pm = personMarker(pClothes[Math.floor(rng()*pClothes.length)]);\n    pm.position.set(x,0,z);\n    pm.rotation.y = rng()*Math.PI*2;\n    crowdGroup.add(pm);\n    made++;\n  }\n  scene.add(crowdGroup);\n  addLabel('C',0x8a9a5b,1.0,0.9,4.6);\n})();\n\n\/* ============================================================\n   SOUND-THROW VISUALIZATION\n   ============================================================ *\/\nvar soundGroup = new THREE.Group();\n(function(){\n  var mat = new THREE.MeshBasicMaterial({color:0xe0ab6b, transparent:true, opacity:0.10,\n    side:THREE.DoubleSide, depthWrite:false, blending:THREE.AdditiveBlending});\n  [-0.6,0,0.6].forEach(function(offset){\n    var geo = new THREE.ConeGeometry(3.6, 8.5, 24, 1, true);\n    var beam = new THREE.Mesh(geo, mat);\n    beam.rotation.z = Math.PI\/2;\n    beam.rotation.y = offset*0.12;\n    beam.position.set(2.4,1.4,-1 + offset*0.9);\n    soundGroup.add(beam);\n  });\n  scene.add(soundGroup);\n})();\n\n\/* ============================================================\n   BACKSTAGE COMPOUND (D) \u2014 star trailer + generators, screened by trees\n   ============================================================ *\/\n(function(){\n  var g = new THREE.Group();\n  var trailer = new THREE.Mesh(new THREE.BoxGeometry(3.4,1.15,1.3),\n    new THREE.MeshLambertMaterial({color:0xd8d2c2}));\n  trailer.position.y = 0.7; trailer.castShadow = true; trailer.receiveShadow = true;\n  var stripe = new THREE.Mesh(new THREE.BoxGeometry(3.42,0.16,1.32),\n    new THREE.MeshLambertMaterial({color:0xc98a3d}));\n  stripe.position.y = 0.55;\n  g.add(trailer); g.add(stripe);\n\n  [[-1.4,1.1],[-1.4,-1.1]].forEach(function(p){\n    var wheel = new THREE.Mesh(new THREE.CylinderGeometry(0.22,0.22,0.2,10),\n      new THREE.MeshLambertMaterial({color:0x141414}));\n    wheel.rotation.z = Math.PI\/2;\n    wheel.position.set(p[0],0.22,p[1]);\n    g.add(wheel);\n  });\n\n  [1.9, 2.9].forEach(function(gz){\n    var gen = new THREE.Mesh(new THREE.BoxGeometry(0.9,0.7,0.6),\n      new THREE.MeshLambertMaterial({color:0x4a4d52}));\n    gen.position.set(0.2,0.35,gz);\n    gen.castShadow = true;\n    g.add(gen);\n  });\n\n  g.position.set(9.6,0,1.3);\n  g.rotation.y = -0.5;\n  scene.add(g);\n  addLabel('D',0x555a63,9.6,2.1,1.3);\n})();\n\n\/* ============================================================\n   HOSPITALITY TENT (E)\n   ============================================================ *\/\n(function(){\n  var tent = tentMesh(2.6,2.6,1.9,0xeee6d4,0xf4eee0);\n  tent.position.set(9.2,0,4.0);\n  scene.add(tent);\n  addLabel('E',0xd8cdb4,9.2,2.4,4.0);\n})();\n\n\/* ============================================================\n   VENDOR & FOOD ROW (F)\n   ============================================================ *\/\n(function(){\n  var positions = [[-1.4,-7.3],[0.2,-7.6],[1.8,-7.6],[3.4,-7.3],[4.8,-6.8]];\n  positions.forEach(function(p){\n    var tent = tentMesh(1.3,1.3,1.4,0x8a5a2b,0xc4a06a);\n    tent.position.set(p[0],0,p[1]);\n    scene.add(tent);\n  });\n  addLabel('F',0x8a5a2b,1.8,2.1,-7.6);\n})();\n\n\/* ============================================================\n   RESTROOM CLUSTERS (G x2)\n   ============================================================ *\/\nfunction restroomCluster(cx,cz){\n  var g = new THREE.Group();\n  for(var i=0;i<4;i++){\n    var unit = new THREE.Mesh(new THREE.BoxGeometry(0.5,1.1,0.5),\n      new THREE.MeshLambertMaterial({color:0xe8e2d0}));\n    unit.position.set((i%2)*0.65, 0.55, Math.floor(i\/2)*0.65);\n    unit.castShadow = true;\n    g.add(unit);\n  }\n  g.position.set(cx,0,cz);\n  scene.add(g);\n  return g;\n}\nrestroomCluster(-3.6,-6.2);\nrestroomCluster(2.4,5.4);\naddLabel('G',0xe8e2d0,-3.6,1.4,-6.2);\naddLabel('G',0xe8e2d0,2.4,1.4,5.4);\n\n\/* ============================================================\n   ENTRY GATE (H) + FIRST AID (J)\n   ============================================================ *\/\n(function(){\n  var g = new THREE.Group();\n  [-1.1,1.1].forEach(function(px){\n    var post = new THREE.Mesh(new THREE.CylinderGeometry(0.09,0.09,2.2,8),\n      new THREE.MeshLambertMaterial({color:0xa8433a}));\n    post.position.set(px,1.1,0);\n    post.castShadow = true;\n    g.add(post);\n  });\n  var arch = new THREE.Mesh(new THREE.BoxGeometry(2.4,0.22,0.14),\n    new THREE.MeshLambertMaterial({color:0xa8433a}));\n  arch.position.set(0,2.15,0);\n  g.add(arch);\n  g.position.set(-4.6,0,-8.3);\n  g.rotation.y = 0.5;\n  scene.add(g);\n  addLabel('H',0xa8433a,-4.6,2.9,-8.3);\n\n  var aidTent = tentMesh(1.1,1.1,1.3,0xa8433a,0xf1e9d8);\n  aidTent.position.set(-2.9,0,-8.0);\n  scene.add(aidTent);\n  addLabel('J',0xa8433a,-2.9,1.9,-8.0);\n})();\n\n\/* ============================================================\n   PARKING \u2014 K (artist\/production) & L (general)\n   ============================================================ *\/\nvar carColors = [0x6b7b8a,0x8a7b6b,0x5a6b5a,0x7a6b7b,0x8a8a8a];\n(function(){ \/* K \u2014 small cluster near residence *\/\n  var pts = [[-6.8,-13.5],[-6.0,-13.5],[-5.2,-13.5],[-6.8,-14.4],[-6.0,-14.4],[-5.2,-14.4]];\n  pts.forEach(function(p){\n    var c = carBlock(carColors[Math.floor(rng()*carColors.length)]);\n    c.position.set(p[0],0,p[1]);\n    c.rotation.y = 0.05;\n    scene.add(c);\n  });\n  addLabel('K',0x3a4b6c,-6.0,1.1,-15.4);\n})();\n(function(){ \/* L \u2014 general parking, rows south of the field *\/\n  var rows=4, cols=7;\n  for(var r=0;r<rows;r++){\n    for(var cIdx=0;cIdx<cols;cIdx++){\n      var c = carBlock(carColors[Math.floor(rng()*carColors.length)]);\n      c.position.set(-6 + cIdx*1.15, 0, 9.5 + r*2.1);\n      scene.add(c);\n    }\n  }\n  addLabel('L',0x3a4b6c,-2,1.1,15.5);\n})();\n\n\/* ============================================================\n   TRASH \/ RECYCLING (M)\n   ============================================================ *\/\nfunction trashBin(x,z){\n  var g = new THREE.Group();\n  [0,0.32].forEach(function(off,i){\n    var bin = new THREE.Mesh(new THREE.CylinderGeometry(0.16,0.14,0.4,8),\n      new THREE.MeshLambertMaterial({color:i===0?0x6b7f3f:0x555a63}));\n    bin.position.set(off,0.2,0);\n    bin.castShadow = true;\n    g.add(bin);\n  });\n  g.position.set(x,0,z);\n  scene.add(g);\n}\n[[4.6,3.6],[6.2,-2.4],[-1.5,-6.0],[2.0,6.4]].forEach(function(p){ trashBin(p[0],p[1]); });\naddLabel('M',0x6b7f3f,4.6,1.0,3.6);\n\n\/* ============================================================\n   POND (east edge, per aerial)\n   ============================================================ *\/\n(function(){\n  var geo = new THREE.CircleGeometry(6.2,28);\n  var mat = new THREE.MeshLambertMaterial({color:0x2f4f5f, transparent:true, opacity:0.88});\n  var pond = new THREE.Mesh(geo, mat);\n  pond.rotation.x = -Math.PI\/2;\n  pond.scale.set(1.1,0.65,1);\n  pond.position.set(14.5,0.015,-1);\n  pond.receiveShadow = true;\n  scene.add(pond);\n})();\n\n\/* ============================================================\n   CAMERA CONTROLS \u2014 custom spherical orbit (no OrbitControls dependency)\n   ============================================================ *\/\nvar cam = {\n  target: new THREE.Vector3(1,0.8,0),\n  radius: 26, theta: 0.65, phi: 0.95\n};\nvar animTarget = null, animT = 0, animDur = 1.1, animFrom = null;\n\nfunction shortestAngle(a,b){\n  var d = (b-a) % (Math.PI*2);\n  if(d > Math.PI) d -= Math.PI*2;\n  if(d < -Math.PI) d += Math.PI*2;\n  return a+d;\n}\n\nfunction updateCameraFromSpherical(){\n  var x = cam.target.x + cam.radius*Math.sin(cam.phi)*Math.sin(cam.theta);\n  var y = cam.target.y + cam.radius*Math.cos(cam.phi);\n  var z = cam.target.z + cam.radius*Math.sin(cam.phi)*Math.cos(cam.theta);\n  camera.position.set(x,y,z);\n  camera.lookAt(cam.target);\n  var deg = (cam.theta*180\/Math.PI) % 360;\n  var compassSvg = document.querySelector('#compass svg');\n  if(compassSvg) compassSvg.style.transform = 'rotate(' + (-deg) + 'deg)';\n}\n\nvar PRESETS = {\n  aerial:{theta:0.55, phi:0.62, radius:30, target:[1,0.6,0]},\n  \/* camera stands on the stage, looking out west across the lawn *\/\n  stage: {theta:1.60, phi:1.35, radius:7.0, target:[0.8,1.5,-0.2]},\n  \/* camera stands in the crowd, looking back east at the stage *\/\n  crowd: {theta:-1.40, phi:1.42, radius:9.3, target:[7.2,1.9,-0.6]},\n  gate:  {theta:1.95, phi:1.30, radius:8.5, target:[-1.5,1.2,-7.2]}\n};\n\nfunction goToPreset(name){\n  var p = PRESETS[name];\n  animFrom = {theta:cam.theta, phi:cam.phi, radius:cam.radius, target:cam.target.clone()};\n  var toTheta = shortestAngle(cam.theta, p.theta);\n  animTarget = {theta:toTheta, phi:p.phi, radius:p.radius,\n    target:new THREE.Vector3(p.target[0],p.target[1],p.target[2])};\n  animT = 0;\n}\n\n\/* pointer \/ touch drag to orbit *\/\nvar dragging=false, lastX=0, lastY=0;\nvar pinchDist=null;\nfunction pointerDown(x,y){ dragging=true; lastX=x; lastY=y; canvasEl.classList.add('dragging'); }\nfunction pointerMove(x,y){\n  if(!dragging) return;\n  var dx = x-lastX, dy = y-lastY;\n  cam.theta -= dx*0.0055;\n  cam.phi -= dy*0.0045;\n  cam.phi = Math.max(0.18, Math.min(1.55, cam.phi));\n  lastX=x; lastY=y;\n}\nfunction pointerUp(){ dragging=false; canvasEl.classList.remove('dragging'); }\n\ncanvasEl.addEventListener('mousedown', function(e){ pointerDown(e.clientX,e.clientY); });\nwindow.addEventListener('mousemove', function(e){ pointerMove(e.clientX,e.clientY); });\nwindow.addEventListener('mouseup', pointerUp);\n\ncanvasEl.addEventListener('touchstart', function(e){\n  if(e.touches.length===1){ pointerDown(e.touches[0].clientX, e.touches[0].clientY); }\n  else if(e.touches.length===2){\n    var dx=e.touches[0].clientX-e.touches[1].clientX, dy=e.touches[0].clientY-e.touches[1].clientY;\n    pinchDist = Math.sqrt(dx*dx+dy*dy);\n  }\n},{passive:true});\ncanvasEl.addEventListener('touchmove', function(e){\n  if(e.touches.length===1){ pointerMove(e.touches[0].clientX, e.touches[0].clientY); }\n  else if(e.touches.length===2 && pinchDist){\n    var dx=e.touches[0].clientX-e.touches[1].clientX, dy=e.touches[0].clientY-e.touches[1].clientY;\n    var d = Math.sqrt(dx*dx+dy*dy);\n    var delta = pinchDist - d;\n    cam.radius = Math.max(4, Math.min(55, cam.radius + delta*0.05));\n    pinchDist = d;\n  }\n},{passive:true});\ncanvasEl.addEventListener('touchend', function(e){ if(e.touches.length===0){ pointerUp(); pinchDist=null; } });\n\ncanvasEl.addEventListener('wheel', function(e){\n  e.preventDefault();\n  cam.radius = Math.max(4, Math.min(55, cam.radius + e.deltaY*0.02));\n},{passive:false});\n\n\/* hide the hint after first interaction \/ a few seconds *\/\nvar hintEl = document.getElementById('hint');\nvar hintHidden=false;\nfunction hideHint(){ if(!hintHidden){ hintEl.classList.add('fade'); hintHidden=true; } }\ncanvasEl.addEventListener('mousedown', hideHint);\ncanvasEl.addEventListener('touchstart', hideHint);\nsetTimeout(hideHint, 5000);\n\n\/* ============================================================\n   UI WIRING\n   ============================================================ *\/\ndocument.querySelectorAll('.pill[data-preset]').forEach(function(btn){\n  btn.addEventListener('click', function(){\n    document.querySelectorAll('.pill[data-preset]').forEach(function(b){b.classList.remove('active');});\n    btn.classList.add('active');\n    goToPreset(btn.getAttribute('data-preset'));\n  });\n});\n\nvar panelToggle = document.getElementById('panel-toggle');\nvar sidePanel = document.getElementById('side-panel');\nvar closePanel = document.getElementById('close-panel');\npanelToggle.addEventListener('click', function(){ sidePanel.classList.remove('hidden'); panelToggle.style.display='none'; });\nclosePanel.addEventListener('click', function(){ sidePanel.classList.add('hidden'); panelToggle.style.display='flex'; });\n\ndocument.querySelectorAll('.tod-btn').forEach(function(btn){\n  btn.addEventListener('click', function(){\n    document.querySelectorAll('.tod-btn').forEach(function(b){b.classList.remove('active');});\n    btn.classList.add('active');\n    applyTOD(btn.getAttribute('data-tod'));\n  });\n});\n\nfunction wireSwitch(id, onChange){\n  var el = document.getElementById(id);\n  var state = true;\n  el.addEventListener('click', function(){\n    state = !state;\n    el.classList.toggle('on', state);\n    onChange(state);\n  });\n}\nwireSwitch('toggle-labels', function(on){ labelSprites.forEach(function(s){ s.visible = on; }); });\nwireSwitch('toggle-crowd', function(on){ crowdGroup.visible = on; });\nwireSwitch('toggle-sound', function(on){ soundGroup.visible = on; });\n\n\/* ============================================================\n   ANIMATE\n   ============================================================ *\/\napplyTOD('golden');\nupdateCameraFromSpherical();\n\nvar clock = new THREE.Clock();\nfunction animate(){\n  requestAnimationFrame(animate);\n  var dt = clock.getDelta();\n\n  if(animTarget){\n    animT += dt\/animDur;\n    var t = Math.min(1, animT);\n    var e = t<0.5 ? 2*t*t : 1-Math.pow(-2*t+2,2)\/2; \/* ease-in-out-quad *\/\n    cam.theta = animFrom.theta + (animTarget.theta-animFrom.theta)*e;\n    cam.phi = animFrom.phi + (animTarget.phi-animFrom.phi)*e;\n    cam.radius = animFrom.radius + (animTarget.radius-animFrom.radius)*e;\n    cam.target.lerpVectors(animFrom.target, animTarget.target, e);\n    if(t>=1){ animTarget=null; }\n  }\n\n  \/* label sprites always face camera and stay legible-sized *\/\n  labelSprites.forEach(function(s){\n    var d = s.position.distanceTo(camera.position);\n    var sc = Math.max(0.55, Math.min(1.3, d*0.045));\n    s.scale.set(sc,sc,sc);\n  });\n\n  updateCameraFromSpherical();\n  renderer.render(scene, camera);\n}\nanimate();\n\n})();\n<\/script>\n<\/body>\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Nikki Mitchell Jazz Festival \u2014 3D Site Model Nikki Mitchell Jazz Festival 150 Heartland Ln, Henderson NC \u2014 3D site model, schematic scaledrag to orbit \u00b7 scroll \/ pinch to zoom N Camera Aerial Stage-eye Crowd-eye Arrival \/ Gate \u2630 \u2715 Site Key Time of Day Midday Golden Hr Dusk Display Labels Crowd markers Sound [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-516","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/Pa6WkL-8k","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/pages\/516","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/comments?post=516"}],"version-history":[{"count":8,"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/pages\/516\/revisions"}],"predecessor-version":[{"id":526,"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/pages\/516\/revisions\/526"}],"wp:attachment":[{"href":"https:\/\/itutu.com\/index.php\/wp-json\/wp\/v2\/media?parent=516"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}