| 
							 | 
						<!DOCTYPE html> | 
					
					
						
						| 
							 | 
						<html lang="en"> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						<head> | 
					
					
						
						| 
							 | 
						    <meta charset="UTF-8"> | 
					
					
						
						| 
							 | 
						    <meta name="viewport" content="width=device-width, initial-scale=1.0"> | 
					
					
						
						| 
							 | 
						    <title>Motion Capture Visualization</title> | 
					
					
						
						| 
							 | 
						    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> | 
					
					
						
						| 
							 | 
						    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script> | 
					
					
						
						| 
							 | 
						    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet"> | 
					
					
						
						| 
							 | 
						    <style> | 
					
					
						
						| 
							 | 
						        body { | 
					
					
						
						| 
							 | 
						            font-family: 'Orbitron', sans-serif; | 
					
					
						
						| 
							 | 
						            margin: 0; | 
					
					
						
						| 
							 | 
						            padding: 20px; | 
					
					
						
						| 
							 | 
						            display: flex; | 
					
					
						
						| 
							 | 
						            flex-direction: column; | 
					
					
						
						| 
							 | 
						            align-items: center; | 
					
					
						
						| 
							 | 
						            background-color: #000; | 
					
					
						
						| 
							 | 
						            color: #fff; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        h1 { | 
					
					
						
						| 
							 | 
						            color: gold; | 
					
					
						
						| 
							 | 
						            text-shadow: 2px 2px 4px rgba(255, 215, 0, 0.5); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .main-container { | 
					
					
						
						| 
							 | 
						            display: flex; | 
					
					
						
						| 
							 | 
						            width: 100%; | 
					
					
						
						| 
							 | 
						            max-width: 1500px; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .episode-list { | 
					
					
						
						| 
							 | 
						            width: 150px; | 
					
					
						
						| 
							 | 
						            margin-right: 0px; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .episode-list label { | 
					
					
						
						| 
							 | 
						            display: block; | 
					
					
						
						| 
							 | 
						            margin-bottom: 10px; | 
					
					
						
						| 
							 | 
						            color: #ddd; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .content-container { | 
					
					
						
						| 
							 | 
						            display: flex; | 
					
					
						
						| 
							 | 
						            justify-content: space-between; | 
					
					
						
						| 
							 | 
						            flex-grow: 1; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .video-container { | 
					
					
						
						| 
							 | 
						            width: 48%; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        #plotDiv { | 
					
					
						
						| 
							 | 
						            width: 440px; | 
					
					
						
						| 
							 | 
						            height: 600px; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        video { | 
					
					
						
						| 
							 | 
						            width: 100%; | 
					
					
						
						| 
							 | 
						            height: auto; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .controls { | 
					
					
						
						| 
							 | 
						            display: flex; | 
					
					
						
						| 
							 | 
						            justify-content: center; | 
					
					
						
						| 
							 | 
						            margin-top: 2px; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        button { | 
					
					
						
						| 
							 | 
						            margin: 0 5px; | 
					
					
						
						| 
							 | 
						            font-size: 20px; | 
					
					
						
						| 
							 | 
						            background-color: #333; | 
					
					
						
						| 
							 | 
						            color: #fff; | 
					
					
						
						| 
							 | 
						            border: none; | 
					
					
						
						| 
							 | 
						            padding: 5px 10px; | 
					
					
						
						| 
							 | 
						            cursor: pointer; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        .checkbox-container label { | 
					
					
						
						| 
							 | 
						            display: block; | 
					
					
						
						| 
							 | 
						            margin-bottom: 20px; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        #loadingIndicator { | 
					
					
						
						| 
							 | 
						            display: none; | 
					
					
						
						| 
							 | 
						            position: fixed; | 
					
					
						
						| 
							 | 
						            top: 50%; | 
					
					
						
						| 
							 | 
						            left: 50%; | 
					
					
						
						| 
							 | 
						            transform: translate(-50%, -50%); | 
					
					
						
						| 
							 | 
						            background-color: rgba(0, 0, 0, 0.7); | 
					
					
						
						| 
							 | 
						            color: rgb(255, 255, 255); | 
					
					
						
						| 
							 | 
						            padding: 20px; | 
					
					
						
						| 
							 | 
						            border-radius: 5px; | 
					
					
						
						| 
							 | 
						            z-index: 1000; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						    </style> | 
					
					
						
						| 
							 | 
						</head> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						<body> | 
					
					
						
						| 
							 | 
						    <h1>Motion Capture Visualization</h1> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    <div class="main-container"> | 
					
					
						
						| 
							 | 
						        <div class="episode-list"> | 
					
					
						
						| 
							 | 
						            <h3>Episodes</h3> | 
					
					
						
						| 
							 | 
						             | 
					
					
						
						| 
							 | 
						            <label><input type="checkbox"> Episode 1</label> | 
					
					
						
						| 
							 | 
						            <label><input type="checkbox"> Episode 2</label> | 
					
					
						
						| 
							 | 
						             | 
					
					
						
						| 
							 | 
						            <label><input type="checkbox"> Episode 29</label> | 
					
					
						
						| 
							 | 
						            <label><input type="checkbox"> Episode 30</label> | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        <div class="content-container"> | 
					
					
						
						| 
							 | 
						            <div class="checkbox-container"> | 
					
					
						
						| 
							 | 
						                <h3>Tasks</h3> | 
					
					
						
						| 
							 | 
						                <label> | 
					
					
						
						| 
							 | 
						                    <input type="radio" name="videoOption" value="fold_towels" checked> Fold towels | 
					
					
						
						| 
							 | 
						                </label> | 
					
					
						
						| 
							 | 
						                <label> | 
					
					
						
						| 
							 | 
						                    <input type="radio" name="videoOption" value="pipette"> Pipette | 
					
					
						
						| 
							 | 
						                </label> | 
					
					
						
						| 
							 | 
						                <label> | 
					
					
						
						| 
							 | 
						                    <input type="radio" name="videoOption" value="take_the_item"> Take the item | 
					
					
						
						| 
							 | 
						                </label> | 
					
					
						
						| 
							 | 
						                <label> | 
					
					
						
						| 
							 | 
						                    <input type="radio" name="videoOption" value="twist_the_tube"> Twist the tube | 
					
					
						
						| 
							 | 
						                </label> | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            <div class="video-container"> | 
					
					
						
						| 
							 | 
						                <video id="laptopVideo"> | 
					
					
						
						| 
							 | 
						                    <source src="https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/Video/video.mp4" | 
					
					
						
						| 
							 | 
						                        type="video/mp4"> | 
					
					
						
						| 
							 | 
						                    Your browser does not support the video tag. | 
					
					
						
						| 
							 | 
						                </video> | 
					
					
						
						| 
							 | 
						                <div class="controls"> | 
					
					
						
						| 
							 | 
						                    <button id="playPauseBtn">▶️</button> | 
					
					
						
						| 
							 | 
						                    <button id="rewindBtn">⏪</button> | 
					
					
						
						| 
							 | 
						                    <button id="forwardBtn">⏩</button> | 
					
					
						
						| 
							 | 
						                    <button id="restartBtn">↩️</button> | 
					
					
						
						| 
							 | 
						                </div> | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						            <div id="plotDiv"></div> | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						    </div> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    <div id="loadingIndicator">Loading...</div> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    <script> | 
					
					
						
						| 
							 | 
						        let csvFilePath = 'https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/MoCap/mocap.csv'; | 
					
					
						
						| 
							 | 
						        const body_part_names = [ | 
					
					
						
						| 
							 | 
						            'Left Shoulder', 'Right Upper Arm', 'Left Lower Leg', 'Spine1', 'Right Upper Leg', | 
					
					
						
						| 
							 | 
						            'Spine3', 'Right Lower Arm', 'Left Foot', 'Right Lower Leg', 'Right Shoulder', | 
					
					
						
						| 
							 | 
						            'Left Hand', 'Left Upper Leg', 'Right Foot', 'Spine', 'Spine2', 'Left Lower Arm', | 
					
					
						
						| 
							 | 
						            'Left Toe', 'Neck', 'Right Hand', 'Right Toe', 'Head', 'Left Upper Arm', 'Hips' | 
					
					
						
						| 
							 | 
						        ]; | 
					
					
						
						| 
							 | 
						        const laptopVideo = document.getElementById('laptopVideo'); | 
					
					
						
						| 
							 | 
						        const playPauseBtn = document.getElementById('playPauseBtn'); | 
					
					
						
						| 
							 | 
						        const rewindBtn = document.getElementById('rewindBtn'); | 
					
					
						
						| 
							 | 
						        const forwardBtn = document.getElementById('forwardBtn'); | 
					
					
						
						| 
							 | 
						        const restartBtn = document.getElementById('restartBtn'); | 
					
					
						
						| 
							 | 
						        const radioButtons = document.querySelectorAll('input[name="videoOption"]'); | 
					
					
						
						| 
							 | 
						        let animationFrameId; | 
					
					
						
						| 
							 | 
						        let isPlaying = false; | 
					
					
						
						| 
							 | 
						        function togglePlayPause() { | 
					
					
						
						| 
							 | 
						            if (!isPlaying) { | 
					
					
						
						| 
							 | 
						                laptopVideo.play(); | 
					
					
						
						| 
							 | 
						                playPauseBtn.textContent = '⏸️'; | 
					
					
						
						| 
							 | 
						                isPlaying = true; | 
					
					
						
						| 
							 | 
						                animate3DVisualization(); | 
					
					
						
						| 
							 | 
						            } else { | 
					
					
						
						| 
							 | 
						                laptopVideo.pause(); | 
					
					
						
						| 
							 | 
						                playPauseBtn.textContent = '▶️'; | 
					
					
						
						| 
							 | 
						                isPlaying = false; | 
					
					
						
						| 
							 | 
						                cancelAnimationFrame(animationFrameId); | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function rewind() { | 
					
					
						
						| 
							 | 
						            laptopVideo.currentTime -= 5; | 
					
					
						
						| 
							 | 
						            update3DVisualization(); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function forward() { | 
					
					
						
						| 
							 | 
						            laptopVideo.currentTime += 5; | 
					
					
						
						| 
							 | 
						            update3DVisualization(); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function restart() { | 
					
					
						
						| 
							 | 
						            laptopVideo.currentTime = 0; | 
					
					
						
						| 
							 | 
						            update3DVisualization(); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        playPauseBtn.addEventListener('click', togglePlayPause); | 
					
					
						
						| 
							 | 
						        rewindBtn.addEventListener('click', rewind); | 
					
					
						
						| 
							 | 
						        forwardBtn.addEventListener('click', forward); | 
					
					
						
						| 
							 | 
						        restartBtn.addEventListener('click', restart); | 
					
					
						
						| 
							 | 
						        function getCoordinates(data, coordinate) { | 
					
					
						
						| 
							 | 
						            return body_part_names.map(part => parseFloat(data[`${part}_${coordinate}`])); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        let frames; | 
					
					
						
						| 
							 | 
						        function processData(results) { | 
					
					
						
						| 
							 | 
						            console.log("Processing data:", results); | 
					
					
						
						| 
							 | 
						            const motion_capture_data = results.data.filter((_, index) => index % 3 === 0); | 
					
					
						
						| 
							 | 
						            frames = motion_capture_data.map((row, index) => ({ | 
					
					
						
						| 
							 | 
						                name: index.toString(), | 
					
					
						
						| 
							 | 
						                data: [{ | 
					
					
						
						| 
							 | 
						                    x: getCoordinates(row, 'x'), | 
					
					
						
						| 
							 | 
						                    y: getCoordinates(row, 'y'), | 
					
					
						
						| 
							 | 
						                    z: getCoordinates(row, 'z'), | 
					
					
						
						| 
							 | 
						                    mode: 'markers', | 
					
					
						
						| 
							 | 
						                    type: 'scatter3d', | 
					
					
						
						| 
							 | 
						                    marker: { size: 4, color: 'blue' } | 
					
					
						
						| 
							 | 
						                }] | 
					
					
						
						| 
							 | 
						            })); | 
					
					
						
						| 
							 | 
						            if (frames.length === 0) { | 
					
					
						
						| 
							 | 
						                console.error("No frames were created from the data"); | 
					
					
						
						| 
							 | 
						                return; | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						            const initialFrame = frames[0].data[0]; | 
					
					
						
						| 
							 | 
						            const layout = { | 
					
					
						
						| 
							 | 
						                title: '3D Motion Capture', | 
					
					
						
						| 
							 | 
						                scene: { | 
					
					
						
						| 
							 | 
						                    xaxis: { title: 'X' }, | 
					
					
						
						| 
							 | 
						                    yaxis: { title: 'Y' }, | 
					
					
						
						| 
							 | 
						                    zaxis: { title: 'Z' } | 
					
					
						
						| 
							 | 
						                } | 
					
					
						
						| 
							 | 
						            }; | 
					
					
						
						| 
							 | 
						            Plotly.newPlot('plotDiv', [initialFrame], layout); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function update3DVisualization() { | 
					
					
						
						| 
							 | 
						            if (!frames) return; | 
					
					
						
						| 
							 | 
						            const currentTime = laptopVideo.currentTime; | 
					
					
						
						| 
							 | 
						            const totalDuration = laptopVideo.duration; | 
					
					
						
						| 
							 | 
						            const frameIndex = Math.floor((currentTime / totalDuration) * frames.length); | 
					
					
						
						| 
							 | 
						            const frame = frames[Math.min(frameIndex, frames.length - 1)]; | 
					
					
						
						| 
							 | 
						            Plotly.animate('plotDiv', frame, { | 
					
					
						
						| 
							 | 
						                transition: { duration: 0 }, | 
					
					
						
						| 
							 | 
						                frame: { duration: 0, redraw: true } | 
					
					
						
						| 
							 | 
						            }); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function animate3DVisualization() { | 
					
					
						
						| 
							 | 
						            update3DVisualization(); | 
					
					
						
						| 
							 | 
						            if (isPlaying) { | 
					
					
						
						| 
							 | 
						                animationFrameId = requestAnimationFrame(animate3DVisualization); | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function updateVideoAndCSVSource() { | 
					
					
						
						| 
							 | 
						            const selectedOption = document.querySelector('input[name="videoOption"]:checked').value; | 
					
					
						
						| 
							 | 
						            const videoUrl = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/Video/video.mp4`; | 
					
					
						
						| 
							 | 
						            if (selectedOption != "twist_the_tube") { | 
					
					
						
						| 
							 | 
						                csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/mocap.csv`; | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						            else { | 
					
					
						
						| 
							 | 
						                csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/MoCap.csv`; | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						            laptopVideo.pause(); | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						            laptopVideo.querySelector('source').src = videoUrl; | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						            laptopVideo.load(); | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						            isPlaying = false; | 
					
					
						
						| 
							 | 
						            playPauseBtn.textContent = '▶️'; | 
					
					
						
						| 
							 | 
						             | 
					
					
						
						| 
							 | 
						            fetchAndProcessCSV(); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        function fetchAndProcessCSV() { | 
					
					
						
						| 
							 | 
						            fetch(csvFilePath) | 
					
					
						
						| 
							 | 
						                .then(response => { | 
					
					
						
						| 
							 | 
						                    if (!response.ok) { | 
					
					
						
						| 
							 | 
						                        throw new Error(`HTTP error! status: ${response.status}`); | 
					
					
						
						| 
							 | 
						                    } | 
					
					
						
						| 
							 | 
						                    return response.text(); | 
					
					
						
						| 
							 | 
						                }) | 
					
					
						
						| 
							 | 
						                .then(csvString => { | 
					
					
						
						| 
							 | 
						                    console.log("CSV data loaded successfully"); | 
					
					
						
						| 
							 | 
						                    Papa.parse(csvString, { | 
					
					
						
						| 
							 | 
						                        header: true, | 
					
					
						
						| 
							 | 
						                        dynamicTyping: true, | 
					
					
						
						| 
							 | 
						                        complete: processData | 
					
					
						
						| 
							 | 
						                    }); | 
					
					
						
						| 
							 | 
						                }) | 
					
					
						
						| 
							 | 
						                .catch(error => console.error('Error loading the CSV file:', error)); | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						        radioButtons.forEach(radio => { | 
					
					
						
						| 
							 | 
						            radio.addEventListener('change', updateVideoAndCSVSource); | 
					
					
						
						| 
							 | 
						        }); | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        fetchAndProcessCSV(); | 
					
					
						
						| 
							 | 
						    </script> | 
					
					
						
						| 
							 | 
						</body> | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						</html> |