Files
PozzettiAndrea-ComfyUI-Turn…/dev/linux-cpu/index.html
T
2026-06-07 17:33:06 +00:00

1593 lines
112 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PozzettiAndrea/ComfyUI-GaussianPack - Test Results</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #0f1923;
color: #e6edf3;
min-height: 100vh;
line-height: 1.6;
}
header {
background: #162033;
padding: 1.25rem 2rem;
border-bottom: 1px solid #243656;
}
body.in-iframe header {
display: none;
}
body.in-iframe .container {
padding-top: 1.25rem;
}
body.in-iframe .summary-meta {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
margin-bottom: 1rem;
}
h1 {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
h1 a {
color: #e6edf3;
text-decoration: none;
}
h1 a:hover { color: #58a6ff; }
.meta-chips {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
align-items: center;
}
.meta-chip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.2rem 0.6rem;
background: #1c2d44;
border: 1px solid #243656;
border-radius: 2rem;
font-size: 0.75rem;
color: #8ba3c1;
}
a.meta-chip {
text-decoration: none;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}
a.meta-chip:hover {
background: #25395a;
border-color: #3a5587;
color: #cfe1f7;
}
.meta-chip svg {
width: 12px;
height: 12px;
fill: currentColor;
flex-shrink: 0;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
/* Summary Section */
.summary {
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.progress-wrapper {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.progress-bar {
background: #1c2d44;
border-radius: 6px;
height: 10px;
overflow: hidden;
flex: 1;
}
.progress-fill {
background: #3fb950;
height: 100%;
border-radius: 6px;
transition: width 0.3s ease;
}
.progress-fill.has-failures {
background: linear-gradient(90deg, #3fb950 0%, #3fb950 100.0%, #f85149 100.0%, #f85149 100%);
width: 100% !important;
border-radius: 6px;
}
.progress-label {
font-size: 0.85rem;
font-weight: 600;
color: #8ba3c1;
white-space: nowrap;
min-width: 3.5rem;
text-align: right;
}
.stats {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
align-items: center;
}
.stat-badge {
padding: 0.35rem 0.75rem;
border-radius: 2rem;
font-weight: 600;
font-size: 0.8rem;
}
.stat-pass {
background: rgba(63, 185, 80, 0.15);
color: #3fb950;
}
.stat-fail {
background: rgba(248, 81, 73, 0.15);
color: #f85149;
}
.stat-total {
color: #8ba3c1;
font-size: 0.85rem;
}
/* Failed Section */
.failed-section {
background: rgba(248, 81, 73, 0.08);
border: 1px solid rgba(248, 81, 73, 0.3);
border-radius: 8px;
padding: 1.25rem;
margin-bottom: 2rem;
}
.failed-section h2 {
color: #f85149;
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 0.75rem;
}
.failed-item {
background: #162033;
border: 1px solid #243656;
border-radius: 6px;
padding: 1rem;
margin-bottom: 0.5rem;
}
.failed-item:last-child {
margin-bottom: 0;
}
.failed-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.failed-name {
font-weight: 600;
color: #f85149;
}
.failed-duration {
color: #8ba3c1;
font-size: 0.8rem;
}
.failed-error {
background: #0f1923;
border: 1px solid #243656;
padding: 0.75rem;
border-radius: 6px;
font-family: 'SFMono-Regular', 'Menlo', 'Monaco', monospace;
font-size: 0.8rem;
color: #d29922;
margin-bottom: 0.5rem;
}
.log-link {
color: #58a6ff;
text-decoration: none;
font-size: 0.8rem;
}
.log-link:hover {
text-decoration: underline;
}
/* Workflow Grid */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.25rem;
}
.section-title {
font-size: 0.8rem;
color: #8ba3c1;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.view-controls {
display: flex;
gap: 0;
align-items: center;
border: 1px solid #243656;
border-radius: 6px;
overflow: hidden;
}
.view-btn {
background: #1c2d44;
color: #8ba3c1;
border: none;
border-right: 1px solid #243656;
padding: 0.3rem 0.75rem;
cursor: pointer;
font-size: 0.75rem;
font-weight: 500;
transition: all 0.15s;
}
.view-btn:last-child {
border-right: none;
}
.view-btn:hover {
background: #243656;
color: #e6edf3;
}
.view-btn.active {
background: #58a6ff;
color: #fff;
}
.workflow-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.workflow-grid.view-list {
grid-template-columns: 1fr;
gap: 0;
}
.workflow-grid.view-list .workflow-card {
border-radius: 0;
border-bottom: 1px solid #243656;
}
.workflow-grid.view-list .workflow-card:first-child {
border-radius: 8px 8px 0 0;
}
.workflow-grid.view-list .workflow-card:last-child {
border-radius: 0 0 8px 8px;
border-bottom: none;
}
.workflow-grid.view-list .workflow-card:only-child {
border-radius: 8px;
}
.workflow-grid.view-list .workflow-screenshot {
width: 100%;
height: auto;
aspect-ratio: auto;
}
.workflow-grid.view-list .workflow-info {
border-top: 1px solid #243656;
padding: 0.75rem 1rem;
}
.workflow-grid.view-list .workflow-name {
max-width: none;
font-size: 0.9rem;
}
.workflow-card {
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
overflow: hidden;
transition: transform 0.15s, border-color 0.15s;
}
.workflow-card:hover {
transform: translateY(-1px);
border-color: #4a6282;
}
.workflow-card.clickable {
cursor: pointer;
}
.workflow-card.failed {
border-color: #f85149;
}
.workflow-card.failed:hover {
border-color: #f85149;
}
.workflow-screenshot {
width: 100%;
aspect-ratio: 16/10;
object-fit: cover;
background: #0f1923;
display: block;
}
.workflow-screenshot.placeholder {
display: flex;
align-items: center;
justify-content: center;
color: #4a6282;
font-size: 0.8rem;
}
.workflow-info {
padding: 0.75rem 1rem;
border-top: 1px solid #243656;
}
.workflow-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.25rem;
}
.workflow-name {
font-weight: 500;
font-size: 0.85rem;
color: #e6edf3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 65%;
}
.workflow-badge {
padding: 0.15rem 0.5rem;
border-radius: 2rem;
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
flex-shrink: 0;
}
.workflow-badge.pass {
background: rgba(63, 185, 80, 0.15);
color: #3fb950;
}
.workflow-badge.fail {
background: rgba(248, 81, 73, 0.15);
color: #f85149;
}
.workflow-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.75rem;
color: #4a6282;
}
/* Lightbox */
.lightbox {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(1, 4, 9, 0.9);
z-index: 1000;
justify-content: center;
align-items: flex-start;
padding: 2rem;
overflow-y: auto;
}
.lightbox.active {
display: flex;
}
.lightbox-content {
display: flex;
flex-direction: column;
max-width: 1200px;
width: 100%;
margin: auto;
}
.lightbox-content img {
max-width: 100%;
max-height: 60vh;
object-fit: contain;
border-radius: 8px;
border: 1px solid #243656;
align-self: center;
cursor: zoom-in;
}
.img-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1002;
background: rgba(1, 4, 9, 0.95);
overflow: auto;
align-items: center;
justify-content: center;
}
.img-overlay.active {
display: flex;
}
.img-overlay.zoomed {
align-items: flex-start;
justify-content: flex-start;
}
.img-overlay img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
cursor: zoom-in;
}
.img-overlay.zoomed img {
max-width: none;
max-height: none;
cursor: zoom-out;
}
.lightbox-close {
position: fixed;
top: 1rem;
right: 1.5rem;
font-size: 2rem;
color: #e6edf3;
cursor: pointer;
opacity: 0.6;
background: none;
border: none;
z-index: 1001;
}
.lightbox-close:hover {
opacity: 1;
}
.lightbox-nav {
position: fixed;
top: 50%;
transform: translateY(-50%);
background: rgba(22, 32, 51, 0.8);
border: 1px solid #243656;
color: #e6edf3;
font-size: 2.5rem;
width: 48px;
height: 64px;
border-radius: 8px;
cursor: pointer;
opacity: 0.6;
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.15s;
padding: 0;
line-height: 1;
}
.lightbox-nav:hover {
opacity: 1;
}
.lightbox-nav-left { left: 1rem; }
.lightbox-nav-right { right: 1rem; }
.lightbox-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.25rem;
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
margin-top: 1rem;
}
.lightbox-title {
font-size: 1rem;
font-weight: 600;
color: #e6edf3;
}
.lightbox-hardware {
display: block;
font-size: 0.75rem;
color: #8ba3c1;
margin-top: 0.25rem;
}
.lightbox-meta {
display: flex;
gap: 1rem;
align-items: center;
}
.lightbox-badge {
padding: 0.25rem 0.75rem;
border-radius: 2rem;
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
}
.lightbox-badge.pass {
background: rgba(63, 185, 80, 0.15);
color: #3fb950;
}
.lightbox-badge.fail {
background: rgba(248, 81, 73, 0.15);
color: #f85149;
}
.lightbox-duration {
color: #8ba3c1;
font-size: 0.85rem;
}
.lightbox-log {
background: #0f1923;
border: 1px solid #243656;
border-radius: 8px;
padding: 1rem;
margin-top: 1rem;
max-height: 300px;
overflow-y: auto;
font-family: 'SFMono-Regular', 'Menlo', 'Monaco', monospace;
font-size: 0.8rem;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-all;
color: #8ba3c1;
}
.lightbox-log::-webkit-scrollbar {
width: 8px;
}
.lightbox-log::-webkit-scrollbar-track {
background: #162033;
border-radius: 4px;
}
.lightbox-log::-webkit-scrollbar-thumb {
background: #243656;
border-radius: 4px;
}
.lightbox-log::-webkit-scrollbar-thumb:hover {
background: #4a6282;
}
/* Resource Graph */
.resource-graph {
display: none;
margin-top: 1rem;
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
padding: 1rem;
}
.resource-graph.active {
display: block;
}
.resource-graph-title {
font-size: 0.8rem;
color: #8ba3c1;
font-weight: 500;
margin-bottom: 0.5rem;
}
.resource-graph canvas {
width: 100%;
height: 120px;
cursor: crosshair;
}
.resource-legend {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
font-size: 0.75rem;
color: #8ba3c1;
}
.resource-legend span {
display: flex;
align-items: center;
gap: 4px;
}
.resource-legend .dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.resource-legend .ram { background: #3fb950; }
.resource-legend .gpu { background: #d29922; }
/* Video Player */
.video-player {
display: none;
margin-top: 1rem;
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
padding: 1rem;
}
.video-player.active {
display: block;
}
.video-controls {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 0.5rem;
}
.video-play-btn {
background: #58a6ff;
color: #fff;
border: none;
padding: 0.4rem 1rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.8rem;
font-weight: 500;
}
.video-play-btn:hover {
background: #79b8ff;
}
.video-frame-counter {
color: #8ba3c1;
font-size: 0.8rem;
}
.video-slider-container {
padding: 15px 0;
}
/* noUiSlider customization */
#video-slider {
height: 6px;
background: #1c2d44;
border: none;
box-shadow: none;
}
#video-slider .noUi-connect {
background: #58a6ff;
}
#video-slider .noUi-handle {
width: 16px;
height: 16px;
background: #58a6ff;
border: none;
border-radius: 50%;
box-shadow: none;
top: -5px;
right: -8px;
cursor: pointer;
}
#video-slider .noUi-handle:before,
#video-slider .noUi-handle:after {
display: none;
}
/* Pips (tick marks) */
.noUi-pips {
color: #4a6282;
}
.noUi-marker {
background: #243656;
width: 2px;
}
.noUi-marker-large {
height: 12px;
}
.noUi-value {
display: none;
}
/* Models Section */
.models-section {
margin-top: 2rem;
margin-bottom: 2rem;
}
.models-total {
font-size: 0.8rem;
color: #8ba3c1;
}
.models-folder {
background: #162033;
border: 1px solid #243656;
border-radius: 8px;
margin-bottom: 0.5rem;
overflow: hidden;
}
.models-folder-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
cursor: pointer;
user-select: none;
list-style: none;
}
.models-folder-header::-webkit-details-marker {
display: none;
}
.models-folder-header::before {
content: '\25B6';
font-size: 0.6rem;
color: #4a6282;
margin-right: 0.5rem;
transition: transform 0.15s;
}
.models-folder[open] > .models-folder-header::before {
transform: rotate(90deg);
}
.models-folder-name {
font-family: 'SFMono-Regular', 'Menlo', 'Monaco', monospace;
font-size: 0.85rem;
font-weight: 600;
color: #58a6ff;
}
.models-folder-meta {
display: flex;
align-items: center;
gap: 0.75rem;
}
.models-folder-size {
font-size: 0.8rem;
font-weight: 600;
color: #8ba3c1;
}
.models-source-link {
font-size: 0.75rem;
color: #3fb950;
text-decoration: none;
padding: 0.15rem 0.5rem;
background: rgba(63, 185, 80, 0.1);
border: 1px solid rgba(63, 185, 80, 0.2);
border-radius: 2rem;
}
.models-source-link:hover {
background: rgba(63, 185, 80, 0.2);
text-decoration: none;
}
.models-file-list {
border-top: 1px solid #243656;
padding: 0.25rem 0;
}
.models-file {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.35rem 1rem 0.35rem 2rem;
font-size: 0.8rem;
}
.models-file:hover {
background: rgba(88, 166, 255, 0.05);
}
.models-file-path {
font-family: 'SFMono-Regular', 'Menlo', 'Monaco', monospace;
color: #8ba3c1;
word-break: break-all;
}
.models-file-size {
color: #4a6282;
white-space: nowrap;
margin-left: 1rem;
flex-shrink: 0;
}
/* Footer */
footer {
text-align: center;
padding: 2.5rem;
color: #4a6282;
font-size: 0.8rem;
}
footer a {
color: #58a6ff;
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
/* Responsive */
@media (max-width: 600px) {
.workflow-grid {
grid-template-columns: 1fr !important;
}
.workflow-grid.view-list .workflow-card {
grid-template-columns: 1fr;
}
.workflow-grid.view-list .workflow-screenshot {
width: 100%;
height: auto;
aspect-ratio: 16/10;
}
.stats {
flex-direction: column;
align-items: flex-start;
}
.section-header {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
.container {
padding: 1rem;
}
}
</style>
<link href="https://cdn.jsdelivr.net/npm/nouislider@15/dist/nouislider.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/nouislider@15/dist/nouislider.min.js"></script>
</head>
<body>
<header>
<h1><a href="https://github.com/PozzettiAndrea/PozzettiAndrea/ComfyUI-GaussianPack">PozzettiAndrea/ComfyUI-GaussianPack</a> Test Results</h1>
<div class="meta-chips">
<span class="meta-chip"><svg viewBox="0 0 16 16"><path d="M8 0a8 8 0 110 16A8 8 0 018 0zm.5 4.5a.5.5 0 00-1 0v3.793L5.854 9.854a.5.5 0 10.708.708l1.853-1.854a.5.5 0 00.085-.094V4.5z"/></svg> 2026-06-07 17:32 UTC</span> <a class="meta-chip" href="https://github.com/PozzettiAndrea/comfy-gpu-ci/actions/runs/27099644068" target="_blank" rel="noopener noreferrer"><svg viewBox="0 0 16 16"><path d="M8 0a8 8 0 100 16A8 8 0 008 0zM6.5 4.5l5 3.5-5 3.5v-7z"/></svg> Test run</a> <span class="meta-chip"><svg viewBox="0 0 16 16"><path d="M2.5 4a.5.5 0 100 1 .5.5 0 000-1zM4 4.5a.5.5 0 01.5-.5h7a.5.5 0 010 1h-7a.5.5 0 01-.5-.5zM2.5 7a.5.5 0 100 1 .5.5 0 000-1zM4 7.5a.5.5 0 01.5-.5h7a.5.5 0 010 1h-7A.5.5 0 014 7.5zM2.5 10a.5.5 0 100 1 .5.5 0 000-1zM4 10.5a.5.5 0 01.5-.5h7a.5.5 0 010 1h-7a.5.5 0 01-.5-.5z"/></svg> Linux-6.17.0-1015-azure-x86_64-with-glibc2.39</span> <span class="meta-chip"><svg viewBox="0 0 16 16"><path d="M5 0a.5.5 0 01.5.5V2h1V.5a.5.5 0 011 0V2h1V.5a.5.5 0 011 0V2h.5A2.5 2.5 0 0112.5 4.5H14v1h-1.5v1H14v1h-1.5v1H14v1h-1.5A2.5 2.5 0 0110 12h-.5v1.5a.5.5 0 01-1 0V12h-1v1.5a.5.5 0 01-1 0V12H6v1.5a.5.5 0 01-1 0V12h-.5A2.5 2.5 0 012 9.5H.5v-1H2v-1H.5v-1H2v-1H.5v-1H2A2.5 2.5 0 014.5 2V.5A.5.5 0 015 0zm-.5 4A1.5 1.5 0 003 5.5v4A1.5 1.5 0 004.5 11h6a1.5 1.5 0 001.5-1.5v-4A1.5 1.5 0 0010.5 4h-6z"/></svg> AMD EPYC 7763 64-Core Processor</span>
</div>
</header>
<div class="container">
<div class="summary">
<div class="progress-wrapper">
<div class="progress-bar">
<div class="progress-fill" style="width: 100.0%"></div>
</div>
<span class="progress-label">100.0%</span>
</div>
<div class="stats">
<span class="stat-badge stat-pass">4 passed</span>
<span class="stat-total">4/4 tests</span>
</div>
</div>
<div class="section-header">
<h2 class="section-title">Workflows</h2>
<div class="view-controls">
<button class="view-btn active" onclick="setView('grid')">Grid</button>
<button class="view-btn" onclick="setView('list')">List</button>
</div>
</div>
<div class="workflow-grid" id="workflow-grid">
<div class="workflow-card clickable " onclick="openLightboxByName('gaussian_analysis')">
<img class="workflow-screenshot" src="screenshots/gaussian_analysis_executed.png"
alt="gaussian_analysis" loading="lazy">
<div class="workflow-info">
<div class="workflow-header">
<span class="workflow-name" title="gaussian_analysis">gaussian_analysis</span>
<span class="workflow-badge pass">pass</span>
</div>
<div class="workflow-meta">
<span>10.60s</span>
</div>
</div>
</div>
<div class="workflow-card clickable " onclick="openLightboxByName('merge_splats')">
<img class="workflow-screenshot" src="screenshots/merge_splats_executed.png"
alt="merge_splats" loading="lazy">
<div class="workflow-info">
<div class="workflow-header">
<span class="workflow-name" title="merge_splats">merge_splats</span>
<span class="workflow-badge pass">pass</span>
</div>
<div class="workflow-meta">
<span>87.51s</span>
</div>
</div>
</div>
<div class="workflow-card clickable " onclick="openLightboxByName('rotate_splats')">
<img class="workflow-screenshot" src="screenshots/rotate_splats_executed.png"
alt="rotate_splats" loading="lazy">
<div class="workflow-info">
<div class="workflow-header">
<span class="workflow-name" title="rotate_splats">rotate_splats</span>
<span class="workflow-badge pass">pass</span>
</div>
<div class="workflow-meta">
<span>70.36s</span>
</div>
</div>
</div>
<div class="workflow-card clickable " onclick="openLightboxByName('spectate')">
<img class="workflow-screenshot" src="screenshots/spectate_executed.png"
alt="spectate" loading="lazy">
<div class="workflow-info">
<div class="workflow-header">
<span class="workflow-name" title="spectate">spectate</span>
<span class="workflow-badge pass">pass</span>
</div>
<div class="workflow-meta">
<span>17.75s</span>
</div>
</div>
</div>
</div>
</div>
<div class="lightbox" id="lightbox">
<button class="lightbox-close" onclick="closeLightbox()">&times;</button>
<button class="lightbox-nav lightbox-nav-left" onclick="navigateLightbox(-1)">&#8249;</button>
<button class="lightbox-nav lightbox-nav-right" onclick="navigateLightbox(1)">&#8250;</button>
<div class="lightbox-content">
<img id="lightbox-img" src="" alt="">
<video id="lightbox-video" controls preload="metadata" style="display:none; max-width:90vw; max-height:80vh; background:#000;"></video>
<div class="video-player" id="video-player">
<div class="video-slider-container">
<div id="video-slider"></div>
</div>
<div class="video-controls">
<span class="video-frame-counter" id="video-frame-counter">0.0s / 0.0s</span>
</div>
</div>
<div class="resource-graph" id="resource-graph">
<div class="resource-graph-title">Resource Usage</div>
<canvas id="resource-canvas"></canvas>
<div class="resource-legend">
<span><span class="dot ram"></span> RAM (GB)</span>
<span id="gpu-legend" style="display:none"><span class="dot gpu"></span> VRAM (GB)</span>
</div>
</div>
<div class="lightbox-info">
<div>
<span class="lightbox-title" id="lightbox-title"></span>
<span class="lightbox-hardware" id="lightbox-hardware"></span>
</div>
<div class="lightbox-meta">
<span class="lightbox-badge" id="lightbox-badge"></span>
<span class="lightbox-duration" id="lightbox-duration"></span>
</div>
</div>
<pre class="lightbox-log" id="lightbox-log"></pre>
</div>
</div>
<div class="img-overlay" id="img-overlay">
<img id="img-overlay-content" src="" alt="">
</div>
<footer>
Generated by <a href="https://github.com/PozzettiAndrea/comfy-test">comfy-test</a>
</footer>
<script>
function setView(mode) {
const grid = document.getElementById('workflow-grid');
grid.className = mode === 'list' ? 'workflow-grid view-list' : 'workflow-grid';
document.querySelectorAll('.view-controls .view-btn').forEach(btn => {
btn.classList.toggle('active', btn.textContent.trim().toLowerCase() === mode);
});
}
const workflowData = {"gaussian_analysis": {"src": "screenshots/gaussian_analysis_executed.png", "title": "gaussian_analysis", "status": "pass", "duration": "10.60", "log": " [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\nCapturing execution frames: gaussian_analysis.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 4 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 19: GaussianAnalysis\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 20: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"compressed_room.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 21: GaussianAnalysis\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_path\": [\"20\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: e92f40ff-64a0-434a-ab4c-d4c19153032a\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'compressed_room.ply'\n [ComfyUI] [comfy-env] SubprocessWorker: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [comfy-env] env_vars: {'COMFYUI_BASE': '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI'}\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_878570b9fb5e']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_878570b9fb5e (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=1 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.61s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianAnalysis: ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.analyze_gaussians.GaussianAnalysis.analyze\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=2 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianAnalysis done (0.01s): result: dict\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=3 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianAnalysis: ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.analyze_gaussians.GaussianAnalysis.analyze\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=4 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianAnalysis done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 1.64 seconds\u001b[0m\n Node executed (2 total), capturing...\n Frame 2 saved (frame_001.jpg, t=2.0s)\n [capture-node] freeze=3ms shot=90ms unfreeze=0ms saved=True\n Execution complete (t=2.0s)\n [3d-wait] Phase 1: Waiting for 'Loading 3D Model' text to disappear...\n [3d-wait] Phase 1 done in 0.0s\n [3d-wait] Phase 2: iframes=0\n [3d-wait] Total 3D wait: 0.0s\n Captured 2 unique frames over 2.16s\n [debug] iframes: 0\n [timing] trigger_3d_previews: 0.0s\n Saved high-quality screenshot: gaussian_analysis_executed.png\n [timing] final_screenshot: 0.3s\n Captured 3 video frames", "hardware": {"os": "Linux-6.17.0-1015-azure-x86_64-with-glibc2.39", "cpu": "AMD EPYC 7763 64-Core Processor"}}, "merge_splats": {"src": "screenshots/merge_splats_executed.png", "title": "merge_splats", "status": "pass", "duration": "87.51", "log": "Capturing execution frames: merge_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 12: GaussianMerge\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"target_count\": 100000, \"output_filename\": \"applemerged\", \"opacity_threshold\": 0.1, \"k\": 16, \"backend\": \"nanogs_cpu\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"12\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 0583cf3f-691e-4509-80fd-c1f4d1f20bb9\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=5 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianMerge: target_count: 100000, output_filename: 'applemerged', opacity_threshold: 0.1, k: 16, backend: 'nanogs_cpu', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.merge_gaussians.GaussianMerge.merge\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=6 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] Loading PLY: /home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/input/apple.ply\n [ComfyUI] [worker:ComfyUI-GaussianPack] Initial splats: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruned splats: 200000, target: 100000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Opacity Mean: 0.53443545 Median: 0.48362076\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruning splats with opacity below 0.1000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Original count: 200000, after opacity pruning: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] After opacity pruning, 200000 splats remain.\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 1: 200000 splats\n Frame 2 saved (frame_001.jpg, t=2.2s)\n [capture-periodic] freeze=2ms shot=83ms unfreeze=5ms saved=True\n [ComfyUI] \n [ComfyUI] Edge costs: 0%| | 0/19 [00:00<?, ?it/s]\n Frame 3 saved (frame_002.jpg, t=4.4s)\n [ComfyUI] Edge costs: 5%|\u258c | 1/19 [00:00<00:02, 6.46it/s]\n [capture-periodic] freeze=3ms shot=87ms unfreeze=3ms saved=True\n [ComfyUI] Edge costs: 11%|\u2588 | 2/19 [00:00<00:02, 5.94it/s]\n [ComfyUI] Edge costs: 16%|\u2588\u258c | 3/19 [00:00<00:02, 5.77it/s]\n [ComfyUI] Edge costs: 21%|\u2588\u2588 | 4/19 [00:00<00:02, 5.92it/s]\n [ComfyUI] Edge costs: 26%|\u2588\u2588\u258b | 5/19 [00:00<00:02, 6.02it/s]\n [ComfyUI] Edge costs: 32%|\u2588\u2588\u2588\u258f | 6/19 [00:01<00:02, 5.95it/s]\n [ComfyUI] Edge costs: 37%|\u2588\u2588\u2588\u258b | 7/19 [00:01<00:02, 5.90it/s]\n [ComfyUI] Edge costs: 42%|\u2588\u2588\u2588\u2588\u258f | 8/19 [00:01<00:01, 5.99it/s]\n [capture-loop] iter=50 t=5.7s state={'complete': False, 'error': None, 'executedCount': 0, 'wsState': 1} eval_ms=3 ram=2.5/15.6GB (16%) swap=0.0/3.0GB (0%) cpu=32% browser_rss=0.86GB\n [ComfyUI] Edge costs: 47%|\u2588\u2588\u2588\u2588\u258b | 9/19 [00:01<00:01, 6.09it/s]\n [ComfyUI] Edge costs: 53%|\u2588\u2588\u2588\u2588\u2588\u258e | 10/19 [00:01<00:01, 6.10it/s]\n [ComfyUI] Edge costs: 58%|\u2588\u2588\u2588\u2588\u2588\u258a | 11/19 [00:01<00:01, 6.12it/s]\n [ComfyUI] Edge costs: 63%|\u2588\u2588\u2588\u2588\u2588\u2588\u258e | 12/19 [00:01<00:01, 6.17it/s]\n [ComfyUI] Edge costs: 68%|\u2588\u2588\u2588\u2588\u2588\u2588\u258a | 13/19 [00:02<00:00, 6.23it/s]\n [ComfyUI] Edge costs: 74%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258e | 14/19 [00:02<00:00, 6.27it/s]\n [ComfyUI] Edge costs: 79%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2589 | 15/19 [00:02<00:00, 6.35it/s]\n [ComfyUI] Edge costs: 84%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258d | 16/19 [00:02<00:00, 6.32it/s]\n [ComfyUI] Edge costs: 89%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2589 | 17/19 [00:02<00:00, 6.30it/s]\n [ComfyUI] Edge costs: 95%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258d| 18/19 [00:02<00:00, 6.38it/s]\n [ComfyUI] Edge costs: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 19/19 [00:02<00:00, 6.35it/s]\n [ComfyUI] [worker:ComfyUI-GaussianPack] edges: 1848776, pairs: 96906 (need 100000)\n [ComfyUI] [worker:ComfyUI-GaussianPack] Merging 96906 pairs\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 2: 103094 splats\n [ComfyUI] \n [ComfyUI] Edge costs: 0%| | 0/10 [00:00<?, ?it/s]\n [ComfyUI] Edge costs: 10%|\u2588 | 1/10 [00:00<00:01, 6.99it/s]\n [ComfyUI] Edge costs: 20%|\u2588\u2588 | 2/10 [00:00<00:01, 6.93it/s]\n [ComfyUI] Edge costs: 30%|\u2588\u2588\u2588 | 3/10 [00:00<00:01, 6.98it/s]\n [ComfyUI] Edge costs: 40%|\u2588\u2588\u2588\u2588 | 4/10 [00:00<00:00, 6.92it/s]\n [ComfyUI] Edge costs: 50%|\u2588\u2588\u2588\u2588\u2588 | 5/10 [00:00<00:00, 6.83it/s]\n [capture-loop] iter=100 t=11.2s state={'complete': False, 'error': None, 'executedCount': 0, 'wsState': 1} eval_ms=3 ram=2.4/15.6GB (16%) swap=0.0/3.0GB (0%) cpu=33% browser_rss=0.86GB\n [ComfyUI] Edge costs: 60%|\u2588\u2588\u2588\u2588\u2588\u2588 | 6/10 [00:00<00:00, 6.71it/s]\n [ComfyUI] Edge costs: 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 7/10 [00:01<00:00, 6.70it/s]\n [ComfyUI] Edge costs: 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 8/10 [00:01<00:00, 6.74it/s]\n [ComfyUI] Edge costs: 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:01<00:00, 6.85it/s]\n [ComfyUI] Edge costs: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:01<00:00, 7.43it/s]\n [ComfyUI] [worker:ComfyUI-GaussianPack] edges: 919857, pairs: 3094 (need 3094)\n [ComfyUI] [worker:ComfyUI-GaussianPack] Merging 3094 pairs\n [ComfyUI] [worker:ComfyUI-GaussianPack] Final splats: 100000\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianMerge done (14.64s): result: dict\n [ComfyUI] [comfy-env] Running PreviewGaussianDual: layout: 'slider', camera_mode: 'orbit', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path_1: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa..., ply_path_2: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian_dual.PreviewGaussianDual.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=7 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussianDual done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 14.66 seconds\u001b[0m\n Node executed (2 total), capturing...\n Frame 4 saved (frame_003.jpg, t=15.0s)\n [capture-node] freeze=2ms shot=101ms unfreeze=0ms saved=True\n Execution complete (t=15.0s)\n [3d-wait] Phase 1: Waiting for 'Loading 3D Model' text to disappear...\n [3d-wait] Phase 1 done in 0.0s\n [3d-wait] Phase 2: iframes=1\n [3d-wait] iframe viewer_ready=False (matched 0 console logs)\n [3d-wait] Waiting for 'Loaded successfully' console message (timeout=60s)...\n [3d-wait] iframe wait exception: Timeout 60000ms exceeded while waiting for event \"console\"\n=========================== logs ===========================\nwaiting for event \"console\"\n============================================================\n [3d-wait] Total 3D wait: 62.2s\n Captured 4 unique frames over 77.35s\n [debug] iframes: 1\n [debug] iframe[0]: src=http://127.0.0.1:41884/extensions/ComfyUI-GaussianPack/viewer_gaussian_dual.html, canvas=486x240, rafFrozen=True\n [timing] trigger_3d_previews: 0.0s\n Saved high-quality screenshot: merge_splats_executed.png\n [timing] final_screenshot: 0.2s\n Captured 5 video frames", "hardware": {"os": "Linux-6.17.0-1015-azure-x86_64-with-glibc2.39", "cpu": "AMD EPYC 7763 64-Core Processor"}}, "rotate_splats": {"src": "screenshots/rotate_splats_executed.png", "title": "rotate_splats", "status": "pass", "duration": "70.36", "log": "Capturing execution frames: rotate_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"18\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 18: TransformGaussian\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"rotate_x\": -90, \"rotate_y\": 0, \"rotate_z\": 0, \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 869a66a1-b7e2-41f2-991e-1fae9c1a04bc\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: failed\n [ComfyUI] [ComfyUI-GaussianPack] Socket unhealthy, restarting worker...\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_1c2607df29c7']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_1c2607df29c7 (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=8 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.60s): result: list[1]\n [ComfyUI] [comfy-env] Running TransformGaussian: rotate_x: -90.0, rotate_y: 0.0, rotate_z: 0.0, ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.transform_gaussian.TransformGaussian.transform\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=9 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] TransformGaussian done (0.39s): result: list[1]\n [ComfyUI] [comfy-env] Running PreviewGaussianDual: layout: 'slider', camera_mode: 'orbit', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path_1: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa..., ply_path_2: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian_dual.PreviewGaussianDual.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=10 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussianDual done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 2.00 seconds\u001b[0m\n Node executed (1 total), capturing...\n Frame 2 saved (frame_001.jpg, t=2.3s)\n [capture-node] freeze=26ms shot=194ms unfreeze=0ms saved=True\n Execution complete (t=2.3s)\n [3d-wait] Phase 1: Waiting for 'Loading 3D Model' text to disappear...\n [3d-wait] Phase 1 done in 0.0s\n [3d-wait] Phase 2: iframes=1\n [3d-wait] iframe viewer_ready=False (matched 0 console logs)\n [3d-wait] Waiting for 'Loaded successfully' console message (timeout=60s)...\n [3d-wait] iframe wait exception: Timeout 60000ms exceeded while waiting for event \"console\"\n=========================== logs ===========================\nwaiting for event \"console\"\n============================================================\n [3d-wait] Total 3D wait: 60.1s\n Captured 2 unique frames over 62.71s\n [debug] iframes: 1\n [debug] iframe[0]: src=http://127.0.0.1:41884/extensions/ComfyUI-GaussianPack/viewer_gaussian_dual.html, canvas=486x214, rafFrozen=True\n [timing] trigger_3d_previews: 0.0s\n Saved high-quality screenshot: rotate_splats_executed.png\n [timing] final_screenshot: 0.2s\n Captured 3 video frames", "hardware": {"os": "Linux-6.17.0-1015-azure-x86_64-with-glibc2.39", "cpu": "AMD EPYC 7763 64-Core Processor"}}, "spectate": {"src": "screenshots/spectate_executed.png", "title": "spectate", "status": "pass", "duration": "17.75", "log": "Capturing execution frames: spectate.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 2 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"compressed_room.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 2: PreviewGaussians\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"camera_mode\": \"spectate\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 541e47cc-e238-4508-a1cb-f2a8304ff9db\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'compressed_room.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: failed\n [ComfyUI] [ComfyUI-GaussianPack] Socket unhealthy, restarting worker...\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_7f15f9f19225']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_7f15f9f19225 (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=11 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.65s): result: list[1]\n [ComfyUI] [comfy-env] Running PreviewGaussians: camera_mode: 'spectate', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian.PreviewGaussians.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=12 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussians done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 1.66 seconds\u001b[0m\n Node executed (1 total), capturing...\n Frame 2 saved (frame_001.jpg, t=2.1s)\n [capture-node] freeze=2ms shot=83ms unfreeze=0ms saved=True\n Execution complete (t=2.1s)\n [3d-wait] Phase 1: Waiting for 'Loading 3D Model' text to disappear...\n [3d-wait] Phase 1 done in 0.0s\n [3d-wait] Phase 2: iframes=1\n [3d-wait] iframe viewer_ready=False (matched 0 console logs)\n [3d-wait] Waiting for 'Loaded successfully' console message (timeout=60s)...\n [3d-wait] Got 'Loaded successfully' after 1.0s\n [3d-wait] Unfrozen in 0.009s, rendering for 5s...\n [3d-wait] JS halted via CDP after 5.2s\n [3d-wait] Re-frozen in 6.3s\n [3d-wait] Total 3D wait: 7.3s\n Captured 2 unique frames over 9.49s\n [debug] iframes: 1\n [debug] iframe[0]: src=http://127.0.0.1:41884/extensions/ComfyUI-GaussianPack/viewer_gaussian.html?mode, canvas=781x404, rafFrozen=True\n [timing] trigger_3d_previews: 0.0s\n Saved high-quality screenshot: spectate_executed.png\n [timing] final_screenshot: 0.4s\n Captured 3 video frames", "hardware": {"os": "Linux-6.17.0-1015-azure-x86_64-with-glibc2.39", "cpu": "AMD EPYC 7763 64-Core Processor"}}};
const workflowNames = Object.keys(workflowData);
const videoData = {"merge_splats": {"frames": [{"file": "frame_000.jpg", "time": 0.0, "log": "Capturing execution frames: merge_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache."}, {"file": "frame_001.jpg", "time": 2.21, "log": "Capturing execution frames: merge_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 12: GaussianMerge\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"target_count\": 100000, \"output_filename\": \"applemerged\", \"opacity_threshold\": 0.1, \"k\": 16, \"backend\": \"nanogs_cpu\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"12\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 0583cf3f-691e-4509-80fd-c1f4d1f20bb9\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=5 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianMerge: target_count: 100000, output_filename: 'applemerged', opacity_threshold: 0.1, k: 16, backend: 'nanogs_cpu', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.merge_gaussians.GaussianMerge.merge\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=6 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] Loading PLY: /home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/input/apple.ply\n [ComfyUI] [worker:ComfyUI-GaussianPack] Initial splats: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruned splats: 200000, target: 100000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Opacity Mean: 0.53443545 Median: 0.48362076\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruning splats with opacity below 0.1000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Original count: 200000, after opacity pruning: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] After opacity pruning, 200000 splats remain.\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 1: 200000 splats"}, {"file": "frame_002.jpg", "time": 4.44, "log": "Capturing execution frames: merge_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 12: GaussianMerge\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"target_count\": 100000, \"output_filename\": \"applemerged\", \"opacity_threshold\": 0.1, \"k\": 16, \"backend\": \"nanogs_cpu\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"12\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 0583cf3f-691e-4509-80fd-c1f4d1f20bb9\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=5 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianMerge: target_count: 100000, output_filename: 'applemerged', opacity_threshold: 0.1, k: 16, backend: 'nanogs_cpu', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.merge_gaussians.GaussianMerge.merge\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=6 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] Loading PLY: /home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/input/apple.ply\n [ComfyUI] [worker:ComfyUI-GaussianPack] Initial splats: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruned splats: 200000, target: 100000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Opacity Mean: 0.53443545 Median: 0.48362076\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruning splats with opacity below 0.1000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Original count: 200000, after opacity pruning: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] After opacity pruning, 200000 splats remain.\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 1: 200000 splats\n Frame 2 saved (frame_001.jpg, t=2.2s)\n [capture-periodic] freeze=2ms shot=83ms unfreeze=5ms saved=True\n [ComfyUI] \n [ComfyUI] Edge costs: 0%| | 0/19 [00:00<?, ?it/s]"}, {"file": "frame_003.jpg", "time": 15.02, "log": "Capturing execution frames: merge_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 12: GaussianMerge\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"target_count\": 100000, \"output_filename\": \"applemerged\", \"opacity_threshold\": 0.1, \"k\": 16, \"backend\": \"nanogs_cpu\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"12\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 0583cf3f-691e-4509-80fd-c1f4d1f20bb9\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=5 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianMerge: target_count: 100000, output_filename: 'applemerged', opacity_threshold: 0.1, k: 16, backend: 'nanogs_cpu', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.merge_gaussians.GaussianMerge.merge\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=6 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] Loading PLY: /home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/input/apple.ply\n [ComfyUI] [worker:ComfyUI-GaussianPack] Initial splats: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruned splats: 200000, target: 100000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Opacity Mean: 0.53443545 Median: 0.48362076\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pruning splats with opacity below 0.1000\n [ComfyUI] [worker:ComfyUI-GaussianPack] Original count: 200000, after opacity pruning: 200000\n [ComfyUI] [worker:ComfyUI-GaussianPack] After opacity pruning, 200000 splats remain.\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 1: 200000 splats\n Frame 2 saved (frame_001.jpg, t=2.2s)\n [capture-periodic] freeze=2ms shot=83ms unfreeze=5ms saved=True\n [ComfyUI] \n [ComfyUI] Edge costs: 0%| | 0/19 [00:00<?, ?it/s]\n Frame 3 saved (frame_002.jpg, t=4.4s)\n [ComfyUI] Edge costs: 5%|\u258c | 1/19 [00:00<00:02, 6.46it/s]\n [capture-periodic] freeze=3ms shot=87ms unfreeze=3ms saved=True\n [ComfyUI] Edge costs: 11%|\u2588 | 2/19 [00:00<00:02, 5.94it/s]\n [ComfyUI] Edge costs: 16%|\u2588\u258c | 3/19 [00:00<00:02, 5.77it/s]\n [ComfyUI] Edge costs: 21%|\u2588\u2588 | 4/19 [00:00<00:02, 5.92it/s]\n [ComfyUI] Edge costs: 26%|\u2588\u2588\u258b | 5/19 [00:00<00:02, 6.02it/s]\n [ComfyUI] Edge costs: 32%|\u2588\u2588\u2588\u258f | 6/19 [00:01<00:02, 5.95it/s]\n [ComfyUI] Edge costs: 37%|\u2588\u2588\u2588\u258b | 7/19 [00:01<00:02, 5.90it/s]\n [ComfyUI] Edge costs: 42%|\u2588\u2588\u2588\u2588\u258f | 8/19 [00:01<00:01, 5.99it/s]\n [capture-loop] iter=50 t=5.7s state={'complete': False, 'error': None, 'executedCount': 0, 'wsState': 1} eval_ms=3 ram=2.5/15.6GB (16%) swap=0.0/3.0GB (0%) cpu=32% browser_rss=0.86GB\n [ComfyUI] Edge costs: 47%|\u2588\u2588\u2588\u2588\u258b | 9/19 [00:01<00:01, 6.09it/s]\n [ComfyUI] Edge costs: 53%|\u2588\u2588\u2588\u2588\u2588\u258e | 10/19 [00:01<00:01, 6.10it/s]\n [ComfyUI] Edge costs: 58%|\u2588\u2588\u2588\u2588\u2588\u258a | 11/19 [00:01<00:01, 6.12it/s]\n [ComfyUI] Edge costs: 63%|\u2588\u2588\u2588\u2588\u2588\u2588\u258e | 12/19 [00:01<00:01, 6.17it/s]\n [ComfyUI] Edge costs: 68%|\u2588\u2588\u2588\u2588\u2588\u2588\u258a | 13/19 [00:02<00:00, 6.23it/s]\n [ComfyUI] Edge costs: 74%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258e | 14/19 [00:02<00:00, 6.27it/s]\n [ComfyUI] Edge costs: 79%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2589 | 15/19 [00:02<00:00, 6.35it/s]\n [ComfyUI] Edge costs: 84%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258d | 16/19 [00:02<00:00, 6.32it/s]\n [ComfyUI] Edge costs: 89%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2589 | 17/19 [00:02<00:00, 6.30it/s]\n [ComfyUI] Edge costs: 95%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258d| 18/19 [00:02<00:00, 6.38it/s]\n [ComfyUI] Edge costs: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 19/19 [00:02<00:00, 6.35it/s]\n [ComfyUI] [worker:ComfyUI-GaussianPack] edges: 1848776, pairs: 96906 (need 100000)\n [ComfyUI] [worker:ComfyUI-GaussianPack] Merging 96906 pairs\n [ComfyUI] [worker:ComfyUI-GaussianPack] Pass 2: 103094 splats\n [ComfyUI] \n [ComfyUI] Edge costs: 0%| | 0/10 [00:00<?, ?it/s]\n [ComfyUI] Edge costs: 10%|\u2588 | 1/10 [00:00<00:01, 6.99it/s]\n [ComfyUI] Edge costs: 20%|\u2588\u2588 | 2/10 [00:00<00:01, 6.93it/s]\n [ComfyUI] Edge costs: 30%|\u2588\u2588\u2588 | 3/10 [00:00<00:01, 6.98it/s]\n [ComfyUI] Edge costs: 40%|\u2588\u2588\u2588\u2588 | 4/10 [00:00<00:00, 6.92it/s]\n [ComfyUI] Edge costs: 50%|\u2588\u2588\u2588\u2588\u2588 | 5/10 [00:00<00:00, 6.83it/s]\n [capture-loop] iter=100 t=11.2s state={'complete': False, 'error': None, 'executedCount': 0, 'wsState': 1} eval_ms=3 ram=2.4/15.6GB (16%) swap=0.0/3.0GB (0%) cpu=33% browser_rss=0.86GB\n [ComfyUI] Edge costs: 60%|\u2588\u2588\u2588\u2588\u2588\u2588 | 6/10 [00:00<00:00, 6.71it/s]\n [ComfyUI] Edge costs: 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 7/10 [00:01<00:00, 6.70it/s]\n [ComfyUI] Edge costs: 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 8/10 [00:01<00:00, 6.74it/s]\n [ComfyUI] Edge costs: 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:01<00:00, 6.85it/s]\n [ComfyUI] Edge costs: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:01<00:00, 7.43it/s]\n [ComfyUI] [worker:ComfyUI-GaussianPack] edges: 919857, pairs: 3094 (need 3094)\n [ComfyUI] [worker:ComfyUI-GaussianPack] Merging 3094 pairs\n [ComfyUI] [worker:ComfyUI-GaussianPack] Final splats: 100000\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianMerge done (14.64s): result: dict\n [ComfyUI] [comfy-env] Running PreviewGaussianDual: layout: 'slider', camera_mode: 'orbit', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path_1: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa..., ply_path_2: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian_dual.PreviewGaussianDual.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=7 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussianDual done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 14.66 seconds\u001b[0m"}, {"file": "frame_004.jpg", "time": 82.19879198074341, "log": "Final screenshot"}], "total_time": 77.35}, "spectate": {"frames": [{"file": "frame_000.jpg", "time": 0.0, "log": "Capturing execution frames: spectate.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache."}, {"file": "frame_001.jpg", "time": 2.08, "log": "Capturing execution frames: spectate.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 2 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"compressed_room.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 2: PreviewGaussians\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"camera_mode\": \"spectate\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 541e47cc-e238-4508-a1cb-f2a8304ff9db\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'compressed_room.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: failed\n [ComfyUI] [ComfyUI-GaussianPack] Socket unhealthy, restarting worker...\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_7f15f9f19225']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_7f15f9f19225 (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=11 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.65s): result: list[1]\n [ComfyUI] [comfy-env] Running PreviewGaussians: camera_mode: 'spectate', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian.PreviewGaussians.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=12 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussians done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 1.66 seconds\u001b[0m"}, {"file": "frame_002.jpg", "time": 11.915531635284424, "log": "Final screenshot"}], "total_time": 9.49}, "gaussian_analysis": {"frames": [{"file": "frame_000.jpg", "time": 0.0, "log": " [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\nCapturing execution frames: gaussian_analysis.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache."}, {"file": "frame_001.jpg", "time": 2.0, "log": " [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\nCapturing execution frames: gaussian_analysis.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 4 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 19: GaussianAnalysis\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 20: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"compressed_room.ply\"}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 21: GaussianAnalysis\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_path\": [\"20\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: e92f40ff-64a0-434a-ab4c-d4c19153032a\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'compressed_room.ply'\n [ComfyUI] [comfy-env] SubprocessWorker: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [comfy-env] env_vars: {'COMFYUI_BASE': '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI'}\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_878570b9fb5e']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_878570b9fb5e (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=1 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.61s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianAnalysis: ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.analyze_gaussians.GaussianAnalysis.analyze\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=2 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianAnalysis done (0.01s): result: dict\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=3 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (0.01s): result: list[1]\n [ComfyUI] [comfy-env] Running GaussianAnalysis: ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.analyze_gaussians.GaussianAnalysis.analyze\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=4 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] GaussianAnalysis done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 1.64 seconds\u001b[0m"}, {"file": "frame_002.jpg", "time": 4.433459997177124, "log": "Final screenshot"}], "total_time": 2.16}, "rotate_splats": {"frames": [{"file": "frame_000.jpg", "time": 0.0, "log": "Capturing execution frames: rotate_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache."}, {"file": "frame_001.jpg", "time": 2.32, "log": "Capturing execution frames: rotate_splats.json\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Using RAM pressure cache.\n Frame 1 saved (frame_000.jpg, t=0.0s)\n Validating workflow...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === /validate endpoint called ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Received JSON with keys: ['prompt']\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Prompt has 3 nodes\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 1: LoadPLY\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"ply_file\": \"apple.ply\"}\n Queuing workflow for execution...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 14: PreviewGaussianDual\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"layout\": \"slider\", \"camera_mode\": \"orbit\", \"fov_degrees\": 70, \"renderer\": \"playcanvas\", \"transport_format\": \"ply\", \"ply_path_1\": [\"1\", 0], \"ply_path_2\": [\"18\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Node 18: TransformGaussian\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Inputs: {\"rotate_x\": -90, \"rotate_y\": 0, \"rotate_z\": 0, \"ply_path\": [\"1\", 0]}\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Generated prompt_id: 869a66a1-b7e2-41f2-991e-1fae9c1a04bc\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Calling execution.validate_prompt()...\n [ComfyUI] \u001b[32m[INFO]\u001b[0m Validation result: valid=True\n [ComfyUI] \u001b[32m[INFO]\u001b[0m === Validation PASSED ===\n [ComfyUI] \u001b[32m[INFO]\u001b[0m got prompt\n [ComfyUI] [comfy-env] Running LoadPLY: ply_file: 'apple.ply'\n [ComfyUI] [SubprocessWorker] call_method: nodes.load_ply.LoadPLY.load\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: failed\n [ComfyUI] [ComfyUI-GaussianPack] Socket unhealthy, restarting worker...\n [ComfyUI] [ComfyUI-GaussianPack] python: /home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [ComfyUI-GaussianPack] sys_path sent to worker: ['/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack', '/home/runner/.ce/.pixi/envs/gaussianpack-nodes/lib/python3.12/site-packages', '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspaces/GaussianPack-1728/ComfyUI/custom_nodes/ComfyUI-GaussianPack']\n [ComfyUI] [SubprocessWorker] is_pixi=True, python=/home/runner/.ce/.pixi/envs/gaussianpack-nodes/bin/python\n [ComfyUI] [SubprocessWorker] launching cmd=['/home/runner/.pixi/bin/pixi', 'run', '--as-is', '--manifest-path', '/home/runner/.ce/pixi.toml', '-e', 'gaussianpack-nodes', 'python', '/tmp/comfyui_pvenv_wwaqo7fk/persistent_worker.py', 'abstract://comfy_worker_1c2607df29c7']...\n [ComfyUI] [SubprocessWorker] socket_addr=abstract://comfy_worker_1c2607df29c7 (abstract, no filesystem path)\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=8 sending call_method\n [ComfyUI] [worker:ComfyUI-GaussianPack] WARNING: SPZ route not registered (ModuleNotFoundError: No module named 'comfy_aimdo')\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] LoadPLY done (1.60s): result: list[1]\n [ComfyUI] [comfy-env] Running TransformGaussian: rotate_x: -90.0, rotate_y: 0.0, rotate_z: 0.0, ply_path: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.transform_gaussian.TransformGaussian.transform\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=9 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] TransformGaussian done (0.39s): result: list[1]\n [ComfyUI] [comfy-env] Running PreviewGaussianDual: layout: 'slider', camera_mode: 'orbit', fov_degrees: 70.0, renderer: 'playcanvas', transport_format: 'ply', ply_path_1: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa..., ply_path_2: '/home/runner/work/comfy-gpu-ci/comfy-gpu-ci/test_workspa...\n [ComfyUI] [SubprocessWorker] call_method: nodes.preview_gaussian_dual.PreviewGaussianDual.preview\n [ComfyUI] [SubprocessWorker] acquired lock, ensuring started...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ping (timeout=5.0s)...\n [ComfyUI] [ComfyUI-GaussianPack] Health check: ok\n [ComfyUI] [SubprocessWorker] worker started/confirmed\n [ComfyUI] [SubprocessWorker] serializing kwargs to shm...\n [ComfyUI] [SubprocessWorker] created 0 shm blocks\n [ComfyUI] [SubprocessWorker] sending request via socket...\n [ComfyUI] [SubprocessWorker] call_id=10 sending call_method\n [ComfyUI] [SubprocessWorker] got response: ok\n [ComfyUI] [comfy-env] PreviewGaussianDual done (0.01s): result: dict\n [ComfyUI] \u001b[32m[INFO]\u001b[0m \u001b[32mPrompt executed in 2.00 seconds\u001b[0m"}, {"file": "frame_002.jpg", "time": 64.96599745750427, "log": "Final screenshot"}], "total_time": 62.71}};
const inIframe = window !== window.top;
let currentWorkflow = null;
let playInterval = null;
let originalLogContent = '';
let currentFrameIndex = 0;
let currentFrames = [];
let currentTotalTime = 0;
function openLightboxByName(name) {
const w = workflowData[name];
if (w) openLightbox(w.src, w.title, w.status, w.duration, w.log, w.hardware);
}
function openLightbox(src, title, status, duration, logContent, hardware) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-title').textContent = title;
currentWorkflow = title;
originalLogContent = logContent;
const badge = document.getElementById('lightbox-badge');
badge.textContent = status;
badge.className = 'lightbox-badge ' + status;
document.getElementById('lightbox-duration').textContent = duration + 's';
document.getElementById('lightbox-log').textContent = logContent || '(No log available)';
const hwEl = document.getElementById('lightbox-hardware');
if (hardware) {
const parts = [];
if (hardware.os) parts.push(hardware.os);
if (hardware.cpu) parts.push(hardware.cpu);
if (hardware.gpu) parts.push(hardware.gpu);
hwEl.textContent = parts.join(' | ');
} else {
hwEl.textContent = status === 'skipped' ? '(Did not run on this machine)' : '';
}
const data = videoData[title];
const videoPlayer = document.getElementById('video-player');
const lightboxImg = document.getElementById('lightbox-img');
const lightboxVideo = document.getElementById('lightbox-video');
// Reset both modes; the branch below activates one.
videoPlayer.classList.remove('active');
lightboxVideo.style.display = 'none';
lightboxVideo.removeAttribute('src');
lightboxImg.style.display = '';
if (data && data.mp4) {
// Playable mp4 (desktop runs). Show <video>, hide the
// frame-slideshow img + slider.
lightboxVideo.src = 'videos/' + encodeURIComponent(title) + '/' + data.mp4;
lightboxVideo.style.display = '';
lightboxImg.style.display = 'none';
} else if (data && data.frames && data.frames.length > 1) {
currentFrames = data.frames;
currentTotalTime = data.total_time || data.frames[data.frames.length - 1].time;
setupVideoSlider(data.frames, currentTotalTime);
updateVideoFrameByIndex(title, data.frames.length - 1);
videoPlayer.classList.add('active');
}
loadResourceGraph(title);
// Close image overlay if open
closeImgOverlay();
document.getElementById('lightbox').classList.add('active');
history.replaceState(null, '', '#' + encodeURIComponent(title));
// Notify parent frames for deep linking
if (inIframe) {
window.parent.postMessage({ type: 'comfytest-open', name: title }, '*');
}
}
function buildSliderRange(frames, totalTime) {
const range = { 'min': frames[0].time };
frames.forEach((frame, idx) => {
if (idx > 0 && idx < frames.length - 1) {
const pct = (frame.time / totalTime * 100).toFixed(1) + '%';
range[pct] = frame.time;
}
});
range['max'] = frames[frames.length - 1].time;
return range;
}
function setupVideoSlider(frames, totalTime) {
const sliderEl = document.getElementById('video-slider');
if (sliderEl.noUiSlider) {
sliderEl.noUiSlider.destroy();
}
const range = buildSliderRange(frames, totalTime);
noUiSlider.create(sliderEl, {
start: frames[frames.length - 1].time,
snap: true,
range: range,
pips: {
mode: 'range',
density: 100
}
});
sliderEl.noUiSlider.on('update', function(values) {
const time = parseFloat(values[0]);
const frameIdx = frames.findIndex(f => Math.abs(f.time - time) < 0.01);
if (frameIdx >= 0 && frameIdx !== currentFrameIndex) {
currentFrameIndex = frameIdx;
showFrame(currentWorkflow, frameIdx);
}
});
}
function showFrame(workflowName, frameIndex) {
const data = videoData[workflowName];
if (!data || !data.frames) return;
const frame = data.frames[frameIndex];
const img = document.getElementById('lightbox-img');
const isLastFrame = frameIndex === data.frames.length - 1;
if (isLastFrame && workflowData[workflowName] && workflowData[workflowName].src) {
img.src = workflowData[workflowName].src;
} else {
img.src = 'videos/' + workflowName + '/' + frame.file;
}
const counter = document.getElementById('video-frame-counter');
const totalTime = data.total_time || data.frames[data.frames.length - 1].time;
counter.textContent = frame.time.toFixed(1) + 's / ' + totalTime.toFixed(1) + 's';
const logEl = document.getElementById('lightbox-log');
if (frame.log) {
logEl.textContent = frame.log;
logEl.scrollTop = logEl.scrollHeight;
}
}
function updateVideoFrameByIndex(workflowName, frameIndex) {
currentFrameIndex = frameIndex;
showFrame(workflowName, frameIndex);
const sliderEl = document.getElementById('video-slider');
if (sliderEl.noUiSlider && currentFrames[frameIndex]) {
sliderEl.noUiSlider.set(currentFrames[frameIndex].time);
}
}
function toggleVideoPlay() {
const btn = document.getElementById('video-play-btn');
if (playInterval) {
clearInterval(playInterval);
playInterval = null;
btn.innerHTML = '&#9654; Play';
} else {
btn.innerHTML = '&#9632; Stop';
playInterval = setInterval(() => {
if (!currentFrames.length) return;
currentFrameIndex = (currentFrameIndex + 1) % currentFrames.length;
updateVideoFrameByIndex(currentWorkflow, currentFrameIndex);
}, 500);
}
}
let resourceGraphState = null;
async function loadResourceGraph(workflowName) {
const graphContainer = document.getElementById('resource-graph');
const canvas = document.getElementById('resource-canvas');
const gpuLegend = document.getElementById('gpu-legend');
resourceGraphState = null;
try {
const csvResponse = await fetch('logs/' + workflowName + '_resources.csv');
if (!csvResponse.ok) {
graphContainer.classList.remove('active');
return;
}
const text = await csvResponse.text();
const allLines = text.trim().split('\n');
let totalRamGb = 32;
if (allLines[0].startsWith('#')) {
const metaMatch = allLines[0].match(/total_ram_gb=([\d.]+)/);
if (metaMatch) {
totalRamGb = parseFloat(metaMatch[1]);
}
}
const dataLines = allLines.slice(2);
if (dataLines.length < 2) {
graphContainer.classList.remove('active');
return;
}
const data = dataLines.map(line => {
const [t, ram, vram] = line.split(',');
return {
t: parseFloat(t),
ram: parseFloat(ram),
vram: vram ? parseFloat(vram) : null
};
});
const hasVram = data.some(d => d.vram !== null);
gpuLegend.style.display = hasVram ? 'flex' : 'none';
graphContainer.classList.add('active');
await new Promise(r => setTimeout(r, 10));
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
const w = rect.width;
const h = rect.height;
const padding = { top: 10, right: 40, bottom: 20, left: 45 };
const graphW = w - padding.left - padding.right;
const graphH = h - padding.top - padding.bottom;
const maxRam = Math.max(...data.map(d => d.ram), 0.5);
const maxVram = hasVram ? Math.max(...data.filter(d => d.vram !== null).map(d => d.vram), 0.5) : 1;
const maxTime = data[data.length - 1].t;
resourceGraphState = { data, padding, w, h, graphW, graphH, maxRam, maxVram, maxTime, hasVram, dpr };
drawResourceGraph();
} catch (e) {
console.error('Resource graph error:', e);
graphContainer.classList.remove('active');
}
}
function drawResourceGraph(hoverX) {
if (!resourceGraphState) return;
const { data, padding, w, h, graphW, graphH, maxRam, maxVram, maxTime, hasVram, dpr } = resourceGraphState;
const canvas = document.getElementById('resource-canvas');
const ctx = canvas.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.clearRect(0, 0, w, h);
// Grid lines
ctx.strokeStyle = '#1c2d44';
ctx.lineWidth = 0.5;
for (let i = 1; i < 4; i++) {
const y = padding.top + (graphH * i / 4);
ctx.beginPath();
ctx.moveTo(padding.left, y);
ctx.lineTo(w - padding.right, y);
ctx.stroke();
}
// Axes
ctx.strokeStyle = '#243656';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(padding.left, padding.top);
ctx.lineTo(padding.left, h - padding.bottom);
ctx.lineTo(w - padding.right, h - padding.bottom);
ctx.lineTo(w - padding.right, padding.top);
ctx.stroke();
// Left axis: RAM
ctx.fillStyle = '#3fb950';
ctx.font = '9px sans-serif';
ctx.textAlign = 'right';
const ramMax = Math.ceil(maxRam * 10) / 10;
ctx.fillText(ramMax.toFixed(1) + ' GB', padding.left - 3, padding.top + 4);
ctx.fillText('0', padding.left - 3, h - padding.bottom + 4);
// Right axis: VRAM (if present)
if (hasVram) {
ctx.fillStyle = '#d29922';
ctx.textAlign = 'left';
const vramMax = Math.ceil(maxVram * 10) / 10;
ctx.fillText(vramMax.toFixed(1) + ' GB', w - padding.right + 3, padding.top + 4);
ctx.fillText('0', w - padding.right + 3, h - padding.bottom + 4);
}
// Time labels
ctx.fillStyle = '#4a6282';
ctx.textAlign = 'center';
ctx.fillText('0s', padding.left, h - padding.bottom + 12);
ctx.fillText(maxTime.toFixed(0) + 's', w - padding.right, h - padding.bottom + 12);
function drawLine(values, maxVal, color) {
if (values.every(v => v === null || isNaN(v))) return;
ctx.strokeStyle = color;
ctx.lineWidth = 1.5;
ctx.beginPath();
let started = false;
data.forEach((d, i) => {
const val = values[i];
if (val === null || isNaN(val)) return;
const x = padding.left + (d.t / maxTime) * graphW;
const y = padding.top + (1 - val / maxVal) * graphH;
if (!started) { ctx.moveTo(x, y); started = true; }
else { ctx.lineTo(x, y); }
});
ctx.stroke();
}
drawLine(data.map(d => d.ram), ramMax, '#3fb950');
if (hasVram) {
drawLine(data.map(d => d.vram), Math.ceil(maxVram * 10) / 10, '#d29922');
}
// Hover crosshair
if (hoverX !== undefined && hoverX >= padding.left && hoverX <= w - padding.right) {
const timeAtCursor = ((hoverX - padding.left) / graphW) * maxTime;
let closest = data[0], closestDist = Infinity;
for (const d of data) {
const dist = Math.abs(d.t - timeAtCursor);
if (dist < closestDist) { closestDist = dist; closest = d; }
}
const snapX = padding.left + (closest.t / maxTime) * graphW;
// Vertical line
ctx.strokeStyle = 'rgba(230,237,243,0.2)';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(snapX, padding.top);
ctx.lineTo(snapX, h - padding.bottom);
ctx.stroke();
// Readout
ctx.font = '10px sans-serif';
ctx.textAlign = 'left';
const readoutX = snapX + 6;
let readoutY = padding.top + 14;
ctx.fillStyle = '#8ba3c1';
ctx.fillText(closest.t.toFixed(1) + 's', readoutX, readoutY);
readoutY += 13;
ctx.fillStyle = '#3fb950';
ctx.fillText('RAM: ' + closest.ram.toFixed(2) + ' GB', readoutX, readoutY);
readoutY += 13;
if (hasVram && closest.vram !== null) {
ctx.fillStyle = '#d29922';
ctx.fillText('VRAM: ' + closest.vram.toFixed(2) + ' GB', readoutX, readoutY);
}
}
}
// Canvas hover handler
document.getElementById('resource-canvas').addEventListener('mousemove', function(e) {
if (!resourceGraphState) return;
const rect = this.getBoundingClientRect();
drawResourceGraph(e.clientX - rect.left);
});
document.getElementById('resource-canvas').addEventListener('mouseleave', function() {
drawResourceGraph();
});
function closeImgOverlay() {
const overlay = document.getElementById('img-overlay');
overlay.classList.remove('active', 'zoomed');
}
function closeLightbox() {
if (playInterval) {
clearInterval(playInterval);
playInterval = null;
document.getElementById('video-play-btn').innerHTML = '&#9654; Play';
}
closeImgOverlay();
document.getElementById('resource-graph').classList.remove('active');
document.getElementById('lightbox').classList.remove('active');
history.replaceState(null, '', window.location.pathname);
if (inIframe) {
window.parent.postMessage({ type: 'comfytest-close' }, '*');
}
}
document.getElementById('lightbox').onclick = (e) => {
if (e.target.id === 'lightbox') closeLightbox();
};
function navigateLightbox(delta) {
if (workflowNames.length === 0) return;
const idx = workflowNames.indexOf(currentWorkflow);
if (idx === -1) return;
const newIdx = (idx + delta + workflowNames.length) % workflowNames.length;
openLightboxByName(workflowNames[newIdx]);
}
function handleKey(key) {
const overlay = document.getElementById('img-overlay');
if (key === 'Escape') {
if (overlay.classList.contains('active')) {
closeImgOverlay();
} else {
closeLightbox();
}
return;
}
if (document.getElementById('lightbox').classList.contains('active') && !overlay.classList.contains('active')) {
if (key === 'ArrowLeft') { navigateLightbox(-1); }
if (key === 'ArrowRight') { navigateLightbox(1); }
if ((key === 'ArrowUp' || key === 'ArrowDown') && inIframe) {
window.parent.postMessage({
type: 'comfytest-platform-shift',
delta: key === 'ArrowUp' ? -1 : 1,
workflow: currentWorkflow,
}, '*');
}
}
}
document.onkeydown = (e) => {
if (['Escape', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) {
e.preventDefault();
handleKey(e.key);
}
};
// Click lightbox image -> open in fullscreen overlay (fit mode)
document.getElementById('lightbox-img').addEventListener('click', function(e) {
e.stopPropagation();
const overlay = document.getElementById('img-overlay');
const overlayImg = document.getElementById('img-overlay-content');
overlayImg.src = this.src;
overlay.classList.add('active');
overlay.classList.remove('zoomed');
});
// Click overlay image: fit -> zoomed -> close
document.getElementById('img-overlay-content').addEventListener('click', function(e) {
e.stopPropagation();
const overlay = document.getElementById('img-overlay');
if (overlay.classList.contains('zoomed')) {
closeImgOverlay();
} else {
overlay.classList.add('zoomed');
}
});
// Click overlay background -> close overlay
document.getElementById('img-overlay').addEventListener('click', function(e) {
if (e.target === this) closeImgOverlay();
});
function openFromHash() {
const hash = decodeURIComponent(window.location.hash.slice(1));
if (hash && workflowData[hash]) {
const w = workflowData[hash];
openLightbox(w.src, w.title, w.status, w.duration, w.log, w.hardware);
}
}
window.addEventListener('hashchange', openFromHash);
window.addEventListener('load', openFromHash);
// Listen for messages from parent frames
window.addEventListener('message', function(e) {
if (!e.data || !e.data.type) return;
if (e.data.type === 'comfytest-open' && e.data.name) {
openLightboxByName(e.data.name);
}
if (e.data.type === 'comfytest-key') {
handleKey(e.data.key);
}
});
// Detect iframe: hide header and move meta chips into summary
if (inIframe) {
document.body.classList.add('in-iframe');
const chips = document.querySelector('.meta-chips');
const summary = document.querySelector('.summary');
if (chips && summary) {
const wrapper = document.createElement('div');
wrapper.className = 'summary-meta';
while (chips.firstChild) wrapper.appendChild(chips.firstChild);
summary.insertBefore(wrapper, summary.firstChild);
}
}
</script>
</body>
</html>