{
  "version": 1,
  "id": "scn_quality_control_video_blueprint",
  "slug": "quality-control-v2",
  "name": "Live quality control",
  "icon": "camera.metering.spot",
  "tint": "#AD7543",
  "settings": {
    "description": "Watch the inspection camera, compare the measurements, and keep a surface finding with the operator’s next step.",
    "welcomeSuggestions": [
      {
        "label": "Inspect this run",
        "prompt": "Look at the sample inspection camera, line measurements and machine view. What do the surface marks show, and what remains uncertain? Do not control any equipment."
      },
      {
        "label": "Record a finding",
        "prompt": "Help me write an inspection finding for this sample run. Ask for my observation, then keep it with the evidence in this scene."
      },
      {
        "label": "Use our equipment",
        "prompt": "Help me connect our own camera and line measurements to this inspection scene. Start by asking which sources and equipment we use."
      }
    ]
  },
  "assets": [
    {
      "id": "camera",
      "type": "daslab/webview",
      "name": "Inspection camera",
      "fields": {
        "html": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\n*{box-sizing:border-box}html,body{height:100%;margin:0;overflow:hidden}body{display:flex;flex-direction:column;background:#172023;color:#e2e9e6;font:11px/1.5 Inter,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif}header{height:48px;flex-shrink:0;padding:0 15px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #ffffff16}header strong{font-size:12px;font-weight:550;letter-spacing:-.2px}.status{font-size:9px;color:#a1bdac;display:flex;align-items:center;gap:5px}.status i{height:5px;width:5px;border-radius:50%;background:#a1c2ac}.viewport{position:relative;flex:1;min-height:0;overflow:hidden;background:#172023}.viewport>video{height:100%;width:100%;object-fit:cover;display:block}.viewport:after{content:'';position:absolute;inset:0;pointer-events:none;background:linear-gradient(#12202650,transparent 25%,transparent 75%,#12202655)}.hud,.foot{position:absolute;z-index:2;left:13px;right:13px;display:flex;justify-content:space-between;gap:8px;pointer-events:none;color:#eef4f1;text-shadow:0 1px 4px #102025;font:8px ui-monospace,monospace;letter-spacing:.05em}.hud{top:12px}.foot{bottom:12px}.target{position:absolute;z-index:3;border:1px solid #edbd80;box-shadow:0 0 0 1px #17202350;pointer-events:none}.target:before{content:'SURFACE CHECK';position:absolute;top:-20px;left:-1px;background:#e9b97a;color:#202b2b;padding:3px 5px;font:7px ui-monospace,monospace;white-space:nowrap}.target[hidden]{display:none}.evidence{height:118px;flex-shrink:0;background:#202a2d;padding:12px 15px;display:flex;align-items:center;gap:13px;border-top:1px solid #ffffff18}.strip{display:flex;gap:6px;flex-shrink:0}.strip figure{margin:0;width:62px}.capture{position:relative;height:50px;overflow:hidden;border:1px solid #bc96564d}.capture img{height:100%;width:100%;object-fit:cover;display:block;transform:scale(1.6)}.capture:after{content:'';position:absolute;left:36%;top:38%;width:28%;height:26%;border:1px solid #e9b97a}.strip figcaption{font:7px ui-monospace,monospace;color:#a9b7ae;margin-top:4px;white-space:nowrap}.evidence b{display:block;font-size:11px;font-weight:500;color:#e3d3bc}.evidence small{display:block;color:#92a8a0;font-size:9px;margin-top:4px}.tag{display:block;color:#cca36c;font:8px ui-monospace,monospace;margin-bottom:4px}.evidence.held .tag{color:#9fc3ad}.evidence.held b{color:#cfe2d5}.waiting{display:flex;gap:12px;align-items:center}.waiting>span{height:27px;width:27px;border-radius:50%;border:1px solid #6f8b7c;text-align:center;line-height:25px;color:#b2cbbd}.waiting b{color:#b9cbbf;font-weight:400}.evidence [hidden]{display:none!important}.error{position:absolute;inset:0;z-index:4;display:grid;place-content:center;text-align:center;padding:25px;background:#172023;color:#b3c5ba}.error:empty{display:none}@media(max-width:380px){header{padding:0 11px}.evidence{height:112px;padding:10px 11px;gap:10px}.strip{gap:4px}.strip figure{width:48px}.capture{height:40px}.evidence b{font-size:10px}.evidence small{font-size:8px}}\n</style></head><body>\n<header><strong>Inspection camera</strong><span class=\"status\"><i></i><span id=\"status\">Running</span></span></header>\n<div class=\"viewport\" id=\"viewport\"><video id=\"video\" muted loop playsinline preload=\"auto\" aria-label=\"Cable moving through the inspection station\"></video><div class=\"hud\"><span>CAM 02 · SURFACE</span><span id=\"time\">14:32:00</span></div><div id=\"target\" class=\"target\" hidden></div><div class=\"foot\"><span id=\"location\">GUIDE 02 · RUN-024</span><span id=\"counter\"></span></div><div id=\"error\" class=\"error\"></div></div>\n<div class=\"evidence\" id=\"evidence\"><div id=\"waiting\" class=\"waiting\"><span>✓</span><div><b>Watching the cable surface</b><small>Camera frames and measurements stay together.</small></div></div><div id=\"strip\" class=\"strip\" hidden></div><div id=\"finding\" hidden><span class=\"tag\" id=\"finding-tag\">3 MARKS · 0.50 M APART</span><b id=\"finding-title\">Repeated surface marks</b><small id=\"finding-detail\">Frames kept with this run.</small></div></div>\n<script>\n(()=>{\n const el=id=>document.getElementById(id),video=el('video'),replay=window.__DASLAB_REPLAY__===true;\n let d=window.__DASLAB_WIDGET_DATA__||{},elapsed=Number(d.elapsed)||0,playing=false,speed=1,ready=false;\n const host=replay?location.origin:'https://daslab.run';\n const media=path=>new URL(path,host).href;\n const frame=media(d.captureSrc||'/replay/quality-control-v2/captured-frame.jpg');\n video.muted=true;video.src=media(d.videoSrc||'/replay/quality-control-v2/inspection.mp4');video.poster=frame;\n const metres=v=>Number(v).toLocaleString('en-US',{minimumFractionDigits:1,maximumFractionDigits:1})+' m';\n // The last three marks the camera kept, each a crop of the captured frame.\n function paintStrip(){\n  const marks=(Array.isArray(d.marks)?d.marks:[]).filter(Number.isFinite).slice(-3),strip=el('strip'),key=marks.join();\n  if(strip.dataset.key===key)return;strip.dataset.key=key;\n  strip.replaceChildren(...marks.map((mark,i)=>{const fig=document.createElement('figure'),box=document.createElement('div'),img=document.createElement('img'),cap=document.createElement('figcaption');box.className='capture';img.src=frame;img.alt='Surface mark at '+metres(mark);img.style.objectPosition=(46+i*4)+'% '+(48-i*3)+'%';cap.textContent=metres(mark);box.append(img);fig.append(box,cap);return fig}));\n  const spacing=Number(d.markSpacing)||0;\n  el('finding-tag').textContent=marks.length+' MARKS'+(spacing?' · '+spacing.toFixed(2)+' M APART':'');\n }\n function syncVideo(){\n  if(!ready)return;\n  if(!replay){if(!matchMedia('(prefers-reduced-motion: reduce)').matches)video.play().catch(()=>{});return}\n  const target=(elapsed+(Number(d.videoOffset)||0))%video.duration;\n  // Let the decoder play normally between timeline corrections. On pause or\n  // seek, land on the exact historical frame instead of running a second clock.\n  if(Math.abs(video.currentTime-target)>(playing?.2:.025))video.currentTime=target;\n  video.playbackRate=speed;\n  if(playing){if(video.paused)video.play().catch(()=>{})}else video.pause();\n }\n function positionTarget(){\n  const w=el('viewport').clientWidth,h=el('viewport').clientHeight,scale=Math.max(w/1280,h/720),vw=1280*scale,vh=720*scale;\n  const b=el('target');b.style.left=(w/2-vw/2+vw*.43)+'px';b.style.top=(h/2-vh/2+vh*.45)+'px';b.style.width=(vw*.16)+'px';b.style.height=(vh*.13)+'px';\n }\n function update(){\n  const detected=!!d.detected||!replay,held=!!d.hold;\n  el('waiting').hidden=detected;el('strip').hidden=el('finding').hidden=!detected;\n  el('target').hidden=!detected||held;\n  el('evidence').classList.toggle('held',held);\n  el('finding-title').textContent=held?'Reel '+(d.hold.reel||d.run||'RUN-024')+' held for inspection':d.operatorObservation?'Burr on guide 2':'Repeated surface marks';\n  el('finding-detail').textContent=held?'Guide 2 swap at the next reel change.':d.operatorObservation?'Found by Sam at the guide.':'Frames kept with this run.';\n  el('status').textContent=held?'Running · reel held':'Running';\n  el('time').textContent='14:32:'+String(Math.floor(elapsed)%60).padStart(2,'0');\n  // Metres through the camera: the last kept mark plus the line speed.\n  const start=Number(d.meterAtStart)||18413.6,lineSpeed=Number(d.speed)||400;\n  el('counter').textContent=metres(start+elapsed*lineSpeed/60);\n  el('location').textContent='GUIDE 02 · '+(d.run||'RUN-024');\n  document.body.dataset.phase=d.phase||'notice';document.body.dataset.elapsed=String(elapsed);\n  positionTarget();syncVideo();\n }\n addEventListener('message',e=>{\n  if(!replay||e.source!==parent||e.origin!==location.origin||e.data?.type!=='daslab:replay-clock')return;\n  if(e.data.data){d=e.data.data;paintStrip()}elapsed=Math.max(0,Number(e.data.elapsed)||0)/1000;playing=e.data.playing===true;speed=Number(e.data.speed)||1;update();\n });\n video.addEventListener('loadedmetadata',()=>{ready=Number.isFinite(video.duration)&&video.duration>0;update()});\n video.addEventListener('error',()=>el('error').textContent='The camera clip could not load. Reload to try again.');\n new ResizeObserver(positionTarget).observe(el('viewport'));paintStrip();update();\n})();\n</script></body></html>\n",
        "data": {
          "line": "Cable line 02",
          "run": "RUN-024",
          "camera": "Camera 02",
          "phase": "notice",
          "elapsed": 12,
          "sample": true,
          "diameterTarget": 2.4,
          "speed": 400,
          "marks": [
            18412.3,
            18412.8,
            18413.3
          ],
          "markSpacing": 0.5,
          "guide": {
            "id": "guide-02",
            "rollerDiameterMm": 160,
            "circumferenceM": 0.503
          },
          "samples": [
            {
              "t": -24,
              "diameter": 2.4,
              "speed": 399.6
            },
            {
              "t": -23,
              "diameter": 2.391,
              "speed": 400.4
            },
            {
              "t": -22,
              "diameter": 2.401,
              "speed": 401
            },
            {
              "t": -21,
              "diameter": 2.405,
              "speed": 401
            },
            {
              "t": -20,
              "diameter": 2.393,
              "speed": 400.3
            },
            {
              "t": -19,
              "diameter": 2.391,
              "speed": 399.5
            },
            {
              "t": -18,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": -17,
              "diameter": 2.403,
              "speed": 399.1
            },
            {
              "t": -16,
              "diameter": 2.393,
              "speed": 399.7
            },
            {
              "t": -15,
              "diameter": 2.398,
              "speed": 400.5
            },
            {
              "t": -14,
              "diameter": 2.41,
              "speed": 401.1
            },
            {
              "t": -13,
              "diameter": 2.404,
              "speed": 400.9
            },
            {
              "t": -12,
              "diameter": 2.395,
              "speed": 400.2
            },
            {
              "t": -11,
              "diameter": 2.404,
              "speed": 399.4
            },
            {
              "t": -10,
              "diameter": 2.41,
              "speed": 398.9
            },
            {
              "t": -9,
              "diameter": 2.398,
              "speed": 399.1
            },
            {
              "t": -8,
              "diameter": 2.393,
              "speed": 399.9
            },
            {
              "t": -7,
              "diameter": 2.404,
              "speed": 400.7
            },
            {
              "t": -6,
              "diameter": 2.404,
              "speed": 401.1
            },
            {
              "t": -5,
              "diameter": 2.391,
              "speed": 400.8
            },
            {
              "t": -4,
              "diameter": 2.393,
              "speed": 400.1
            },
            {
              "t": -3,
              "diameter": 2.405,
              "speed": 399.3
            },
            {
              "t": -2,
              "diameter": 2.4,
              "speed": 398.9
            },
            {
              "t": -1,
              "diameter": 2.391,
              "speed": 399.2
            },
            {
              "t": 0,
              "diameter": 2.4,
              "speed": 400
            },
            {
              "t": 1,
              "diameter": 2.409,
              "speed": 400.8
            },
            {
              "t": 2,
              "diameter": 2.4,
              "speed": 401.1
            },
            {
              "t": 3,
              "diameter": 2.395,
              "speed": 400.7
            },
            {
              "t": 4,
              "diameter": 2.407,
              "speed": 399.9
            },
            {
              "t": 5,
              "diameter": 2.409,
              "speed": 399.2
            },
            {
              "t": 6,
              "diameter": 2.396,
              "speed": 398.9
            },
            {
              "t": 7,
              "diameter": 2.396,
              "speed": 399.3
            },
            {
              "t": 8,
              "diameter": 2.407,
              "speed": 400.1
            },
            {
              "t": 9,
              "diameter": 2.402,
              "speed": 400.9
            },
            {
              "t": 10,
              "diameter": 2.39,
              "speed": 401.1
            },
            {
              "t": 11,
              "diameter": 2.396,
              "speed": 400.6
            },
            {
              "t": 12,
              "diameter": 2.405,
              "speed": 399.8
            },
            {
              "t": 13,
              "diameter": 2.396,
              "speed": 399.1
            },
            {
              "t": 14,
              "diameter": 2.39,
              "speed": 398.9
            },
            {
              "t": 15,
              "diameter": 2.402,
              "speed": 399.5
            },
            {
              "t": 16,
              "diameter": 2.407,
              "speed": 400.3
            },
            {
              "t": 17,
              "diameter": 2.397,
              "speed": 400.9
            },
            {
              "t": 18,
              "diameter": 2.397,
              "speed": 401.1
            },
            {
              "t": 19,
              "diameter": 2.409,
              "speed": 400.5
            },
            {
              "t": 20,
              "diameter": 2.407,
              "speed": 399.7
            },
            {
              "t": 21,
              "diameter": 2.395,
              "speed": 399
            },
            {
              "t": 22,
              "diameter": 2.399,
              "speed": 399
            },
            {
              "t": 23,
              "diameter": 2.409,
              "speed": 399.6
            },
            {
              "t": 24,
              "diameter": 2.4,
              "speed": 400.4
            },
            {
              "t": 25,
              "diameter": 2.39,
              "speed": 401
            },
            {
              "t": 26,
              "diameter": 2.399,
              "speed": 401
            },
            {
              "t": 27,
              "diameter": 2.405,
              "speed": 400.4
            },
            {
              "t": 28,
              "diameter": 2.393,
              "speed": 399.6
            },
            {
              "t": 29,
              "diameter": 2.391,
              "speed": 399
            },
            {
              "t": 30,
              "diameter": 2.404,
              "speed": 399
            },
            {
              "t": 31,
              "diameter": 2.405,
              "speed": 399.6
            },
            {
              "t": 32,
              "diameter": 2.394,
              "speed": 400.4
            },
            {
              "t": 33,
              "diameter": 2.398,
              "speed": 401
            },
            {
              "t": 34,
              "diameter": 2.41,
              "speed": 401
            },
            {
              "t": 35,
              "diameter": 2.404,
              "speed": 400.3
            },
            {
              "t": 36,
              "diameter": 2.395,
              "speed": 399.5
            },
            {
              "t": 37,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": 38,
              "diameter": 2.409,
              "speed": 399.1
            },
            {
              "t": 39,
              "diameter": 2.398,
              "speed": 399.7
            },
            {
              "t": 40,
              "diameter": 2.392,
              "speed": 400.6
            },
            {
              "t": 41,
              "diameter": 2.403,
              "speed": 401.1
            },
            {
              "t": 42,
              "diameter": 2.403,
              "speed": 400.9
            },
            {
              "t": 43,
              "diameter": 2.391,
              "speed": 400.2
            },
            {
              "t": 44,
              "diameter": 2.393,
              "speed": 399.4
            }
          ],
          "view": "camera",
          "videoSrc": "/replay/quality-control-v2/inspection.mp4",
          "captureSrc": "/replay/quality-control-v2/captured-frame.jpg",
          "videoOffset": 2.4
        }
      },
      "layout": {
        "sortOrder": 0,
        "size": "large"
      }
    },
    {
      "id": "signals",
      "type": "daslab/webview",
      "name": "Line measurements",
      "fields": {
        "html": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<style>\n*{box-sizing:border-box}html,body{margin:0;height:100%}body{font:11px/1.5 Inter,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;background:#fbfaf6;color:#43514a;overflow:auto;scrollbar-width:thin}header{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid #e7e8df}header strong{font-size:11px;font-weight:550}header small{font:8px ui-monospace,monospace;color:#8d9689}main{padding:10px 12px}.metrics{display:grid;grid-template-columns:1fr 1fr;gap:10px}.metric small{font-size:8px;color:#82907d;display:block;margin-bottom:2px}.metric strong{font-size:22px;line-height:1.1;font-weight:450;letter-spacing:-.5px}.metric em{font-style:normal;font-size:8px;margin-left:4px;color:#8d9785}.chart{height:71px;position:relative;margin-top:5px}.chart canvas{width:100%;height:100%;display:block}.chart-label{display:flex;justify-content:space-between;font:7px ui-monospace,monospace;color:#8d9687}.finding{margin-top:10px;border-top:1px solid #e5e7dd;padding-top:9px;display:flex;gap:8px;align-items:flex-start}.dot{width:6px;height:6px;flex-shrink:0;border-radius:50%;margin-top:5px;background:#91a488}.finding b{font-size:10px;font-weight:550;display:block}.finding p{font-size:9px;line-height:1.5;margin:3px 0 0;color:#8a907f}.finding.warn .dot{background:#c89351}.finding.warn b{color:#966c37}.finding.kept .dot{background:#7b9a8c}.finding.kept b{color:#547563}.receipt{font:8px ui-monospace,monospace;color:#8b9687;margin-top:5px}.entry{margin-top:12px;border-top:1px solid #e5e7dd;padding-top:10px}.entry label{font-size:9px;display:block;margin-bottom:5px;color:#7c8d7a}.entry textarea{width:100%;min-height:66px;padding:8px;border:1px solid #d9dfd2;border-radius:5px;font:11px/1.5 inherit;color:#445747;background:#fffefa;resize:vertical}.entry small{display:block;font-size:8px;color:#8b9687;margin-top:4px}.entry[hidden]{display:none}textarea:focus-visible{outline:2px solid #315fc5;outline-offset:2px}@media(max-height:240px){main{padding:8px 12px}.metric strong{font-size:20px}.chart{height:50px;margin-top:2px}.finding{margin-top:7px;padding-top:7px}.finding p{font-size:8px}.chart-label{font-size:6px}.receipt{font-size:7px}}\n</style></head><body>\n<header><strong>Line measurements</strong><small id=\"run\">RUN-024</small></header>\n<main><div class=\"metrics\"><div class=\"metric\"><small>Diameter</small><strong id=\"diameter\">2.40</strong><em>mm</em></div><div class=\"metric\"><small>Line speed</small><strong id=\"speed\">400</strong><em>m/min</em></div></div><div class=\"chart\"><canvas id=\"chart\" aria-label=\"Diameter history\"></canvas></div><div class=\"chart-label\"><span>DIAMETER · LAST 24 SEC</span><span id=\"range\">± 0.04 mm</span></div><div class=\"finding\" id=\"finding\"><i class=\"dot\"></i><div><b id=\"state\">Within range</b><p id=\"detail\">Watching for a change in the surface.</p><div class=\"receipt\" id=\"receipt\"></div></div></div><div class=\"entry\" id=\"entry\" hidden><label for=\"note\">Your inspection note</label><textarea id=\"note\" placeholder=\"What did you find? What should happen next?\"></textarea><small id=\"saved\">Saved with this run as you type.</small></div></main>\n<script>\n(function(){\n var d=window.__DASLAB_WIDGET_DATA__||{},replay=window.__DASLAB_REPLAY__===true,t=Number(d.elapsed)||0,el=id=>document.getElementById(id),canvas=el('chart'),pending=false;\n el('run').textContent=d.run||'RUN-024';\n function paint(){\n  pending=false;var sample=(d.samples||[]).filter(s=>s.t<=t).at(-1)||{diameter:2.4,speed:d.speed||400};\n  el('diameter').textContent=Number(sample.diameter).toFixed(2);el('speed').textContent=Math.round(Number(sample.speed));\n  var reel=d.run||'RUN-024',spacing=Number(d.markSpacing)?Number(d.markSpacing).toFixed(2)+' m':'',record=d.inspection,held=!!d.hold,observed=!!d.operatorObservation,detected=!!d.detected;\n  el('finding').className='finding '+(held?'kept':detected?'warn':'');\n  el('state').textContent=held?'Reel '+reel+' held for inspection':d.holdProposed?'Hold proposed':observed?'Burr on guide 2':d.askedOperator?'Waiting for Sam at guide 2':detected?'Repeated surface marks':'Within range';\n  el('detail').textContent=held?'Burr on guide 2 found by Sam. Guide swap at the next reel change.':d.holdProposed?'Reel '+reel+' waits for approval.':observed?'Found by Sam. Guide swap at the next reel change.':d.askedOperator?'Mark spacing matches one turn of guide 2.':detected?'Marks every '+(spacing||'0.50 m')+'. Diameter and speed steady.':'Watching the surface as the run continues.';\n  el('receipt').textContent=record?(record.id||'QC-018')+' · '+(record.approvedBy?'APPROVED BY '+String(record.approvedBy).toUpperCase():'ON RECORD'):'';\n  var box=canvas.getBoundingClientRect(),w=box.width,h=box.height,ratio=Math.min(devicePixelRatio,2);canvas.width=w*ratio;canvas.height=h*ratio;\n  var c=canvas.getContext('2d');c.scale(ratio,ratio);var left=t-24,xx=v=>(v-left)/24*w,yy=v=>h/2-(v-2.4)/.1*h;\n  c.fillStyle='#edf1e8';c.fillRect(0,yy(2.44),w,yy(2.36)-yy(2.44));\n  c.strokeStyle='#dce3d3';c.lineWidth=.7;for(var v of[2.36,2.4,2.44]){c.beginPath();c.moveTo(0,yy(v));c.lineTo(w,yy(v));c.stroke()}\n  c.strokeStyle='#76948b';c.lineWidth=1.7;c.lineJoin='round';c.beginPath();var points=(d.samples||[]).filter(s=>s.t>=left&&s.t<=t);points.forEach((s,i)=>i?c.lineTo(xx(s.t),yy(s.diameter)):c.moveTo(xx(s.t),yy(s.diameter)));c.stroke();\n  if(points.length){var last=points.at(-1);c.fillStyle='#537d70';c.beginPath();c.arc(xx(last.t),yy(last.diameter),2.5,0,Math.PI*2);c.fill()}\n  document.body.dataset.elapsed=String(t);document.body.dataset.phase=d.phase||'notice';\n }\n function update(){if(pending)return;pending=true;requestAnimationFrame(paint)}\n addEventListener('message',e=>{if(!replay||e.source!==parent||e.origin!==location.origin||e.data?.type!=='daslab:replay-clock')return;if(e.data.data)d=e.data.data;t=Math.max(0,Number(e.data.elapsed)||0)/1000;update()});\n new ResizeObserver(update).observe(canvas.parentElement);\n if(!replay){d.detected=true;el('entry').hidden=false;var key='asset:inspection:'+(d.run||'RUN-024')+':note';try{el('note').value=localStorage.getItem(key)||''}catch(e){}el('note').oninput=()=>{try{localStorage.setItem(key,el('note').value);el('saved').textContent='Saved with this run.'}catch(e){el('saved').textContent='Could not save. Keep a copy of your note.'}}}\n update();\n})();\n</script></body></html>\n",
        "data": {
          "line": "Cable line 02",
          "run": "RUN-024",
          "camera": "Camera 02",
          "phase": "notice",
          "elapsed": 12,
          "sample": true,
          "diameterTarget": 2.4,
          "speed": 400,
          "marks": [
            18412.3,
            18412.8,
            18413.3
          ],
          "markSpacing": 0.5,
          "guide": {
            "id": "guide-02",
            "rollerDiameterMm": 160,
            "circumferenceM": 0.503
          },
          "samples": [
            {
              "t": -24,
              "diameter": 2.4,
              "speed": 399.6
            },
            {
              "t": -23,
              "diameter": 2.391,
              "speed": 400.4
            },
            {
              "t": -22,
              "diameter": 2.401,
              "speed": 401
            },
            {
              "t": -21,
              "diameter": 2.405,
              "speed": 401
            },
            {
              "t": -20,
              "diameter": 2.393,
              "speed": 400.3
            },
            {
              "t": -19,
              "diameter": 2.391,
              "speed": 399.5
            },
            {
              "t": -18,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": -17,
              "diameter": 2.403,
              "speed": 399.1
            },
            {
              "t": -16,
              "diameter": 2.393,
              "speed": 399.7
            },
            {
              "t": -15,
              "diameter": 2.398,
              "speed": 400.5
            },
            {
              "t": -14,
              "diameter": 2.41,
              "speed": 401.1
            },
            {
              "t": -13,
              "diameter": 2.404,
              "speed": 400.9
            },
            {
              "t": -12,
              "diameter": 2.395,
              "speed": 400.2
            },
            {
              "t": -11,
              "diameter": 2.404,
              "speed": 399.4
            },
            {
              "t": -10,
              "diameter": 2.41,
              "speed": 398.9
            },
            {
              "t": -9,
              "diameter": 2.398,
              "speed": 399.1
            },
            {
              "t": -8,
              "diameter": 2.393,
              "speed": 399.9
            },
            {
              "t": -7,
              "diameter": 2.404,
              "speed": 400.7
            },
            {
              "t": -6,
              "diameter": 2.404,
              "speed": 401.1
            },
            {
              "t": -5,
              "diameter": 2.391,
              "speed": 400.8
            },
            {
              "t": -4,
              "diameter": 2.393,
              "speed": 400.1
            },
            {
              "t": -3,
              "diameter": 2.405,
              "speed": 399.3
            },
            {
              "t": -2,
              "diameter": 2.4,
              "speed": 398.9
            },
            {
              "t": -1,
              "diameter": 2.391,
              "speed": 399.2
            },
            {
              "t": 0,
              "diameter": 2.4,
              "speed": 400
            },
            {
              "t": 1,
              "diameter": 2.409,
              "speed": 400.8
            },
            {
              "t": 2,
              "diameter": 2.4,
              "speed": 401.1
            },
            {
              "t": 3,
              "diameter": 2.395,
              "speed": 400.7
            },
            {
              "t": 4,
              "diameter": 2.407,
              "speed": 399.9
            },
            {
              "t": 5,
              "diameter": 2.409,
              "speed": 399.2
            },
            {
              "t": 6,
              "diameter": 2.396,
              "speed": 398.9
            },
            {
              "t": 7,
              "diameter": 2.396,
              "speed": 399.3
            },
            {
              "t": 8,
              "diameter": 2.407,
              "speed": 400.1
            },
            {
              "t": 9,
              "diameter": 2.402,
              "speed": 400.9
            },
            {
              "t": 10,
              "diameter": 2.39,
              "speed": 401.1
            },
            {
              "t": 11,
              "diameter": 2.396,
              "speed": 400.6
            },
            {
              "t": 12,
              "diameter": 2.405,
              "speed": 399.8
            },
            {
              "t": 13,
              "diameter": 2.396,
              "speed": 399.1
            },
            {
              "t": 14,
              "diameter": 2.39,
              "speed": 398.9
            },
            {
              "t": 15,
              "diameter": 2.402,
              "speed": 399.5
            },
            {
              "t": 16,
              "diameter": 2.407,
              "speed": 400.3
            },
            {
              "t": 17,
              "diameter": 2.397,
              "speed": 400.9
            },
            {
              "t": 18,
              "diameter": 2.397,
              "speed": 401.1
            },
            {
              "t": 19,
              "diameter": 2.409,
              "speed": 400.5
            },
            {
              "t": 20,
              "diameter": 2.407,
              "speed": 399.7
            },
            {
              "t": 21,
              "diameter": 2.395,
              "speed": 399
            },
            {
              "t": 22,
              "diameter": 2.399,
              "speed": 399
            },
            {
              "t": 23,
              "diameter": 2.409,
              "speed": 399.6
            },
            {
              "t": 24,
              "diameter": 2.4,
              "speed": 400.4
            },
            {
              "t": 25,
              "diameter": 2.39,
              "speed": 401
            },
            {
              "t": 26,
              "diameter": 2.399,
              "speed": 401
            },
            {
              "t": 27,
              "diameter": 2.405,
              "speed": 400.4
            },
            {
              "t": 28,
              "diameter": 2.393,
              "speed": 399.6
            },
            {
              "t": 29,
              "diameter": 2.391,
              "speed": 399
            },
            {
              "t": 30,
              "diameter": 2.404,
              "speed": 399
            },
            {
              "t": 31,
              "diameter": 2.405,
              "speed": 399.6
            },
            {
              "t": 32,
              "diameter": 2.394,
              "speed": 400.4
            },
            {
              "t": 33,
              "diameter": 2.398,
              "speed": 401
            },
            {
              "t": 34,
              "diameter": 2.41,
              "speed": 401
            },
            {
              "t": 35,
              "diameter": 2.404,
              "speed": 400.3
            },
            {
              "t": 36,
              "diameter": 2.395,
              "speed": 399.5
            },
            {
              "t": 37,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": 38,
              "diameter": 2.409,
              "speed": 399.1
            },
            {
              "t": 39,
              "diameter": 2.398,
              "speed": 399.7
            },
            {
              "t": 40,
              "diameter": 2.392,
              "speed": 400.6
            },
            {
              "t": 41,
              "diameter": 2.403,
              "speed": 401.1
            },
            {
              "t": 42,
              "diameter": 2.403,
              "speed": 400.9
            },
            {
              "t": 43,
              "diameter": 2.391,
              "speed": 400.2
            },
            {
              "t": 44,
              "diameter": 2.393,
              "speed": 399.4
            }
          ],
          "view": "signals"
        }
      },
      "layout": {
        "sortOrder": 1,
        "size": "large"
      }
    },
    {
      "id": "machine",
      "type": "daslab/webview",
      "name": "Station layout",
      "fields": {
        "html": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\n*{box-sizing:border-box}html,body{height:100%;margin:0;overflow:hidden}body{display:flex;flex-direction:column;background:#eff0eb;color:#46534e;font:11px/1.5 Inter,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif}header{height:38px;flex-shrink:0;padding:0 12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #dce1d7}header strong{font-weight:550;font-size:11px}.status{color:#829382;font-size:8px}.status:before{content:'';display:inline-block;height:5px;width:5px;background:#9bbaa0;border-radius:50%;margin-right:5px}.viewport{position:relative;flex:1;min-height:0;cursor:grab}.viewport:active{cursor:grabbing}canvas{display:block;width:100%;height:100%;touch-action:none}.label,.hint{position:absolute;left:11px;font:8px ui-monospace,monospace;color:#7c8b7f;pointer-events:none}.label{top:9px}.hint{bottom:9px;right:11px;display:flex;justify-content:space-between;gap:8px}.error{position:absolute;inset:0;padding:20px;display:grid;place-content:center;text-align:center;color:#7c8b7f}.error:empty{display:none}\n</style></head><body><header><strong>Station layout</strong><span class=\"status\" id=\"status\">3 cameras</span></header><div id=\"viewport\" class=\"viewport\"><span class=\"label\">INLINE SURFACE INSPECTION</span><div class=\"hint\"><span id=\"finding\">ENCLOSED VISION HEAD</span><span>Drag to orbit</span></div><div id=\"error\" class=\"error\"></div></div>\n<script>\n(()=>{\n let d=window.__DASLAB_WIDGET_DATA__||{},replay=window.__DASLAB_REPLAY__===true,t=Number(d.elapsed)||0,draw=null,pending=false;\n const el=id=>document.getElementById(id);\n function update(){if(pending||!draw)return;pending=true;requestAnimationFrame(()=>{pending=false;draw()})}\n addEventListener('message',e=>{if(!replay||e.source!==parent||e.origin!==location.origin||e.data?.type!=='daslab:replay-clock')return;if(e.data.data)d=e.data.data;t=Math.max(0,Number(e.data.elapsed)||0)/1000;update()});\n init().catch(()=>el('error').textContent='The station layout could not load. Reload to try again.');\n async function init(){\n  const THREE=await import((replay?location.origin:'https://daslab.run')+'/replay/quality-control/three.module.js');\n  const mount=el('viewport'),renderer=new THREE.WebGLRenderer({antialias:true,preserveDrawingBuffer:true});renderer.setPixelRatio(Math.min(devicePixelRatio,1.7));renderer.shadowMap.enabled=true;renderer.shadowMap.type=THREE.PCFSoftShadowMap;renderer.toneMapping=THREE.ACESFilmicToneMapping;renderer.toneMappingExposure=1.3;mount.prepend(renderer.domElement);\n  const scene=new THREE.Scene();scene.background=new THREE.Color(0xeff0eb);scene.add(new THREE.HemisphereLight(0xffffff,0x848f7d,2.3));\n  const key=new THREE.DirectionalLight(0xfff4e5,3.2);key.position.set(2,5,4);key.castShadow=true;key.shadow.mapSize.set(1024,1024);key.shadow.camera.left=-2;key.shadow.camera.right=2;key.shadow.camera.top=2;key.shadow.camera.bottom=-2;key.shadow.bias=-.0005;scene.add(key);\n  const fill=new THREE.DirectionalLight(0xd2e7f1,1.6);fill.position.set(-3,3,-2);scene.add(fill);\n  const mat=(color,metalness=.2,roughness=.6)=>new THREE.MeshStandardMaterial({color,metalness,roughness});\n  const paint=mat(0x456e87),silver=mat(0xc0c9c7,.72,.3),base=mat(0x748c98),dark=mat(0x202c2e,.12,.63),roller=mat(0xccaa62,.28,.42),screen=mat(0x293e47,.2,.35),steel=mat(0xa8b6b8,.7,.25);\n  function add(geometry,material,x,y,z){const m=new THREE.Mesh(geometry,material);m.position.set(x,y,z);m.castShadow=m.receiveShadow=true;scene.add(m);return m}\n  const box=(w,h,l,x,y,z,m)=>add(new THREE.BoxGeometry(w,h,l),m,x,y,z);\n  function cyl(r,l,x,y,z,m,axis='y'){const v=add(new THREE.CylinderGeometry(r,r,l,32),m,x,y,z);if(axis==='x')v.rotation.z=Math.PI/2;if(axis==='z')v.rotation.x=Math.PI/2;return v}\n  // Representative inline inspection head: an enclosed optical chamber and\n  // through-bore on a pedestal, with guides and an operator terminal. Geometry\n  // informed by manufacturer photos; it is not an exact factory digital twin.\n  function housing(depth,material,x){const s=new THREE.Shape();s.moveTo(-.29,-.24);s.lineTo(.29,-.24);s.lineTo(.29,.24);s.lineTo(-.29,.24);s.closePath();const hole=new THREE.Path();hole.absarc(0,0,.055,0,Math.PI*2,true);s.holes.push(hole);const g=new THREE.ExtrudeGeometry(s,{depth,bevelEnabled:true,bevelSize:.004,bevelThickness:.003,bevelSegments:2,steps:1});g.rotateY(Math.PI/2);return add(g,material,x,1.02,0)}\n  housing(.29,paint,-.145);housing(.012,silver,.15);housing(.012,silver,-.168);\n  // Dark optical collar around the cable bore; no camera lenses floating above it.\n  for(const x of[-.179,.178]){const ring=new THREE.Mesh(new THREE.TorusGeometry(.068,.014,10,40),dark);ring.rotation.y=Math.PI/2;ring.position.set(x,1.02,0);scene.add(ring)}\n  box(.25,.05,.49,0,.75,0,base);box(.095,.51,.1,0,.47,0,steel);box(.34,.2,.32,0,.13,0,base);box(.46,.025,.47,0,.022,0,base);\n  for(const x of[-.18,.18])for(const z of[-.19,.19])cyl(.027,.018,x,.016,z,dark);\n  for(const y of[.81,1.23])for(const z of[-.24,.24])cyl(.01,.01,.168,y,z,dark,'x');\n  // One cable on a guided path, not a conveyor of exposed copper.\n  cyl(.011,2.9,0,1.02,0,dark,'x');\n  for(const x of[-.73,.63]){\n   box(.13,.04,.2,x,.89,0,steel);box(.055,.67,.06,x,.535,0,steel);box(.24,.035,.3,x,.18,0,base);cyl(.057,.095,x,.954,0,roller,'z');\n   for(const z of[-.059,.059])cyl(.066,.012,x,.954,z,dark,'z');\n   for(const z of[-.082,.082])box(.03,.13,.023,x,.938,z,steel);\n  }\n  const highlight=box(.17,.17,.23,.63,.972,0,new THREE.MeshBasicMaterial({color:0xd99e43,transparent:true,opacity:.15,depthWrite:false}));\n  const edges=new THREE.LineSegments(new THREE.EdgesGeometry(highlight.geometry),new THREE.LineBasicMaterial({color:0xba8435}));edges.position.copy(highlight.position);scene.add(edges);\n  box(.075,1.08,.075,-.29,.55,-.53,base);box(.38,.03,.3,-.29,.025,-.53,base);box(.37,.26,.055,-.29,1.25,-.53,dark);box(.32,.20,.006,-.29,1.26,-.497,screen);\n  for(let i=0;i<3;i++)box(.20-i*.035,.007,.008,-.31,1.29-i*.038,-.49,mat(i===0?0xa5c8b0:0x67858b));\n  cyl(.017,.025,-.13,1.44,-.53,mat(0x8ea97c));box(.026,.09,.026,-.13,1.385,-.53,dark);\n  const floor=new THREE.Mesh(new THREE.PlaneGeometry(20,20),mat(0xe6e9e1,0,.95));floor.rotation.x=-Math.PI/2;floor.position.y=-.004;floor.receiveShadow=true;scene.add(floor);\n  const camera=new THREE.PerspectiveCamera(33,1,.01,30);let angle=.9,tilt=.53,drag=null;\n  draw=()=>{const active=!!d.inspectionStation||!replay;highlight.visible=edges.visible=active;camera.position.set(Math.sin(angle)*3.6,.75+tilt*2.3,Math.cos(angle)*3.6);camera.lookAt(0,.77,0);renderer.render(scene,camera);el('status').textContent=active?'Guide 02':'3 cameras';el('finding').textContent=d.hold?'GUIDE 02 · SWAP AT REEL CHANGE':d.operatorObservation?'BURR ON GUIDE 02':active?'CHECK GUIDE 02':'ENCLOSED VISION HEAD';document.body.dataset.phase=d.phase||'notice';document.body.dataset.elapsed=String(t)};\n  function resize(){const w=mount.clientWidth,h=mount.clientHeight;if(!w||!h)return;renderer.setSize(w,h,false);camera.aspect=w/h;camera.updateProjectionMatrix();update()}\n  renderer.domElement.addEventListener('pointerdown',e=>{drag={x:e.clientX,y:e.clientY,a:angle,t:tilt};renderer.domElement.setPointerCapture(e.pointerId)});\n  renderer.domElement.addEventListener('pointermove',e=>{if(!drag)return;angle=drag.a+(e.clientX-drag.x)*.008;tilt=Math.max(.12,Math.min(1.2,drag.t+(e.clientY-drag.y)*.004));update()});\n  renderer.domElement.addEventListener('pointerup',()=>drag=null);renderer.domElement.addEventListener('pointercancel',()=>drag=null);\n  new ResizeObserver(resize).observe(mount);resize();update();\n }\n})();\n</script></body></html>\n",
        "data": {
          "line": "Cable line 02",
          "run": "RUN-024",
          "camera": "Camera 02",
          "phase": "notice",
          "elapsed": 12,
          "sample": true,
          "diameterTarget": 2.4,
          "speed": 400,
          "marks": [
            18412.3,
            18412.8,
            18413.3
          ],
          "markSpacing": 0.5,
          "guide": {
            "id": "guide-02",
            "rollerDiameterMm": 160,
            "circumferenceM": 0.503
          },
          "samples": [
            {
              "t": -24,
              "diameter": 2.4,
              "speed": 399.6
            },
            {
              "t": -23,
              "diameter": 2.391,
              "speed": 400.4
            },
            {
              "t": -22,
              "diameter": 2.401,
              "speed": 401
            },
            {
              "t": -21,
              "diameter": 2.405,
              "speed": 401
            },
            {
              "t": -20,
              "diameter": 2.393,
              "speed": 400.3
            },
            {
              "t": -19,
              "diameter": 2.391,
              "speed": 399.5
            },
            {
              "t": -18,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": -17,
              "diameter": 2.403,
              "speed": 399.1
            },
            {
              "t": -16,
              "diameter": 2.393,
              "speed": 399.7
            },
            {
              "t": -15,
              "diameter": 2.398,
              "speed": 400.5
            },
            {
              "t": -14,
              "diameter": 2.41,
              "speed": 401.1
            },
            {
              "t": -13,
              "diameter": 2.404,
              "speed": 400.9
            },
            {
              "t": -12,
              "diameter": 2.395,
              "speed": 400.2
            },
            {
              "t": -11,
              "diameter": 2.404,
              "speed": 399.4
            },
            {
              "t": -10,
              "diameter": 2.41,
              "speed": 398.9
            },
            {
              "t": -9,
              "diameter": 2.398,
              "speed": 399.1
            },
            {
              "t": -8,
              "diameter": 2.393,
              "speed": 399.9
            },
            {
              "t": -7,
              "diameter": 2.404,
              "speed": 400.7
            },
            {
              "t": -6,
              "diameter": 2.404,
              "speed": 401.1
            },
            {
              "t": -5,
              "diameter": 2.391,
              "speed": 400.8
            },
            {
              "t": -4,
              "diameter": 2.393,
              "speed": 400.1
            },
            {
              "t": -3,
              "diameter": 2.405,
              "speed": 399.3
            },
            {
              "t": -2,
              "diameter": 2.4,
              "speed": 398.9
            },
            {
              "t": -1,
              "diameter": 2.391,
              "speed": 399.2
            },
            {
              "t": 0,
              "diameter": 2.4,
              "speed": 400
            },
            {
              "t": 1,
              "diameter": 2.409,
              "speed": 400.8
            },
            {
              "t": 2,
              "diameter": 2.4,
              "speed": 401.1
            },
            {
              "t": 3,
              "diameter": 2.395,
              "speed": 400.7
            },
            {
              "t": 4,
              "diameter": 2.407,
              "speed": 399.9
            },
            {
              "t": 5,
              "diameter": 2.409,
              "speed": 399.2
            },
            {
              "t": 6,
              "diameter": 2.396,
              "speed": 398.9
            },
            {
              "t": 7,
              "diameter": 2.396,
              "speed": 399.3
            },
            {
              "t": 8,
              "diameter": 2.407,
              "speed": 400.1
            },
            {
              "t": 9,
              "diameter": 2.402,
              "speed": 400.9
            },
            {
              "t": 10,
              "diameter": 2.39,
              "speed": 401.1
            },
            {
              "t": 11,
              "diameter": 2.396,
              "speed": 400.6
            },
            {
              "t": 12,
              "diameter": 2.405,
              "speed": 399.8
            },
            {
              "t": 13,
              "diameter": 2.396,
              "speed": 399.1
            },
            {
              "t": 14,
              "diameter": 2.39,
              "speed": 398.9
            },
            {
              "t": 15,
              "diameter": 2.402,
              "speed": 399.5
            },
            {
              "t": 16,
              "diameter": 2.407,
              "speed": 400.3
            },
            {
              "t": 17,
              "diameter": 2.397,
              "speed": 400.9
            },
            {
              "t": 18,
              "diameter": 2.397,
              "speed": 401.1
            },
            {
              "t": 19,
              "diameter": 2.409,
              "speed": 400.5
            },
            {
              "t": 20,
              "diameter": 2.407,
              "speed": 399.7
            },
            {
              "t": 21,
              "diameter": 2.395,
              "speed": 399
            },
            {
              "t": 22,
              "diameter": 2.399,
              "speed": 399
            },
            {
              "t": 23,
              "diameter": 2.409,
              "speed": 399.6
            },
            {
              "t": 24,
              "diameter": 2.4,
              "speed": 400.4
            },
            {
              "t": 25,
              "diameter": 2.39,
              "speed": 401
            },
            {
              "t": 26,
              "diameter": 2.399,
              "speed": 401
            },
            {
              "t": 27,
              "diameter": 2.405,
              "speed": 400.4
            },
            {
              "t": 28,
              "diameter": 2.393,
              "speed": 399.6
            },
            {
              "t": 29,
              "diameter": 2.391,
              "speed": 399
            },
            {
              "t": 30,
              "diameter": 2.404,
              "speed": 399
            },
            {
              "t": 31,
              "diameter": 2.405,
              "speed": 399.6
            },
            {
              "t": 32,
              "diameter": 2.394,
              "speed": 400.4
            },
            {
              "t": 33,
              "diameter": 2.398,
              "speed": 401
            },
            {
              "t": 34,
              "diameter": 2.41,
              "speed": 401
            },
            {
              "t": 35,
              "diameter": 2.404,
              "speed": 400.3
            },
            {
              "t": 36,
              "diameter": 2.395,
              "speed": 399.5
            },
            {
              "t": 37,
              "diameter": 2.403,
              "speed": 398.9
            },
            {
              "t": 38,
              "diameter": 2.409,
              "speed": 399.1
            },
            {
              "t": 39,
              "diameter": 2.398,
              "speed": 399.7
            },
            {
              "t": 40,
              "diameter": 2.392,
              "speed": 400.6
            },
            {
              "t": 41,
              "diameter": 2.403,
              "speed": 401.1
            },
            {
              "t": 42,
              "diameter": 2.403,
              "speed": 400.9
            },
            {
              "t": 43,
              "diameter": 2.391,
              "speed": 400.2
            },
            {
              "t": 44,
              "diameter": 2.393,
              "speed": 399.4
            }
          ],
          "view": "machine"
        }
      },
      "layout": {
        "sortOrder": 2,
        "size": "large"
      }
    },
    {
      "id": "guide",
      "type": "daslab/note",
      "name": "Make this inspection yours",
      "fields": {
        "content": "# Make this inspection yours\n\nThree cells bring the same run together: **Inspection camera**, **Line measurements**, and **Machine view**. The starting scene uses sample imagery and sample measurements: a rendered station in the original version, or a generated cable-line video in V2. No camera, sensor or machine account is connected.\n\nLook at the captured surface mark, compare it with the measurements, and add your own observation in **Line measurements**. Your inspection note is saved with the cell. Ask Daslab to help you investigate, or invite an operator into a job with their @username.\n\nThe sample’s diameter and speed remain within their usual range. A surface mark is a reason to inspect the guide; it does not establish the cause on its own. Keep that distinction in your finding.\n\nTo use your equipment, bring a camera and its measurements into the scene. Ask Daslab to adapt these views around your sources, thresholds and station layout. Start with observation and a team handoff. Add an equipment action only after its connection, permissions and review step are configured.\n\nKeep the same scene across runs. Preserve captured evidence and operator observations so the next person can see what was checked and what remains open.\n"
      },
      "layout": {
        "sortOrder": 3,
        "size": "medium"
      }
    }
  ],
  "meta": {
    "author": "Daslab",
    "license": "MIT"
  }
}
