{
  "version": 3,
  "sources": ["../../../Scripts/scenes/phone-figures/steps.mjs", "../../../Scripts/scenes/phone-figures/spring.mjs", "../../../Scripts/scenes/phone-figures/gesture.mjs", "../../../Scripts/scenes/phone-figures.mjs"],
  "sourcesContent": ["// Which screen a phone figure shows, and the timer that moves it on while the figure is in view.\n// The reader's first click, key or swipe ends the auto-advance for good: from then on the figure\n// only moves when they move it.\nexport function createSteps({ count, interval = 4500, timers = globalThis, onChange = () => {} }) {\n  let index = 0;\n  let autoplay = count > 1;\n  let playing = false;\n  let timer = null;\n\n  const schedule = () => {\n    timers.clearTimeout(timer);\n    timer = playing && autoplay ? timers.setTimeout(() => { go(index + 1); }, interval) : null;\n  };\n\n  function go(i, { user = false } = {}) {\n    if (count < 2) return;\n    if (user) autoplay = false;\n    const wrapped = Number.isInteger(i) && (i < 0 || i >= count) && Math.abs(i - index) === 1\n      ? (i + count) % count // next/prev wrap around\n      : Math.min(count - 1, Math.max(0, i)); // a direct pick is clamped\n    if (wrapped !== index) {\n      const from = index;\n      index = wrapped;\n      onChange(index, from);\n    }\n    schedule();\n  }\n\n  return {\n    get index() { return index; },\n    get autoplay() { return autoplay; },\n    go,\n    next: opts => go(index + 1, opts),\n    prev: opts => go(index - 1, opts),\n    play() { playing = true; schedule(); },\n    pause() { playing = false; schedule(); },\n  };\n}\n", "// A damped spring for one angle of the phone (degrees). It runs only while it moves: the player\n// stops drawing once every spring has settled.\nexport function createSpring({ value = 0, stiffness = 170, damping = 22 } = {}) {\n  let velocity = 0;\n  const spring = {\n    value,\n    target: value,\n    get settled() {\n      return Math.abs(spring.target - spring.value) < 0.02 && Math.abs(velocity) < 0.05;\n    },\n    step(dt) {\n      // Fixed substeps keep it stable through a long frame (a tab coming back).\n      let left = Math.min(dt, 0.25);\n      while (left > 0) {\n        const h = Math.min(left, 1 / 120);\n        const force = stiffness * (spring.target - spring.value) - damping * velocity;\n        velocity += force * h;\n        spring.value += velocity * h;\n        left -= h;\n      }\n      if (spring.settled) {\n        spring.value = spring.target;\n        velocity = 0;\n      }\n    },\n  };\n  return spring;\n}\n", "// Tells a step swipe from a page scroll on a touch screen. The phone has touch-action: pan-y, so\n// the browser keeps vertical scrolling; a move only counts as a swipe once it is clearly sideways.\nexport function createSwipe({ rtl = false, distance = 48, flick = 24, flickMs = 160, tapSlop = 8, tapMs = 300 } = {}) {\n  return {\n    // true / false once the direction is clear, null while it is not yet.\n    isHorizontal({ dx, dy }) {\n      if (Math.hypot(dx, dy) < 10) return null;\n      return Math.abs(dx) > Math.abs(dy) * 1.5;\n    },\n    // What a finished touch was: 'next', 'prev', 'tap' or null.\n    classify({ dx, dy, ms }) {\n      if (Math.abs(dx) <= tapSlop && Math.abs(dy) <= tapSlop) return ms <= tapMs ? 'tap' : null;\n      if (Math.abs(dx) < Math.abs(dy) * 1.5) return null;\n      const far = Math.abs(dx) >= distance && ms < 800;\n      const quick = Math.abs(dx) >= flick && ms <= flickMs;\n      if (!far && !quick) return null;\n      // Swiping left pulls the next screen in, the way a carousel does; RTL reads the other way.\n      return (dx < 0) !== rtl ? 'next' : 'prev';\n    },\n  };\n}\n", "// Phone figures: a 3D iPhone in a blog post that shows the app's screens, step by step.\n//\n// PhoneFigureProcessor expands a post's <figure class=\"phone-figure\"> into its final markup at\n// build time: a device box (the screenshots, stacked, behind a still of the phone with its screen\n// cut out), the step buttons and the dots. So the figure is laid out before any script runs, and\n// works in three tiers:\n//   1. No JS: the first screen in the phone still, every step's text beside or under it.\n//   2. This module, always: buttons, dots, arrow keys, swipe and tap step through the screens,\n//      which cross-fade in the DOM, so their text stays pin-sharp. A stage (data-layout=\"stage\")\n//      also moves on by itself while it is in view, until the reader takes over.\n//   3. WebGL2, no reduced motion, no Save-Data: once the page is idle and the figure is near the\n//      viewport, three.js and the phone (blog_phone.glb, ~150 KB) load and a canvas draws the same\n//      phone, straight on, exactly over the still. It fades in, turns gently towards the text, and\n//      then follows the pointer: hovering leans it, a drag turns it. A step change pushes the next\n//      screen in from the side, the way the app itself navigates; the phone holds still for it.\n//      It draws only while something moves.\n//\n// The still (blog_phone_shell.webp) is drawn by this module itself (?debug, see\n// Scripts/scenes/render-phone-shell.mjs), so the two match; window.phoneFigures.screenRect()\n// prints where the screen sits, for .phone-figure-screens in Theme/css/phone-figure.css.\n//\n// This is the source: Scripts/scenes/build.sh --js bundles it (with ./phone-figures/*.mjs) into\n// Content/StaticFiles/scenes/, next to the three bundle it shares with live-scenes.mjs.\nimport { createSteps } from './phone-figures/steps.mjs';\nimport { createSpring } from './phone-figures/spring.mjs';\nimport { createSwipe } from './phone-figures/gesture.mjs';\n\nconst BASE = new URL('./', import.meta.url);\nconst MAX_DPR = 2;\nconst NEAR_VIEWPORT = '300px';\n// The camera: the device straight on, filling PHONE_FILL of its box (CSS aspect-ratio, 5 / 8 for a\n// phone) in whichever direction is tighter.\nconst FOV = 20;\nconst PHONE_FILL = 0.84;\n// The pose it rests in once live, turned towards the text (degrees), and how far a drag turns it.\nconst REST_YAW = 14;\nconst REST_PITCH = 3;\nconst HOVER_YAW = 15;\nconst HOVER_PITCH = 10;\nconst DRAG_YAW = 35;\nconst DRAG_PITCH = 15;\nconst PUSH_MS = 460;\n// What a figure shows (data-device): the phone from the front, its screen showing the shots, or\n// the phone in the orange NFC e-ink case from the back, its e-ink panel showing them. pin is how\n// much of the top of the screen stays put through a push (the phone's status bar).\n// aspect is the box's (width / height, matching the CSS); stillPitch the tilt (degrees) the still\n// and the first frame show it at, so a laptop's display faces the camera with its deck in view.\nconst DEVICES = {\n  phone: { model: 'blog_phone.glb', screen: 'Object_13', back: false, pin: 0.052, aspect: 5 / 8, stillPitch: 0 },\n  einkcase: { model: 'blog_einkcase.glb', screen: 'EInkPanel', back: true, pin: -1, aspect: 5 / 8, stillPitch: 0 },\n  // The iPad lies on the desk with the reader below it, seen from above; the Mac's desk is\n  // already tilted in the model so its display faces the camera.\n  ipad: { model: 'blog_ipad.glb', screen: 'IPadDisplay', back: false, pin: 0.022, aspect: 7 / 10, stillPitch: 0 },\n  mac: { model: 'blog_mac.glb', screen: 'MacDisplay', back: false, pin: 0.03, aspect: 3 / 2, stillPitch: 0 },\n};\n\nconst figures = [...document.querySelectorAll('figure.phone-figure')];\nconst reducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;\nconst saveData = navigator.connection?.saveData === true;\nconst rtl = document.documentElement.dir === 'rtl';\nconst debug = new URLSearchParams(location.search).has('debug');\nconst log = (...args) => debug && console.log('[phone-figures]', ...args);\n\nconst views = figures.map(setUp);\n\nif (views.length && !reducedMotion && !saveData && hasWebGL2()) {\n  afterLoad().then(goLive).catch(error => console.warn('[phone-figures]', error));\n} else {\n  log('3D skipped', { reducedMotion, saveData });\n}\nif (debug) window.phoneFigures = { views };\n\n// ---- tier 2: the DOM figure ----\n\nfunction setUp(figure) {\n  const device = figure.querySelector('.phone-figure-device');\n  const shots = [...figure.querySelectorAll('.phone-figure-shot')];\n  const items = [...figure.querySelectorAll('.phone-figure-steps > li')];\n  const buttons = items.map(li => li.querySelector('.phone-figure-step'));\n  const dots = [...figure.querySelectorAll('.phone-figure-dots > button')];\n  const view = { figure, device, shots, live: null };\n\n  const show = i => {\n    shots.forEach((shot, k) => shot.classList.toggle('is-active', k === i));\n    items.forEach((li, k) => li.classList.toggle('is-active', k === i));\n    buttons.forEach((b, k) => b?.setAttribute('aria-pressed', String(k === i)));\n    dots.forEach((d, k) => d.setAttribute('aria-pressed', String(k === i)));\n  };\n  view.steps = createSteps({\n    count: shots.length,\n    onChange: (i, from) => {\n      show(i);\n      view.live?.change(i, from);\n    },\n  });\n  show(0);\n\n  buttons.forEach((b, i) => b?.addEventListener('click', () => view.steps.go(i, { user: true })));\n  dots.forEach((d, i) => d.addEventListener('click', () => view.steps.go(i, { user: true })));\n  figure.addEventListener('keydown', event => {\n    if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;\n    if (!figure.contains(document.activeElement) || event.target.closest('input, textarea')) return;\n    const forward = (event.key === 'ArrowRight') !== rtl;\n    forward ? view.steps.next({ user: true }) : view.steps.prev({ user: true });\n    // Keep focus on the control of the step now showing, so the keys keep working from there.\n    const visible = [...buttons, ...dots].filter(b => b && b.offsetParent && b.getAttribute('aria-pressed') === 'true');\n    visible[0]?.focus({ preventScroll: true });\n    event.preventDefault();\n  });\n\n  // Touch: swipe sideways or tap the phone to step; vertical moves stay the page's (pan-y).\n  const swipe = createSwipe({ rtl });\n  let touch = null;\n  device.addEventListener('pointerdown', event => {\n    if (event.pointerType === 'mouse') return;\n    touch = { x: event.clientX, y: event.clientY, t: performance.now(), id: event.pointerId };\n  });\n  device.addEventListener('pointercancel', () => { touch = null; });\n  device.addEventListener('pointerup', event => {\n    if (!touch || event.pointerId !== touch.id) return;\n    const gesture = swipe.classify({ dx: event.clientX - touch.x, dy: event.clientY - touch.y, ms: performance.now() - touch.t });\n    touch = null;\n    if (gesture === 'next' || gesture === 'tap') view.steps.next({ user: true });\n    else if (gesture === 'prev') view.steps.prev({ user: true });\n  });\n  // A mouse click on the phone (without dragging it, see goLive) also moves on.\n  device.addEventListener('click', event => {\n    if (event.pointerType && event.pointerType !== 'mouse') return;\n    if (view.dragged) { view.dragged = false; return; }\n    view.steps.next({ user: true });\n  });\n\n  // A stage moves on by itself while most of it is in view, on screens with a real pointer only:\n  // on a phone the reader scrolls past, and a figure changing under their thumb is a distraction.\n  const autoplay = figure.dataset.layout === 'stage' && shots.length > 1 && !reducedMotion\n    && matchMedia('(hover: hover) and (pointer: fine)').matches;\n  if (autoplay) {\n    new IntersectionObserver(([entry]) => {\n      entry.isIntersecting ? view.steps.play() : view.steps.pause();\n    }, { threshold: 0.6 }).observe(figure);\n  }\n  return view;\n}\n\n// ---- tier 3: the live phone ----\n\nfunction hasWebGL2() {\n  try {\n    return !!document.createElement('canvas').getContext('webgl2');\n  } catch {\n    return false;\n  }\n}\n\nfunction afterLoad() {\n  const loaded = document.readyState === 'complete'\n    ? Promise.resolve()\n    : new Promise(resolve => addEventListener('load', resolve, { once: true }));\n  return loaded.then(() => new Promise(resolve => {\n    if ('requestIdleCallback' in window) requestIdleCallback(resolve, { timeout: 2000 });\n    else setTimeout(resolve, 200);\n  }));\n}\n\nasync function goLive() {\n  const t0 = performance.now();\n  const THREE = await import('./vendor/three.scenes.min.mjs');\n  log(`three loaded in ${Math.round(performance.now() - t0)} ms`);\n  const {\n    Box3, DirectionalLight, GLTFLoader, Group, MeshBasicMaterial, MeshoptDecoder, NeutralToneMapping,\n    NoBlending, PMREMGenerator, PerspectiveCamera, RoomEnvironment, SRGBColorSpace, Scene, ShaderMaterial,\n    Texture, Vector3, WebGLRenderer,\n  } = THREE;\n\n  const loader = new GLTFLoader().setMeshoptDecoder(MeshoptDecoder);\n  const models = new Map();\n  const loadModel = name => {\n    if (!models.has(name)) models.set(name, loader.loadAsync(new URL(name, BASE).href));\n    return models.get(name);\n  };\n\n  const observer = new IntersectionObserver(entries => {\n    for (const entry of entries) {\n      if (!entry.isIntersecting) continue;\n      observer.unobserve(entry.target);\n      const view = views.find(v => v.figure === entry.target);\n      mount(view).catch(error => console.warn('[phone-figures]', error));\n    }\n  }, { rootMargin: NEAR_VIEWPORT });\n  views.forEach(view => observer.observe(view.figure));\n\n  if (debug) Object.assign(window.phoneFigures, { THREE });\n\n  async function mount(view) {\n    const started = performance.now();\n    const { device } = view;\n    const canvas = document.createElement('canvas');\n    canvas.className = 'phone-figure-canvas';\n    canvas.setAttribute('aria-hidden', 'true');\n    const renderer = new WebGLRenderer({ canvas, alpha: true, antialias: true, premultipliedAlpha: true, preserveDrawingBuffer: debug });\n    renderer.outputColorSpace = SRGBColorSpace;\n    renderer.toneMapping = NeutralToneMapping;\n    renderer.setClearColor(0x000000, 0);\n\n    const scene = new Scene();\n    const pmrem = new PMREMGenerator(renderer);\n    scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;\n    scene.environmentIntensity = 0.9;\n    pmrem.dispose();\n    const key = new DirectionalLight(0xffffff, 1.6);\n    key.position.set(-0.4, 0.6, 1);\n    scene.add(key);\n\n    const kind = DEVICES[view.figure.dataset.device] ?? DEVICES.phone;\n    const gltf = await loadModel(kind.model);\n    const parts = (gltf.scene.getObjectByName('Phone') ?? gltf.scene).clone(true);\n    // The model's screen faces -Z: turn it to the camera (or, for the case, show its back) and\n    // centre it, so it turns about its own middle.\n    const facing = new Group();\n    facing.rotation.y = kind.back ? 0 : Math.PI;\n    facing.add(parts);\n    const center = new Box3().setFromObject(facing).getCenter(new Vector3());\n    facing.position.sub(center);\n    const pose = new Group();\n    pose.add(facing);\n    scene.add(pose);\n    const size = new Box3().setFromObject(pose).getSize(new Vector3());\n\n    const camera = new PerspectiveCamera(FOV, kind.aspect, 0.05, 5);\n    const halfTan = Math.tan(FOV * Math.PI / 360);\n    camera.position.set(0, 0, Math.max(\n      size.y / PHONE_FILL / 2 / halfTan,\n      size.x / PHONE_FILL / 2 / (halfTan * kind.aspect),\n    ));\n    camera.lookAt(0, 0, 0);\n\n    // The screen: shot a, and shot b on its way in, either fading over a or pushing it aside the\n    // way an iOS navigation push does (b slides in from the side, a drifts a third of the way out).\n    const screen = parts.getObjectByName(kind.screen);\n    if (!screen) throw new Error('no screen mesh');\n    const base = new ShaderMaterial({\n      toneMapped: false,\n      uniforms: { a: { value: null }, b: { value: null }, t: { value: 0 }, dir: { value: 1 }, pin: { value: kind.pin } },\n      vertexShader: `varying vec2 vUv;\n        void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,\n      // No texture reads inside branches: the GPU works out which mip level to sample from the\n      // neighbouring pixels, and where they take different branches (the edge of the status bar\n      // band) the guess goes wrong and draws a dashed line. Every pixel samples all four, then picks.\n      fragmentShader: `uniform sampler2D a; uniform sampler2D b; uniform float t; uniform float dir; uniform float pin;\n        varying vec2 vUv;\n        void main() {\n          // dir 1: b comes in from the right; -1: from the left. x runs in the direction of travel.\n          float x = dir > 0.0 ? vUv.x : 1.0 - vUv.x;\n          float edge = 1.0 - t;\n          float bx = x - edge;\n          float ax = x + t * 0.33;\n          vec4 pushedB = texture2D(b, vec2(dir > 0.0 ? bx : 1.0 - bx, vUv.y));\n          vec4 pushedA = texture2D(a, vec2(dir > 0.0 ? ax : 1.0 - ax, vUv.y));\n          vec4 stillA = texture2D(a, vUv);\n          vec4 stillB = texture2D(b, vUv);\n          pushedB.rgb *= 1.0 - 0.12 * smoothstep(0.0, 0.03, 0.03 - bx); // a soft shadow on b's leading edge\n          pushedA.rgb *= 1.0 - 0.18 * t; // a dims as it goes, like the screen underneath a push\n          vec4 pushed = mix(pushedA, pushedB, step(edge, x));\n          // The status bar stays put through a push, as on iOS (every shot has the same 9:41 bar;\n          // glTF UVs run top down).\n          vec4 still = mix(stillA, stillB, step(0.5, t));\n          gl_FragColor = mix(pushed, still, step(vUv.y, pin));\n          #include <colorspace_fragment>\n        }`,\n    });\n    // GLTFLoader may keep the node as a group around the mesh: dress the meshes under it.\n    screen.traverse(o => { if (o.isMesh) o.material = base; });\n\n    const textures = new Map();\n    const textureFor = async i => {\n      if (!textures.has(i)) {\n        textures.set(i, (async () => {\n          const img = view.shots[i];\n          img.loading = 'eager';\n          await img.decode();\n          const texture = new Texture(img);\n          texture.colorSpace = SRGBColorSpace;\n          texture.flipY = false; // glTF UVs\n          texture.anisotropy = renderer.capabilities.getMaxAnisotropy();\n          texture.needsUpdate = true;\n          return texture;\n        })());\n      }\n      return textures.get(i);\n    };\n    base.uniforms.a.value = base.uniforms.b.value = await textureFor(view.steps.index);\n\n    // Which way is \"towards the text\": a stage's phone sits at the start of the line, a float's at its end.\n    const atStart = view.figure.dataset.layout === 'stage' ? view.figure.dataset.side !== 'end' : view.figure.dataset.side === 'start';\n    const towardsText = (atStart !== rtl) ? 1 : -1;\n    const yaw = createSpring({ value: 0 });\n    const pitch = createSpring({ value: kind.stillPitch });\n    const rest = { yaw: towardsText * REST_YAW, pitch: kind.stillPitch + REST_PITCH };\n    let fade = null; // { to, start }\n\n    let width = 0;\n    let height = 0;\n    const resize = () => {\n      const dpr = Math.min(devicePixelRatio || 1, MAX_DPR);\n      width = Math.round(device.clientWidth * dpr);\n      height = Math.round(device.clientHeight * dpr);\n      if (!width || !height) return;\n      renderer.setSize(width, height, false);\n      camera.aspect = width / height;\n      camera.updateProjectionMatrix();\n      invalidate();\n    };\n\n    let running = false;\n    let last = 0;\n    function invalidate() {\n      if (running) return;\n      running = true;\n      last = performance.now();\n      requestAnimationFrame(frame);\n    }\n    function frame(now) {\n      const dt = Math.min(0.1, (now - last) / 1000);\n      last = now;\n      yaw.step(dt);\n      pitch.step(dt);\n      if (fade) {\n        const t = Math.min(1, (now - fade.start) / PUSH_MS);\n        base.uniforms.t.value = 1 - Math.pow(1 - t, 3); // ease out, like a navigation push\n        if (t === 1) {\n          base.uniforms.a.value = base.uniforms.b.value;\n          base.uniforms.t.value = 0;\n          fade = null;\n        }\n      }\n      draw();\n      if (!yaw.settled || !pitch.settled || fade) requestAnimationFrame(frame);\n      else running = false;\n    }\n    function draw() {\n      pose.rotation.set(pitch.value * Math.PI / 180, yaw.value * Math.PI / 180, 0);\n      renderer.render(scene, camera);\n    }\n\n    view.live = {\n      async change(to, from) {\n        const texture = await textureFor(to);\n        if (view.steps.index !== to) return; // the reader has already moved on\n        if (fade) base.uniforms.a.value = base.uniforms.b.value;\n        const forward = to > from ? to - from <= view.shots.length / 2 : from - to > view.shots.length / 2;\n        base.uniforms.b.value = texture;\n        base.uniforms.t.value = 0;\n        base.uniforms.dir.value = (forward !== rtl) ? 1 : -1; // back slides the other way, like iOS\n        fade = { to, start: performance.now() };\n        invalidate();\n      },\n    };\n\n    // Pointer: hovering turns the phone to face the pointer (both axes the same way: the point under\n    // the pointer recedes), dragging turns it further as if the screen were grabbed and pulled,\n    // and letting go springs it back to rest. Touch never turns it: there, a swipe steps (setUp).\n    let drag = null;\n    const fine = matchMedia('(hover: hover) and (pointer: fine)').matches;\n    const relative = event => {\n      const box = device.getBoundingClientRect();\n      return { x: (event.clientX - box.left) / box.width - 0.5, y: (event.clientY - box.top) / box.height - 0.5 };\n    };\n    if (fine) {\n      device.addEventListener('pointermove', event => {\n        if (event.pointerType !== 'mouse') return;\n        if (drag) {\n          const dx = event.clientX - drag.x;\n          const dy = event.clientY - drag.y;\n          if (Math.hypot(dx, dy) > 4) view.dragged = true;\n          yaw.target = clamp(drag.yaw + dx * 0.45, -DRAG_YAW, DRAG_YAW);\n          pitch.target = clamp(drag.pitch + dy * 0.3, kind.stillPitch - DRAG_PITCH, kind.stillPitch + DRAG_PITCH);\n        } else {\n          const p = relative(event);\n          yaw.target = rest.yaw + p.x * 2 * HOVER_YAW;\n          pitch.target = rest.pitch + p.y * 2 * HOVER_PITCH;\n        }\n        invalidate();\n      });\n      device.addEventListener('pointerdown', event => {\n        if (event.pointerType !== 'mouse' || event.button !== 0) return;\n        drag = { x: event.clientX, y: event.clientY, yaw: yaw.target, pitch: pitch.target };\n        view.dragged = false;\n        device.setPointerCapture(event.pointerId);\n        device.classList.add('is-dragging');\n        event.preventDefault(); // no text selection\n      });\n      const release = () => {\n        if (!drag) return;\n        drag = null;\n        device.classList.remove('is-dragging');\n        yaw.target = rest.yaw;\n        pitch.target = rest.pitch;\n        invalidate();\n      };\n      device.addEventListener('pointerup', release);\n      device.addEventListener('lostpointercapture', release);\n      device.addEventListener('pointerleave', () => {\n        if (drag) return;\n        yaw.target = rest.yaw;\n        pitch.target = rest.pitch;\n        invalidate();\n      });\n    }\n\n    canvas.addEventListener('webglcontextlost', event => {\n      event.preventDefault();\n      running = true; // stop drawing for good\n      view.live = null;\n      device.classList.remove('is-live');\n      canvas.remove();\n    });\n\n    // First frame: straight on, exactly the still. Then fade the canvas in and turn to rest.\n    device.append(canvas);\n    resize();\n    new ResizeObserver(resize).observe(device);\n    draw();\n    device.classList.add('is-live');\n    log(`figure live in ${Math.round(performance.now() - started)} ms`);\n    setTimeout(() => {\n      yaw.target = rest.yaw;\n      pitch.target = rest.pitch;\n      invalidate();\n    }, 450);\n\n    if (debug) {\n      Object.assign(view, { renderer, scene, camera, pose, screen, draw, yaw, pitch });\n      // The still: the phone straight on, its screen cut out (alpha 0) for the shots behind it.\n      view.renderShell = (w, h) => {\n        const hole = new MeshBasicMaterial({ color: 0x000000, opacity: 0, blending: NoBlending });\n        screen.traverse(o => { if (o.isMesh) o.material = hole; });\n        pose.rotation.set(kind.stillPitch * Math.PI / 180, 0, 0);\n        renderer.setSize(w, h, false);\n        renderer.render(scene, camera);\n        const url = canvas.toDataURL('image/webp', 0.92);\n        screen.traverse(o => { if (o.isMesh) o.material = base; });\n        resize();\n        return url;\n      };\n      // Where the screen lands in the box, straight on, as CSS percentages of it.\n      view.screenRect = () => {\n        pose.rotation.set(kind.stillPitch * Math.PI / 180, 0, 0);\n        pose.updateMatrixWorld(true);\n        const box = new Box3().setFromObject(screen);\n        const corners = [new Vector3(box.min.x, box.min.y, box.max.z), new Vector3(box.max.x, box.max.y, box.max.z)]\n          .map(v => v.project(camera));\n        const [a, b] = corners;\n        const pct = v => +(v * 100).toFixed(3);\n        return {\n          left: pct((Math.min(a.x, b.x) + 1) / 2),\n          top: pct((1 - Math.max(a.y, b.y)) / 2),\n          width: pct(Math.abs(b.x - a.x) / 2),\n          height: pct(Math.abs(b.y - a.y) / 2),\n        };\n      };\n    }\n  }\n}\n\nfunction clamp(v, lo, hi) {\n  return Math.min(hi, Math.max(lo, v));\n}\n"],
  "mappings": "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",
  "names": ["createSteps", "count", "interval", "timers", "onChange", "index", "autoplay", "playing", "timer", "schedule", "go", "i", "user", "wrapped", "from", "opts", "createSpring", "value", "stiffness", "damping", "velocity", "spring", "dt", "left", "h", "force", "createSwipe", "rtl", "distance", "flick", "flickMs", "tapSlop", "tapMs", "dx", "dy", "ms", "far", "quick", "BASE", "MAX_DPR", "NEAR_VIEWPORT", "FOV", "PHONE_FILL", "REST_YAW", "REST_PITCH", "HOVER_YAW", "HOVER_PITCH", "DRAG_YAW", "DRAG_PITCH", "PUSH_MS", "DEVICES", "figures", "reducedMotion", "saveData", "rtl", "debug", "log", "args", "views", "setUp", "hasWebGL2", "afterLoad", "goLive", "error", "figure", "device", "shots", "items", "buttons", "li", "dots", "view", "show", "i", "shot", "k", "b", "d", "createSteps", "from", "event", "swipe", "createSwipe", "touch", "gesture", "entry", "resolve", "t0", "THREE", "Box3", "DirectionalLight", "GLTFLoader", "Group", "MeshBasicMaterial", "MeshoptDecoder", "NeutralToneMapping", "NoBlending", "PMREMGenerator", "PerspectiveCamera", "RoomEnvironment", "SRGBColorSpace", "Scene", "ShaderMaterial", "Texture", "Vector3", "WebGLRenderer", "loader", "models", "loadModel", "name", "observer", "entries", "v", "mount", "started", "canvas", "renderer", "scene", "pmrem", "key", "kind", "gltf", "parts", "facing", "center", "pose", "size", "camera", "halfTan", "screen", "base", "o", "textures", "textureFor", "img", "texture", "towardsText", "yaw", "createSpring", "pitch", "rest", "fade", "width", "height", "resize", "dpr", "invalidate", "running", "last", "frame", "now", "dt", "t", "draw", "to", "forward", "drag", "fine", "relative", "box", "dx", "dy", "clamp", "p", "release", "w", "h", "hole", "url", "corners", "a", "pct", "lo", "hi"]
}
