lllqaq's picture
Add VisPhyWorld static comparator Space
31443df verified
/* global window, document, fetch, navigator */
function el(id) {
const node = document.getElementById(id);
if (!node) throw new Error(`Missing element: ${id}`);
return node;
}
function getSearchParams() {
return new URLSearchParams(window.location.search);
}
function getQueryValue(name) {
return getSearchParams().get(name);
}
function titleCase(text) {
return String(text || "")
.split(/[-_\s]+/)
.filter(Boolean)
.map((part) => part[0].toUpperCase() + part.slice(1))
.join(" ");
}
function clampRate(value) {
const numeric = Number(value);
if (!Number.isFinite(numeric) || numeric <= 0) return 1;
return numeric;
}
function buildAssetUrl(mode, manifest, type, path) {
if (mode === "hub") {
const repo =
type === "gt" ? manifest.repos.gt_dataset : manifest.repos.generated_dataset;
return `https://huggingface.co/datasets/${repo}/resolve/main/${path}`;
}
if (type === "gt") {
return `/data/${path}`;
}
return `/data/sub_generated_videos/${path}`;
}
function isLocalPreviewHost() {
const host = window.location.hostname || "";
return host === "localhost" || host === "127.0.0.1";
}
function detectSourceMode() {
const explicit = getQueryValue("source");
if (explicit === "hub") return "hub";
if (explicit === "local" && isLocalPreviewHost()) return "local";
if (isLocalPreviewHost()) return "local";
return "hub";
}
function sameValue(a, b, epsilon) {
return Math.abs(a - b) <= epsilon;
}
function setVideoSource(video, src) {
if (!src) {
video.removeAttribute("src");
video.load();
return;
}
if (video.dataset.currentSrc === src) return;
video.dataset.currentSrc = src;
video.src = src;
video.load();
}
function createButton(label, active, onClick, className) {
const button = document.createElement("button");
button.type = "button";
button.className = className;
if (active) button.classList.add("active");
button.textContent = label;
button.addEventListener("click", onClick);
return button;
}
function createResultCard(result) {
const article = document.createElement("article");
article.className = "video-card result-card";
article.dataset.engine = result.engine;
article.dataset.model = result.model;
const header = document.createElement("div");
header.className = "card-header";
const badges = document.createElement("div");
badges.className = "badge-stack";
const engineBadge = document.createElement("span");
engineBadge.className = "badge";
engineBadge.textContent = result.engine_label;
badges.appendChild(engineBadge);
const modelBadge = document.createElement("span");
modelBadge.className = "badge badge-secondary";
modelBadge.textContent = result.model_label;
badges.appendChild(modelBadge);
const title = document.createElement("div");
title.className = "card-title";
title.textContent = result.model_label;
const subtitle = document.createElement("div");
subtitle.className = "card-subtitle";
subtitle.textContent = `${result.engine_label} renderer`;
const video = document.createElement("video");
video.controls = true;
video.preload = "metadata";
video.playsInline = true;
video.dataset.role = "result-video";
header.appendChild(badges);
header.appendChild(title);
header.appendChild(subtitle);
article.appendChild(header);
article.appendChild(video);
return { article, video };
}
function parseSetParam(name, validValues) {
const raw = getQueryValue(name);
if (!raw) return null;
const out = new Set();
for (const part of raw.split(",")) {
const item = decodeURIComponent(part).trim();
if (item && validValues.has(item)) out.add(item);
}
return out.size > 0 ? out : null;
}
function setsEqual(left, right) {
if (left.size !== right.size) return false;
for (const item of left) {
if (!right.has(item)) return false;
}
return true;
}
async function loadManifest() {
const response = await fetch("./static/manifest.json", { cache: "no-store" });
if (!response.ok) throw new Error(`Failed to load manifest: ${response.status}`);
return response.json();
}
async function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text);
return true;
}
return false;
}
async function main() {
const manifest = await loadManifest();
const samples = Array.isArray(manifest.samples) ? manifest.samples : [];
if (samples.length === 0) throw new Error("Manifest has no samples");
const allModels = [];
const seenModels = new Set();
for (const engine of manifest.engine_order) {
for (const model of manifest.model_order[engine] || []) {
if (seenModels.has(model)) continue;
seenModels.add(model);
allModels.push(model);
}
}
const engineSet = new Set(manifest.engine_order);
const modelSet = new Set(allModels);
const state = {
samples,
sourceMode: detectSourceMode(),
currentIndex: 0,
syncEnabled: getQueryValue("sync") !== "0",
muted: getQueryValue("muted") !== "0",
propagating: false,
selectedEngines: parseSetParam("engines", engineSet) || new Set(manifest.engine_order),
selectedModels: parseSetParam("models", modelSet) || new Set(allModels),
playbackRate: clampRate(getQueryValue("rate") || "1"),
};
const sampleSelect = el("sample-select");
const sampleSearch = el("sample-search");
const sampleCounter = el("sample-counter");
const sourceLocal = el("source-local");
const sourceHub = el("source-hub");
const sourceNote = el("source-note");
const metaTask = el("meta-task");
const metaSplit = el("meta-split");
const metaResults = el("meta-results");
const metaDetection = el("meta-detection");
const sampleMeta = el("sample-meta");
const gtVideo = el("gt-video");
const gtTitle = el("gt-title");
const comparisonTitle = el("comparison-title");
const resultsSummary = el("results-summary");
const activeFilterSummary = el("active-filter-summary");
const resultsGrid = el("results-grid");
const gtCard = resultsGrid.querySelector(".gt-card");
const emptyState = el("empty-state");
const engineFilters = el("engine-filters");
const modelFilters = el("model-filters");
const presetBar = el("preset-bar");
const syncToggle = el("sync-toggle");
const muteToggle = el("mute-toggle");
const playbackRate = el("playback-rate");
const copyLinkButton = el("copy-link");
playbackRate.value = String(state.playbackRate);
const presetDefinitions = [
{
key: "all",
label: "All",
engines: manifest.engine_order,
models: allModels,
},
{
key: "code",
label: "Code",
engines: ["threejs", "p5js"],
models: allModels.filter((model) => model !== "svd-img2vid" && model !== "sora-2" && model !== "veo31"),
},
{
key: "threejs",
label: "Three.js",
engines: ["threejs"],
models: manifest.model_order.threejs || [],
},
{
key: "p5js",
label: "p5.js",
engines: ["p5js"],
models: manifest.model_order.p5js || [],
},
{
key: "video",
label: "Video",
engines: ["video"],
models: manifest.model_order.video || [],
},
];
function currentSample() {
return state.samples[state.currentIndex];
}
function allVisibleVideos() {
return Array.from(resultsGrid.querySelectorAll("video"));
}
function updateUrlState() {
const params = new URLSearchParams();
params.set("sample", currentSample().id);
params.set("source", state.sourceMode);
if (!setsEqual(state.selectedEngines, new Set(manifest.engine_order))) {
params.set("engines", Array.from(state.selectedEngines).join(","));
}
if (!setsEqual(state.selectedModels, new Set(allModels))) {
params.set("models", Array.from(state.selectedModels).join(","));
}
if (!state.syncEnabled) params.set("sync", "0");
if (!state.muted) params.set("muted", "0");
if (!sameValue(state.playbackRate, 1, 0.001)) {
params.set("rate", String(state.playbackRate));
}
const nextUrl = `${window.location.pathname}?${params.toString()}`;
window.history.replaceState(null, "", nextUrl);
}
function updateSourceButtons() {
const localPreview = isLocalPreviewHost();
sourceLocal.disabled = !localPreview;
sourceLocal.title = localPreview ? "Read local files under /data" : "Local mode is only available in local preview";
sourceLocal.classList.toggle("active", state.sourceMode === "local");
sourceHub.classList.toggle("active", state.sourceMode === "hub");
sourceNote.textContent =
state.sourceMode === "local"
? "Reading videos from this repo under /data. This is the best mode for local inspection."
: localPreview
? "Reading videos from the public Hugging Face datasets. This matches the deployed Space."
: "Reading videos from the public Hugging Face datasets used by this Space.";
}
function updateSyncButtons() {
syncToggle.textContent = `Sync: ${state.syncEnabled ? "On" : "Off"}`;
muteToggle.textContent = `Muted: ${state.muted ? "On" : "Off"}`;
syncToggle.classList.toggle("active", state.syncEnabled);
muteToggle.classList.toggle("active", state.muted);
}
function updateCounter() {
sampleCounter.textContent = `${state.currentIndex + 1}/${state.samples.length}`;
}
function applyPlaybackSettings() {
state.playbackRate = clampRate(playbackRate.value || "1");
for (const video of allVisibleVideos()) {
video.playbackRate = state.playbackRate;
video.defaultPlaybackRate = state.playbackRate;
video.muted = state.muted;
}
}
function propagate(origin, action) {
if (!state.syncEnabled || state.propagating) return;
state.propagating = true;
const videos = allVisibleVideos();
try {
if (action === "play") {
for (const video of videos) {
if (video === origin) continue;
if (!sameValue(video.currentTime, origin.currentTime, 0.08)) {
video.currentTime = origin.currentTime;
}
video.playbackRate = origin.playbackRate;
video.play().catch(() => {
/* ignore autoplay restrictions */
});
}
} else if (action === "pause") {
for (const video of videos) {
if (video === origin) continue;
if (!sameValue(video.currentTime, origin.currentTime, 0.08)) {
video.currentTime = origin.currentTime;
}
video.pause();
}
} else if (action === "seek") {
for (const video of videos) {
if (video === origin) continue;
if (!sameValue(video.currentTime, origin.currentTime, 0.1)) {
video.currentTime = origin.currentTime;
}
}
} else if (action === "rate") {
for (const video of videos) {
if (video === origin) continue;
video.playbackRate = origin.playbackRate;
video.defaultPlaybackRate = origin.playbackRate;
}
}
} finally {
window.setTimeout(() => {
state.propagating = false;
}, 0);
}
}
function bindSync(video) {
video.addEventListener("play", () => propagate(video, "play"));
video.addEventListener("pause", () => propagate(video, "pause"));
video.addEventListener("seeked", () => propagate(video, "seek"));
video.addEventListener("ratechange", () => propagate(video, "rate"));
}
function modelsForEngines(engines) {
const out = new Set();
for (const engine of engines) {
for (const model of manifest.model_order[engine] || []) {
out.add(model);
}
}
return out;
}
function activePresetKey() {
for (const preset of presetDefinitions) {
if (
setsEqual(state.selectedEngines, new Set(preset.engines)) &&
setsEqual(state.selectedModels, new Set(preset.models))
) {
return preset.key;
}
}
return null;
}
function describeFilters() {
const engineSummary =
state.selectedEngines.size === manifest.engine_order.length
? "All engines"
: `${state.selectedEngines.size} engine${state.selectedEngines.size === 1 ? "" : "s"}`;
const modelSummary =
state.selectedModels.size === allModels.length
? "all models"
: `${state.selectedModels.size} model${state.selectedModels.size === 1 ? "" : "s"}`;
return `${engineSummary} · ${modelSummary}`;
}
function setFilterState(engines, models) {
state.selectedEngines = new Set(engines);
state.selectedModels = new Set(models);
renderFilterButtons();
renderSample();
}
function renderFilterButtons() {
const activePreset = activePresetKey();
presetBar.innerHTML = "";
for (const preset of presetDefinitions) {
const button = createButton(
preset.label,
activePreset === preset.key,
() => setFilterState(preset.engines, preset.models),
"preset-btn"
);
presetBar.appendChild(button);
}
engineFilters.innerHTML = "";
for (const engine of manifest.engine_order) {
const button = createButton(
manifest.engine_labels[engine] || titleCase(engine),
state.selectedEngines.has(engine),
() => {
if (state.selectedEngines.has(engine)) state.selectedEngines.delete(engine);
else state.selectedEngines.add(engine);
if (state.selectedEngines.size === 0) state.selectedEngines.add(engine);
renderFilterButtons();
renderSample();
},
"pill-btn"
);
engineFilters.appendChild(button);
}
modelFilters.innerHTML = "";
for (const model of allModels) {
const button = createButton(
manifest.model_labels[model] || titleCase(model),
state.selectedModels.has(model),
() => {
if (state.selectedModels.has(model)) state.selectedModels.delete(model);
else state.selectedModels.add(model);
if (state.selectedModels.size === 0) state.selectedModels.add(model);
renderFilterButtons();
renderSample();
},
"pill-btn"
);
modelFilters.appendChild(button);
}
}
function renderSampleOptions(filterText) {
const normalized = String(filterText || "").trim().toLowerCase();
sampleSelect.innerHTML = "";
let nextSelectedValue = null;
for (const sample of state.samples) {
const haystack = `${sample.id} ${sample.label} ${sample.difficulty} ${
sample.is_3d ? "3d" : "2d"
}`.toLowerCase();
if (normalized && !haystack.includes(normalized)) continue;
const option = document.createElement("option");
option.value = sample.id;
option.textContent = sample.label;
sampleSelect.appendChild(option);
if (sample.id === currentSample().id) nextSelectedValue = sample.id;
}
if (nextSelectedValue) {
sampleSelect.value = nextSelectedValue;
} else if (sampleSelect.options.length > 0) {
sampleSelect.selectedIndex = 0;
}
}
function setSampleByIndex(index) {
state.currentIndex = Math.max(0, Math.min(state.samples.length - 1, index));
sampleSelect.value = currentSample().id;
updateCounter();
renderSample();
}
function renderSampleMeta(sample) {
sampleMeta.innerHTML = "";
const chips = [
{ label: sample.is_3d ? "3D" : "2D", tone: "dimension" },
{ label: sample.difficulty || "unknown", tone: sample.difficulty || "default" },
{ label: `${sample.available_result_count} results`, tone: "count" },
];
for (const chip of chips) {
const span = document.createElement("span");
span.className = `meta-chip ${chip.tone}`;
span.textContent = chip.label;
sampleMeta.appendChild(span);
}
metaTask.textContent = sample.id;
metaSplit.textContent = sample.split || "sub";
metaResults.textContent = `${sample.available_result_count}`;
metaDetection.textContent = sample.detection_json_path ? "available" : "none";
}
function filteredResults(sample) {
return (sample.results || []).filter(
(result) =>
state.selectedEngines.has(result.engine) &&
state.selectedModels.has(result.model)
);
}
function renderSample() {
const sample = currentSample();
const visibleResults = filteredResults(sample);
sampleSelect.value = sample.id;
comparisonTitle.textContent = `${sample.id} · ${sample.is_3d ? "3D" : "2D"} · ${titleCase(sample.difficulty)}`;
gtTitle.textContent = `${sample.id} · Ground Truth`;
activeFilterSummary.textContent = describeFilters();
renderSampleMeta(sample);
setVideoSource(gtVideo, buildAssetUrl(state.sourceMode, manifest, "gt", sample.gt.path));
for (const card of Array.from(resultsGrid.querySelectorAll(".result-card"))) {
card.remove();
}
for (const result of visibleResults) {
const card = createResultCard(result);
setVideoSource(card.video, buildAssetUrl(state.sourceMode, manifest, "generated", result.path));
card.video.muted = state.muted;
card.video.playbackRate = state.playbackRate;
bindSync(card.video);
resultsGrid.appendChild(card.article);
}
if (gtCard && resultsGrid.firstElementChild !== gtCard) {
resultsGrid.insertBefore(gtCard, resultsGrid.firstElementChild);
}
resultsSummary.textContent = `${visibleResults.length} generated · ${sample.available_result_count} total`;
emptyState.hidden = visibleResults.length > 0;
applyPlaybackSettings();
updateUrlState();
}
bindSync(gtVideo);
for (const sample of state.samples) {
const option = document.createElement("option");
option.value = sample.id;
option.textContent = sample.label;
sampleSelect.appendChild(option);
}
const requestedSample = getQueryValue("sample");
if (requestedSample) {
const requestedIndex = state.samples.findIndex((sample) => sample.id === requestedSample);
if (requestedIndex >= 0) {
state.currentIndex = requestedIndex;
}
}
sampleSelect.addEventListener("change", () => {
const nextId = sampleSelect.value;
const nextIndex = state.samples.findIndex((sample) => sample.id === nextId);
if (nextIndex >= 0) setSampleByIndex(nextIndex);
});
sampleSearch.addEventListener("input", () => {
renderSampleOptions(sampleSearch.value);
});
sampleSearch.addEventListener("keydown", (event) => {
if (event.key !== "Enter") return;
const nextId = sampleSelect.value;
const nextIndex = state.samples.findIndex((sample) => sample.id === nextId);
if (nextIndex >= 0) setSampleByIndex(nextIndex);
});
el("prev-sample").addEventListener("click", () => setSampleByIndex(state.currentIndex - 1));
el("next-sample").addEventListener("click", () => setSampleByIndex(state.currentIndex + 1));
sourceLocal.addEventListener("click", () => {
if (!isLocalPreviewHost()) return;
state.sourceMode = "local";
updateSourceButtons();
renderSample();
});
sourceHub.addEventListener("click", () => {
state.sourceMode = "hub";
updateSourceButtons();
renderSample();
});
syncToggle.addEventListener("click", () => {
state.syncEnabled = !state.syncEnabled;
updateSyncButtons();
updateUrlState();
});
muteToggle.addEventListener("click", () => {
state.muted = !state.muted;
updateSyncButtons();
applyPlaybackSettings();
updateUrlState();
});
playbackRate.addEventListener("change", () => {
applyPlaybackSettings();
updateUrlState();
});
el("play-all").addEventListener("click", () => {
for (const video of allVisibleVideos()) {
video.play().catch(() => {
/* ignore autoplay restrictions */
});
}
});
el("pause-all").addEventListener("click", () => {
for (const video of allVisibleVideos()) {
video.pause();
}
});
el("restart-all").addEventListener("click", () => {
for (const video of allVisibleVideos()) {
video.currentTime = 0;
video.pause();
}
});
el("reset-filters").addEventListener("click", () => {
setFilterState(manifest.engine_order, allModels);
});
el("random-sample").addEventListener("click", () => {
const nextIndex = Math.floor(Math.random() * state.samples.length);
setSampleByIndex(nextIndex);
});
copyLinkButton.addEventListener("click", async () => {
const copied = await copyToClipboard(window.location.href).catch(() => false);
const original = "Copy link";
copyLinkButton.textContent = copied ? "Copied" : "Copy failed";
window.setTimeout(() => {
copyLinkButton.textContent = original;
}, 1200);
});
document.addEventListener("keydown", (event) => {
if (event.key === "ArrowLeft") setSampleByIndex(state.currentIndex - 1);
if (event.key === "ArrowRight") setSampleByIndex(state.currentIndex + 1);
});
renderSampleOptions("");
renderFilterButtons();
updateSourceButtons();
updateSyncButtons();
updateCounter();
renderSample();
}
window.addEventListener("DOMContentLoaded", () => {
main().catch((error) => {
console.error(error);
document.body.innerHTML = `<pre style="padding:24px;font:14px/1.5 monospace;">${String(
error && error.stack ? error.stack : error
)}</pre>`;
});
});