/* Adapter that gives the older sample pages the same step UI as the pick-and-place pages. * All the drawing and the measurements live in steps-ui.js — this file only reads each * page's own JSON blocks, supplies the task description, and hands StepsUI its containers. */ (function () { const J = id => { const e = document.getElementById(id); return e ? JSON.parse(e.textContent) : null; }; const S = J('series'), STEPS = J('spans') || [], META = J('meta'); if (!S || !STEPS.length || !window.StepsUI) return; const slug = (META && META.slug) || (location.pathname.match(/\/(ep\d+)\//) || [])[1] || ''; const family = slug.replace(/_?ep\d+$/, '') || 'legacy'; // object / target / scene, written from each recording's own description const TASK = { mem: { object: 'DDR memory module', target: 'motherboard slot', scene: 'workbench with an open motherboard, dual-arm grippers' }, drink: { object: 'bottled green beverage', target: 'coaster on the countertop', scene: 'countertop with the drink and a coaster set apart' }, sort: { object: 'packed garment bags (pink / white / beige / green)', target: 'left side of the table', scene: 'table with a material bin of packed garment bags' }, wipe: { object: 'sponge', target: 'stains on the tabletop', scene: 'tabletop with stains' }, legacy: { object: 'water bottle', target: 'basket', scene: 'tabletop with a water bottle and a basket' }, }[family] || {}; const sceneLine = (document.querySelector('.hilevel') || {}).textContent || ''; const task = { instruction: (META && META.high_level_instruction) || (document.querySelector('header h1') || {}).textContent || '', object: TASK.object, target: TASK.target, scene: sceneLine.replace(/^\s*scene\s*/i, '').trim() || TASK.scene || '', }; const header = document.querySelector('header'); const controls = document.querySelector('.panel.controls'); const videos = [...document.querySelectorAll('video')]; const ui = window.StepsUI.mount({ series: S, steps: STEPS, task, numbering: 'id', listItems: document.querySelectorAll('.span-item'), seek: t => videos.forEach(v => { try { v.currentTime = t; } catch (e) {} }), hosts: { instrAfter: header, timelineBefore: controls, panelAfter: controls }, describe: st => { // the recorded instruction for that segment const segs = META && META.instruction_segments; if (!segs) return null; const m = segs.find(x => Math.abs(x.start_frame_index / S.fps - st.start_s) < 0.2); return m ? m.instruction : null; }, }); if (!ui) return; // the chip row is redundant now that the timeline carries the colour key const chips = document.getElementById('chips') || document.querySelector('.chips'); if (chips) chips.remove(); // wording: spans / subtask -> steps document.querySelectorAll('.spans-head').forEach(e => { e.textContent = e.textContent.replace(/temporal spans/i, 'annotated steps').replace(/spans/gi, 'steps'); }); document.querySelectorAll('.ro .k, .rgrid .k').forEach(e => { const t = e.textContent.trim().toLowerCase(); if (t === 'subtask') e.textContent = 'step'; if (t === 'span progress') e.textContent = 'step progress'; }); const master = videos[0]; (function tick() { if (master) ui.update(master.currentTime); requestAnimationFrame(tick); })(); })();