Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
·
21ee9d9
1
Parent(s):
889687b
more UI change
Browse files- index.html +97 -9
index.html
CHANGED
|
@@ -305,6 +305,20 @@
|
|
| 305 |
color: #78716c;
|
| 306 |
}
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
.status-bar {
|
| 309 |
display: flex;
|
| 310 |
justify-content: space-between;
|
|
@@ -332,6 +346,11 @@
|
|
| 332 |
color: #991b1b;
|
| 333 |
}
|
| 334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
.mode-toggle {
|
| 336 |
display: flex;
|
| 337 |
gap: 10px;
|
|
@@ -719,6 +738,7 @@
|
|
| 719 |
<h2>Generated Video</h2>
|
| 720 |
<div class="video-container">
|
| 721 |
<canvas id="outputCanvas"></canvas>
|
|
|
|
| 722 |
<div id="placeholder" class="placeholder">
|
| 723 |
<p>Configure settings and click Start</p>
|
| 724 |
</div>
|
|
@@ -728,6 +748,12 @@
|
|
| 728 |
<div>
|
| 729 |
<span id="statusPill" class="status-pill status-disconnected">Disconnected</span>
|
| 730 |
<span style="margin-left: 15px;">Frames: <strong id="frameCount">0</strong> / <strong id="maxFrames">234</strong></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
</div>
|
| 732 |
<div>
|
| 733 |
<label style="display: inline; margin: 0;">Playback:</label>
|
|
@@ -756,7 +782,6 @@
|
|
| 756 |
<button id="startStopBtn" class="btn btn-primary" onclick="app.toggleGeneration()" style="flex: 1;">
|
| 757 |
Start Generation
|
| 758 |
</button>
|
| 759 |
-
<button class="btn btn-secondary" onclick="app.downloadVideo()">Download</button>
|
| 760 |
</div>
|
| 761 |
|
| 762 |
<!-- Advanced Settings Accordion -->
|
|
@@ -1165,6 +1190,7 @@
|
|
| 1165 |
maxFrames: 234,
|
| 1166 |
ws: null,
|
| 1167 |
frameBuffer: [],
|
|
|
|
| 1168 |
playbackInterval: null,
|
| 1169 |
frameExtractionInterval: null,
|
| 1170 |
webcamStream: null,
|
|
@@ -1174,6 +1200,7 @@
|
|
| 1174 |
recordedChunks: [],
|
| 1175 |
promptUpdateTimer: null,
|
| 1176 |
pendingPromptUpdate: null,
|
|
|
|
| 1177 |
|
| 1178 |
init() {
|
| 1179 |
this.setupEventListeners();
|
|
@@ -1383,10 +1410,18 @@
|
|
| 1383 |
|
| 1384 |
this.isGenerating = true;
|
| 1385 |
this.frameCount = 0;
|
|
|
|
| 1386 |
document.getElementById('frameCount').textContent = '0';
|
| 1387 |
this.frameBuffer = [];
|
|
|
|
| 1388 |
this.updateUI();
|
| 1389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1390 |
// Start recording
|
| 1391 |
this.startRecording();
|
| 1392 |
|
|
@@ -1462,11 +1497,14 @@
|
|
| 1462 |
btn.disabled = !auth.canStart;
|
| 1463 |
}
|
| 1464 |
|
| 1465 |
-
// Update status
|
| 1466 |
-
|
| 1467 |
-
|
| 1468 |
-
statusPill
|
| 1469 |
-
|
|
|
|
|
|
|
|
|
|
| 1470 |
}
|
| 1471 |
|
| 1472 |
// Re-enable mode buttons
|
|
@@ -1474,8 +1512,6 @@
|
|
| 1474 |
const btn = document.getElementById(id);
|
| 1475 |
if (btn) btn.disabled = false;
|
| 1476 |
});
|
| 1477 |
-
|
| 1478 |
-
this.showInfo(`Disconnected: ${event.reason || 'Generation complete'}`);
|
| 1479 |
};
|
| 1480 |
|
| 1481 |
} catch (error) {
|
|
@@ -1554,11 +1590,12 @@
|
|
| 1554 |
const bitmap = await createImageBitmap(blob);
|
| 1555 |
|
| 1556 |
this.frameBuffer.push(bitmap);
|
|
|
|
| 1557 |
this.frameCount++;
|
| 1558 |
document.getElementById('frameCount').textContent = this.frameCount;
|
| 1559 |
|
| 1560 |
if (this.frameCount === 1) {
|
| 1561 |
-
document.getElementById('
|
| 1562 |
this.startPlaybackLoop();
|
| 1563 |
}
|
| 1564 |
|
|
@@ -1569,9 +1606,22 @@
|
|
| 1569 |
// Check if generation is complete
|
| 1570 |
if (this.frameCount >= this.maxFrames) {
|
| 1571 |
this.isGenerating = false;
|
|
|
|
| 1572 |
this.stopFrameExtraction();
|
| 1573 |
this.stopRecording();
|
| 1574 |
this.updateUI();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1575 |
this.showInfo('Generation complete!');
|
| 1576 |
}
|
| 1577 |
},
|
|
@@ -1867,9 +1917,47 @@
|
|
| 1867 |
this.stopFrameExtraction();
|
| 1868 |
this.stopRecording();
|
| 1869 |
this.isGenerating = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1870 |
this.updateUI();
|
| 1871 |
},
|
| 1872 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1873 |
downloadVideo() {
|
| 1874 |
if (this.recordedChunks.length === 0) {
|
| 1875 |
this.showError('No video data to download');
|
|
|
|
| 305 |
color: #78716c;
|
| 306 |
}
|
| 307 |
|
| 308 |
+
.spinner {
|
| 309 |
+
width: 50px;
|
| 310 |
+
height: 50px;
|
| 311 |
+
border: 4px solid #e7e5e4;
|
| 312 |
+
border-top: 4px solid #f59e0b;
|
| 313 |
+
border-radius: 50%;
|
| 314 |
+
animation: spin 1s linear infinite;
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
@keyframes spin {
|
| 318 |
+
0% { transform: rotate(0deg); }
|
| 319 |
+
100% { transform: rotate(360deg); }
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
.status-bar {
|
| 323 |
display: flex;
|
| 324 |
justify-content: space-between;
|
|
|
|
| 346 |
color: #991b1b;
|
| 347 |
}
|
| 348 |
|
| 349 |
+
.status-finished {
|
| 350 |
+
background: #dbeafe;
|
| 351 |
+
color: #1e40af;
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
.mode-toggle {
|
| 355 |
display: flex;
|
| 356 |
gap: 10px;
|
|
|
|
| 738 |
<h2>Generated Video</h2>
|
| 739 |
<div class="video-container">
|
| 740 |
<canvas id="outputCanvas"></canvas>
|
| 741 |
+
<div id="spinner" class="spinner hidden"></div>
|
| 742 |
<div id="placeholder" class="placeholder">
|
| 743 |
<p>Configure settings and click Start</p>
|
| 744 |
</div>
|
|
|
|
| 748 |
<div>
|
| 749 |
<span id="statusPill" class="status-pill status-disconnected">Disconnected</span>
|
| 750 |
<span style="margin-left: 15px;">Frames: <strong id="frameCount">0</strong> / <strong id="maxFrames">234</strong></span>
|
| 751 |
+
<button id="replayBtn" class="btn btn-secondary hidden" onclick="app.replayVideo()" style="margin-left: 15px; padding: 4px 12px; font-size: 0.75rem;">
|
| 752 |
+
Replay
|
| 753 |
+
</button>
|
| 754 |
+
<button id="downloadBtn" class="btn btn-secondary hidden" onclick="app.downloadVideo()" style="margin-left: 10px; padding: 4px 12px; font-size: 0.75rem;">
|
| 755 |
+
Download
|
| 756 |
+
</button>
|
| 757 |
</div>
|
| 758 |
<div>
|
| 759 |
<label style="display: inline; margin: 0;">Playback:</label>
|
|
|
|
| 782 |
<button id="startStopBtn" class="btn btn-primary" onclick="app.toggleGeneration()" style="flex: 1;">
|
| 783 |
Start Generation
|
| 784 |
</button>
|
|
|
|
| 785 |
</div>
|
| 786 |
|
| 787 |
<!-- Advanced Settings Accordion -->
|
|
|
|
| 1190 |
maxFrames: 234,
|
| 1191 |
ws: null,
|
| 1192 |
frameBuffer: [],
|
| 1193 |
+
allFrames: [], // Store all frames for replay
|
| 1194 |
playbackInterval: null,
|
| 1195 |
frameExtractionInterval: null,
|
| 1196 |
webcamStream: null,
|
|
|
|
| 1200 |
recordedChunks: [],
|
| 1201 |
promptUpdateTimer: null,
|
| 1202 |
pendingPromptUpdate: null,
|
| 1203 |
+
generationFinished: false,
|
| 1204 |
|
| 1205 |
init() {
|
| 1206 |
this.setupEventListeners();
|
|
|
|
| 1410 |
|
| 1411 |
this.isGenerating = true;
|
| 1412 |
this.frameCount = 0;
|
| 1413 |
+
this.generationFinished = false;
|
| 1414 |
document.getElementById('frameCount').textContent = '0';
|
| 1415 |
this.frameBuffer = [];
|
| 1416 |
+
this.allFrames = [];
|
| 1417 |
this.updateUI();
|
| 1418 |
|
| 1419 |
+
// Show spinner, hide placeholder, replay and download buttons
|
| 1420 |
+
document.getElementById('spinner').classList.remove('hidden');
|
| 1421 |
+
document.getElementById('placeholder').style.display = 'none';
|
| 1422 |
+
document.getElementById('replayBtn').classList.add('hidden');
|
| 1423 |
+
document.getElementById('downloadBtn').classList.add('hidden');
|
| 1424 |
+
|
| 1425 |
// Start recording
|
| 1426 |
this.startRecording();
|
| 1427 |
|
|
|
|
| 1497 |
btn.disabled = !auth.canStart;
|
| 1498 |
}
|
| 1499 |
|
| 1500 |
+
// Update status - only if not already finished
|
| 1501 |
+
if (!this.generationFinished) {
|
| 1502 |
+
const statusPill = document.getElementById('statusPill');
|
| 1503 |
+
if (statusPill) {
|
| 1504 |
+
statusPill.className = 'status-pill status-disconnected';
|
| 1505 |
+
statusPill.textContent = 'Disconnected';
|
| 1506 |
+
}
|
| 1507 |
+
this.showInfo(`Disconnected: ${event.reason || 'Connection closed'}`);
|
| 1508 |
}
|
| 1509 |
|
| 1510 |
// Re-enable mode buttons
|
|
|
|
| 1512 |
const btn = document.getElementById(id);
|
| 1513 |
if (btn) btn.disabled = false;
|
| 1514 |
});
|
|
|
|
|
|
|
| 1515 |
};
|
| 1516 |
|
| 1517 |
} catch (error) {
|
|
|
|
| 1590 |
const bitmap = await createImageBitmap(blob);
|
| 1591 |
|
| 1592 |
this.frameBuffer.push(bitmap);
|
| 1593 |
+
this.allFrames.push(imageData); // Store raw data for replay
|
| 1594 |
this.frameCount++;
|
| 1595 |
document.getElementById('frameCount').textContent = this.frameCount;
|
| 1596 |
|
| 1597 |
if (this.frameCount === 1) {
|
| 1598 |
+
document.getElementById('spinner').classList.add('hidden');
|
| 1599 |
this.startPlaybackLoop();
|
| 1600 |
}
|
| 1601 |
|
|
|
|
| 1606 |
// Check if generation is complete
|
| 1607 |
if (this.frameCount >= this.maxFrames) {
|
| 1608 |
this.isGenerating = false;
|
| 1609 |
+
this.generationFinished = true;
|
| 1610 |
this.stopFrameExtraction();
|
| 1611 |
this.stopRecording();
|
| 1612 |
this.updateUI();
|
| 1613 |
+
|
| 1614 |
+
// Update status to Finished
|
| 1615 |
+
const statusPill = document.getElementById('statusPill');
|
| 1616 |
+
statusPill.className = 'status-pill status-finished';
|
| 1617 |
+
statusPill.textContent = 'Finished';
|
| 1618 |
+
|
| 1619 |
+
// Show replay and download buttons
|
| 1620 |
+
document.getElementById('replayBtn').classList.remove('hidden');
|
| 1621 |
+
if (this.recordedChunks.length > 0) {
|
| 1622 |
+
document.getElementById('downloadBtn').classList.remove('hidden');
|
| 1623 |
+
}
|
| 1624 |
+
|
| 1625 |
this.showInfo('Generation complete!');
|
| 1626 |
}
|
| 1627 |
},
|
|
|
|
| 1917 |
this.stopFrameExtraction();
|
| 1918 |
this.stopRecording();
|
| 1919 |
this.isGenerating = false;
|
| 1920 |
+
|
| 1921 |
+
// Hide spinner, show placeholder if no frames
|
| 1922 |
+
document.getElementById('spinner').classList.add('hidden');
|
| 1923 |
+
if (this.frameCount === 0) {
|
| 1924 |
+
document.getElementById('placeholder').style.display = 'flex';
|
| 1925 |
+
}
|
| 1926 |
+
|
| 1927 |
+
// Update status pill - only show "Disconnected" if manually stopped or error
|
| 1928 |
+
if (!this.generationFinished) {
|
| 1929 |
+
const statusPill = document.getElementById('statusPill');
|
| 1930 |
+
if (statusPill) {
|
| 1931 |
+
statusPill.className = 'status-pill status-disconnected';
|
| 1932 |
+
statusPill.textContent = 'Disconnected';
|
| 1933 |
+
}
|
| 1934 |
+
}
|
| 1935 |
+
|
| 1936 |
this.updateUI();
|
| 1937 |
},
|
| 1938 |
|
| 1939 |
+
async replayVideo() {
|
| 1940 |
+
if (this.allFrames.length === 0) {
|
| 1941 |
+
this.showError('No frames to replay');
|
| 1942 |
+
return;
|
| 1943 |
+
}
|
| 1944 |
+
|
| 1945 |
+
// Stop current playback
|
| 1946 |
+
this.stopPlaybackLoop();
|
| 1947 |
+
|
| 1948 |
+
// Recreate frameBuffer from stored frames
|
| 1949 |
+
this.frameBuffer = [];
|
| 1950 |
+
for (const imageData of this.allFrames) {
|
| 1951 |
+
const blob = new Blob([imageData], { type: 'image/jpeg' });
|
| 1952 |
+
const bitmap = await createImageBitmap(blob);
|
| 1953 |
+
this.frameBuffer.push(bitmap);
|
| 1954 |
+
}
|
| 1955 |
+
|
| 1956 |
+
// Restart playback
|
| 1957 |
+
this.startPlaybackLoop();
|
| 1958 |
+
this.showInfo('Replaying video');
|
| 1959 |
+
},
|
| 1960 |
+
|
| 1961 |
downloadVideo() {
|
| 1962 |
if (this.recordedChunks.length === 0) {
|
| 1963 |
this.showError('No video data to download');
|