105 lines
3.8 KiB
JavaScript
105 lines
3.8 KiB
JavaScript
import { renderEveSurface } from "../packages/eve-browser-lowering/dist/index.js";
|
|
import { compileEveDsl } from "./eve-dsl.js";
|
|
import { findProviderCatalogEntry, mergeProviderAdvertisement } from "./provider-advertisements.mjs";
|
|
|
|
const app = document.querySelector("#app");
|
|
const output = document.querySelector("#eve-layout-probe-output");
|
|
const params = new URLSearchParams(location.search);
|
|
const providerId = params.get("provider") || "gamecult.eve.embedded-demo";
|
|
const fixtureId = params.get("fixture") || providerId;
|
|
|
|
try {
|
|
const provider = await loadProvider(providerId);
|
|
const surfaceEntry = provider.surfaces?.[0];
|
|
if (!surfaceEntry) throw new Error(`${providerId} has no advertised surface`);
|
|
const state = await loadSurface(surfaceEntry);
|
|
renderEveSurface(state, app, {
|
|
activeSurfaceId: state.surface?.id,
|
|
body: document.body,
|
|
clientId: "browser.reference.layout-probe",
|
|
provider,
|
|
source: "web layout probe",
|
|
});
|
|
await animationFrame();
|
|
await animationFrame();
|
|
publishProbe(measureLayout(state, provider, fixtureId));
|
|
} catch (error) {
|
|
publishProbe({
|
|
schema: "gamecult.eve.web_layout_probe.v1",
|
|
runtimeId: "web",
|
|
providerId,
|
|
surfaceId: "",
|
|
fixtureId,
|
|
generatedAt: new Date().toISOString(),
|
|
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
summary: { nodeCount: 0, measuredNodeCount: 0, zeroAreaCount: 0 },
|
|
nodes: [],
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
}
|
|
|
|
async function loadProvider(requestedProviderId) {
|
|
const response = await fetch("./local-provider-catalog.json", { cache: "no-store" });
|
|
const catalog = await response.json();
|
|
const provider = findProviderCatalogEntry(catalog, requestedProviderId);
|
|
if (!provider) throw new Error(`Unknown local provider: ${requestedProviderId}`);
|
|
if (!provider.advertisement) return provider;
|
|
const advertisement = await (await fetch(provider.advertisement, { cache: "no-store" })).json();
|
|
return mergeProviderAdvertisement(provider, advertisement);
|
|
}
|
|
|
|
async function loadSurface(surface) {
|
|
const response = await fetch(surface.url, { cache: "no-store" });
|
|
const source = await response.text();
|
|
if (surface.transport === "local-eve-dsl") return compileEveDsl(source);
|
|
if (surface.transport === "local-json") return JSON.parse(source);
|
|
throw new Error(`Unsupported probe surface transport: ${surface.transport}`);
|
|
}
|
|
|
|
function measureLayout(state, provider, fixture) {
|
|
const nodes = [...document.querySelectorAll("[data-eve-node-id]")].map(element => {
|
|
const rect = element.getBoundingClientRect();
|
|
return {
|
|
nodeId: element.dataset.eveNodeId || "",
|
|
kind: element.dataset.eveKind || "",
|
|
rect: {
|
|
x: round(rect.x),
|
|
y: round(rect.y),
|
|
width: round(rect.width),
|
|
height: round(rect.height),
|
|
},
|
|
};
|
|
}).filter(node => node.nodeId && node.kind);
|
|
const measuredNodeCount = nodes.filter(node => node.rect.width > 0 && node.rect.height > 0).length;
|
|
return {
|
|
schema: "gamecult.eve.web_layout_probe.v1",
|
|
runtimeId: "web",
|
|
providerId: state.providerId || provider.providerId || providerId,
|
|
surfaceId: state.surface?.id || "",
|
|
fixtureId: fixture,
|
|
generatedAt: new Date().toISOString(),
|
|
viewport: {
|
|
width: window.innerWidth,
|
|
height: window.innerHeight,
|
|
},
|
|
summary: {
|
|
nodeCount: nodes.length,
|
|
measuredNodeCount,
|
|
zeroAreaCount: nodes.length - measuredNodeCount,
|
|
},
|
|
nodes,
|
|
};
|
|
}
|
|
|
|
function publishProbe(probeDocument) {
|
|
output.textContent = JSON.stringify(probeDocument, null, 2);
|
|
document.body?.setAttribute?.("data-probe-ready", "true");
|
|
}
|
|
|
|
function animationFrame() {
|
|
return new Promise(resolve => requestAnimationFrame(() => resolve()));
|
|
}
|
|
|
|
function round(value) {
|
|
return Math.round(value * 100) / 100;
|
|
}
|