update model
This commit is contained in:
+183
-67
@@ -2549,7 +2549,14 @@ function updateSeatTwin(actuatorState) {
|
||||
}
|
||||
|
||||
const REFERENCE_VEHICLE_ROOT = "/assets/models/byd-tang/";
|
||||
const REFERENCE_VEHICLE_URL = `${REFERENCE_VEHICLE_ROOT}byd-tang-2024.fbx`;
|
||||
const REFERENCE_VEHICLE_ASSET_VERSION = "77a0fae7";
|
||||
const REFERENCE_VEHICLE_LOAD_TIMEOUT_MS = 30000;
|
||||
|
||||
function referenceVehicleAssetUrl(fileName) {
|
||||
return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}?v=${REFERENCE_VEHICLE_ASSET_VERSION}`;
|
||||
}
|
||||
|
||||
const REFERENCE_VEHICLE_URL = referenceVehicleAssetUrl("byd-tang-2024.fbx");
|
||||
|
||||
function referenceMaterialDescriptor(material) {
|
||||
const textureNames = [
|
||||
@@ -3643,73 +3650,92 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
|
||||
reject(new Error("FBXLoader is unavailable"));
|
||||
return;
|
||||
}
|
||||
let settled = false;
|
||||
const settle = (callback, value) => {
|
||||
if (settled) return false;
|
||||
settled = true;
|
||||
window.clearTimeout(timeoutId);
|
||||
callback(value);
|
||||
return true;
|
||||
};
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
settle(
|
||||
reject,
|
||||
new Error(`Reference vehicle load timed out after ${REFERENCE_VEHICLE_LOAD_TIMEOUT_MS} ms`),
|
||||
);
|
||||
}, REFERENCE_VEHICLE_LOAD_TIMEOUT_MS);
|
||||
const manager = new THREE.LoadingManager();
|
||||
manager.setURLModifier((url) => {
|
||||
const cleanUrl = String(url).replaceAll("\\", "/");
|
||||
const cleanUrl = String(url).replaceAll("\\", "/").split(/[?#]/, 1)[0];
|
||||
const fileName = decodeURIComponent(cleanUrl.split("/").pop() || "");
|
||||
if (!/\.(png|jpe?g)$/i.test(fileName)) return url;
|
||||
return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}`;
|
||||
return referenceVehicleAssetUrl(fileName);
|
||||
});
|
||||
const loader = new FBXLoaderClass(manager);
|
||||
loader.setResourcePath(REFERENCE_VEHICLE_ROOT);
|
||||
loader.load(
|
||||
REFERENCE_VEHICLE_URL,
|
||||
(vehicle) => {
|
||||
const normalized = normalizeReferenceVehicle(THREE, vehicle);
|
||||
const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
|
||||
const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
|
||||
const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
|
||||
const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
|
||||
const report = configureReferenceVehicleModel(THREE, vehicle);
|
||||
styleReferencePassiveGlass(THREE, vehicle);
|
||||
const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
|
||||
const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
|
||||
emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
|
||||
const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
|
||||
THREE,
|
||||
vehicle,
|
||||
);
|
||||
vehicleSystems.referenceWindowPanes = referenceWindowPanes;
|
||||
vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
|
||||
vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
|
||||
vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
|
||||
vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
|
||||
applyTwinVehicleTheme(vehicleSystems);
|
||||
vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
|
||||
vehicle.userData.twinRole = "reference_vehicle";
|
||||
vehicle.traverse((object) => object.layers.set(1));
|
||||
scene.add(vehicle);
|
||||
vehicleSystems.fallbackExteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
vehicleSystems.fallbackInteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
|
||||
meshes: report.meshes,
|
||||
size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
|
||||
removedFrontSeatTriangles,
|
||||
windowPanes: Object.fromEntries(
|
||||
Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
|
||||
),
|
||||
frontLampMaterials: referenceFrontLampMaterials.length,
|
||||
frontLampMeshes: referenceFrontLampMeshes.length,
|
||||
frontLampHighlights: referenceFrontLampHighlights.length,
|
||||
frontLampLensOutlines: referenceFrontLampLensOutlines.length,
|
||||
rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
|
||||
rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
|
||||
driverCushion,
|
||||
passengerCushion,
|
||||
}));
|
||||
resolve({ vehicle, report, normalized, driverCushion, passengerCushion });
|
||||
if (settled) return;
|
||||
try {
|
||||
const normalized = normalizeReferenceVehicle(THREE, vehicle);
|
||||
const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
|
||||
const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
|
||||
const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
|
||||
const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
|
||||
const report = configureReferenceVehicleModel(THREE, vehicle);
|
||||
styleReferencePassiveGlass(THREE, vehicle);
|
||||
const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
|
||||
const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
|
||||
emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
|
||||
const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
|
||||
THREE,
|
||||
vehicle,
|
||||
);
|
||||
vehicleSystems.referenceWindowPanes = referenceWindowPanes;
|
||||
vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
|
||||
vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
|
||||
vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
|
||||
vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
|
||||
applyTwinVehicleTheme(vehicleSystems);
|
||||
vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
|
||||
vehicle.userData.twinRole = "reference_vehicle";
|
||||
vehicle.traverse((object) => object.layers.set(1));
|
||||
scene.add(vehicle);
|
||||
vehicleSystems.fallbackExteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
vehicleSystems.fallbackInteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
|
||||
meshes: report.meshes,
|
||||
size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
|
||||
removedFrontSeatTriangles,
|
||||
windowPanes: Object.fromEntries(
|
||||
Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
|
||||
),
|
||||
frontLampMaterials: referenceFrontLampMaterials.length,
|
||||
frontLampMeshes: referenceFrontLampMeshes.length,
|
||||
frontLampHighlights: referenceFrontLampHighlights.length,
|
||||
frontLampLensOutlines: referenceFrontLampLensOutlines.length,
|
||||
rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
|
||||
rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
|
||||
driverCushion,
|
||||
passengerCushion,
|
||||
}));
|
||||
settle(resolve, { vehicle, report, normalized, driverCushion, passengerCushion });
|
||||
} catch (error) {
|
||||
settle(reject, error);
|
||||
}
|
||||
},
|
||||
(event) => {
|
||||
if (!fallback || !event.total) return;
|
||||
@@ -3717,7 +3743,7 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
|
||||
const label = fallback.querySelector("span");
|
||||
if (label) label.textContent = `正在加载整车参考模型 · ${progress}%`;
|
||||
},
|
||||
reject,
|
||||
(error) => settle(reject, error),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -3726,7 +3752,33 @@ function initSeatTwin() {
|
||||
const canvas = $("#seatTwinCanvas");
|
||||
const stage = $("#seatTwin");
|
||||
const fallback = $("#twinFallback");
|
||||
if (!canvas || !stage) return;
|
||||
if (!canvas || !stage || state.seatTwin) return;
|
||||
const stageHasLayout = () => {
|
||||
const bounds = stage.getBoundingClientRect();
|
||||
return stage.isConnected && bounds.width >= 2 && bounds.height >= 2;
|
||||
};
|
||||
if (!stageHasLayout()) {
|
||||
if (stage.dataset.twinInitPending === "true") return;
|
||||
stage.dataset.twinInitPending = "true";
|
||||
let pendingObserver = null;
|
||||
const retryInitialization = () => {
|
||||
if (!stageHasLayout()) return;
|
||||
pendingObserver?.disconnect();
|
||||
window.removeEventListener("resize", scheduleRetry);
|
||||
window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
delete stage.dataset.twinInitPending;
|
||||
initSeatTwin();
|
||||
};
|
||||
const scheduleRetry = () => window.requestAnimationFrame(retryInitialization);
|
||||
if (window.ResizeObserver) {
|
||||
pendingObserver = new ResizeObserver(retryInitialization);
|
||||
pendingObserver.observe(stage);
|
||||
}
|
||||
window.addEventListener("resize", scheduleRetry);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
scheduleRetry();
|
||||
return;
|
||||
}
|
||||
if (!window.THREE) {
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 引擎加载失败,精确状态仍可用</span>';
|
||||
@@ -3735,7 +3787,16 @@ function initSeatTwin() {
|
||||
}
|
||||
|
||||
const THREE = window.THREE;
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
|
||||
let renderer;
|
||||
try {
|
||||
renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
|
||||
} catch (error) {
|
||||
console.error("[vehicle-twin] failed to initialize WebGL", error);
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 渲染器初始化失败,状态数据仍可用</span>';
|
||||
refreshIcons();
|
||||
return;
|
||||
}
|
||||
renderer.autoClear = false;
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
|
||||
if ("outputColorSpace" in renderer) renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
@@ -3883,6 +3944,7 @@ function initSeatTwin() {
|
||||
applyTwinSceneTheme(state.seatTwin);
|
||||
});
|
||||
|
||||
canvas.dataset.referenceModelState = "loading";
|
||||
loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback)
|
||||
.then(({ vehicle, report, normalized, driverCushion, passengerCushion }) => {
|
||||
if (!state.seatTwin) return;
|
||||
@@ -3920,11 +3982,12 @@ function initSeatTwin() {
|
||||
.toArray()
|
||||
.map((value) => value.toFixed(2))
|
||||
.join("x");
|
||||
canvas.dataset.referenceModelLoaded = "true";
|
||||
canvas.dataset.referenceModelState = "loaded";
|
||||
fallback.hidden = true;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("[vehicle-twin] failed to load reference vehicle model", error);
|
||||
canvas.dataset.referenceModelState = "failed";
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>实车模型加载失败,已切换轻量回退模型</span>';
|
||||
refreshIcons();
|
||||
@@ -3940,17 +4003,64 @@ function initSeatTwin() {
|
||||
});
|
||||
}
|
||||
|
||||
let stageWasVisible = false;
|
||||
function resize() {
|
||||
const width = Math.max(1, canvas.clientWidth);
|
||||
const height = Math.max(1, canvas.clientHeight);
|
||||
const width = Math.max(1, Math.round(stage.clientWidth));
|
||||
const height = Math.max(1, Math.round(stage.clientHeight));
|
||||
renderer.setSize(width, height, false);
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
state.seatTwin.narrowViewport = width < 600;
|
||||
}
|
||||
|
||||
new ResizeObserver(resize).observe(stage);
|
||||
resize();
|
||||
function synchronizeTwinViewport({ reset = false } = {}) {
|
||||
if (!stageHasLayout()) {
|
||||
stageWasVisible = false;
|
||||
return false;
|
||||
}
|
||||
resize();
|
||||
if (reset || !stageWasVisible) resetView();
|
||||
stageWasVisible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const scheduleViewportSync = () => {
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
|
||||
synchronizeTwinViewport();
|
||||
}));
|
||||
};
|
||||
if (window.ResizeObserver) {
|
||||
const stageObserver = new ResizeObserver(() => synchronizeTwinViewport());
|
||||
stageObserver.observe(stage);
|
||||
state.seatTwin.resizeObserver = stageObserver;
|
||||
}
|
||||
window.addEventListener("resize", scheduleViewportSync);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
|
||||
canvas.addEventListener("webglcontextlost", (event) => {
|
||||
event.preventDefault();
|
||||
canvas.dataset.contextLost = "true";
|
||||
fallback.hidden = false;
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 上下文已中断,正在等待恢复</span>';
|
||||
refreshIcons();
|
||||
});
|
||||
canvas.addEventListener("webglcontextrestored", () => {
|
||||
delete canvas.dataset.contextLost;
|
||||
synchronizeTwinViewport({ reset: true });
|
||||
const modelState = canvas.dataset.referenceModelState;
|
||||
fallback.hidden = modelState === "loaded";
|
||||
if (modelState === "loading") {
|
||||
fallback.classList.remove("error");
|
||||
fallback.innerHTML = '<i data-lucide="loader-circle"></i><span>正在加载整车参考模型</span>';
|
||||
refreshIcons();
|
||||
} else if (modelState === "failed") {
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>实车模型加载失败,已切换轻量回退模型</span>';
|
||||
refreshIcons();
|
||||
window.setTimeout(() => { fallback.hidden = true; }, 3200);
|
||||
}
|
||||
});
|
||||
synchronizeTwinViewport({ reset: true });
|
||||
stage.addEventListener("pointerdown", (event) => {
|
||||
state.seatTwin.dragging = true;
|
||||
state.seatTwin.pointer = { x: event.clientX, y: event.clientY };
|
||||
@@ -4052,6 +4162,12 @@ function initSeatTwin() {
|
||||
function animate(timestamp = 0) {
|
||||
const twin = state.seatTwin;
|
||||
if (!twin) return;
|
||||
if (!stageHasLayout() || canvas.dataset.contextLost === "true") {
|
||||
stageWasVisible = false;
|
||||
window.requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
if (!stageWasVisible) synchronizeTwinViewport({ reset: true });
|
||||
Object.values(twin.models).forEach((model) => {
|
||||
Object.keys(model.positions).forEach((axis) => {
|
||||
const delta = model.targets[axis] - model.positions[axis];
|
||||
@@ -6556,7 +6672,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
initJointTwinLayout();
|
||||
initResultWorkspace();
|
||||
refreshIcons();
|
||||
initSeatTwin();
|
||||
window.requestAnimationFrame(initSeatTwin);
|
||||
$("#requestForm").addEventListener("submit", submitRequest);
|
||||
$("#utterance").addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
<script src="/vendor/three/0.147.0/fflate.min.js" defer></script>
|
||||
<script src="/vendor/three/0.147.0/FBXLoader.js" defer></script>
|
||||
<script src="/network.js?v=android-pad-1" defer></script>
|
||||
<script src="/app.js?v=dual-seat-80" defer></script>
|
||||
<script src="/app.js?v=dual-seat-81" defer></script>
|
||||
<script type="module" src="/gesture-control.js?v=android-pad-7"></script>
|
||||
<script src="/pwa.js?v=android-pad-1" defer></script>
|
||||
<script src="/console-v2.js?v=desktop-refactor-35" defer></script>
|
||||
<script src="/self-extension.js?v=extension-20" defer></script>
|
||||
<script src="/self-calibration.js?v=calibration-6" defer></script>
|
||||
<script src="/self-repair.js?v=repair-20" defer></script>
|
||||
<script src="/self-repair-seat3d.js?v=repair-18" defer></script>
|
||||
<script src="/self-repair-seat3d.js?v=repair-19" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function viewerHasLayout(viewer) {
|
||||
const bounds = viewer.getBoundingClientRect();
|
||||
return viewer.isConnected && bounds.width >= 2 && bounds.height >= 2;
|
||||
}
|
||||
|
||||
function deferSeat3dUntilVisible(viewer, options) {
|
||||
if (viewer.dataset.seat3dPending === "true") return;
|
||||
viewer.dataset.seat3dPending = "true";
|
||||
let observer = null;
|
||||
const retry = () => {
|
||||
if (!viewerHasLayout(viewer)) return;
|
||||
observer?.disconnect();
|
||||
window.removeEventListener("resize", scheduleRetry);
|
||||
window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
delete viewer.dataset.seat3dPending;
|
||||
initSeat3d(options);
|
||||
};
|
||||
const scheduleRetry = () => window.requestAnimationFrame(retry);
|
||||
if (window.ResizeObserver) {
|
||||
observer = new ResizeObserver(retry);
|
||||
observer.observe(viewer);
|
||||
}
|
||||
window.addEventListener("resize", scheduleRetry);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
scheduleRetry();
|
||||
}
|
||||
|
||||
function initSeat3d(options) {
|
||||
const {
|
||||
canvasId,
|
||||
@@ -15,6 +42,10 @@
|
||||
const canvas = document.getElementById(canvasId);
|
||||
const viewer = document.getElementById(viewerId);
|
||||
if (!canvas || !viewer || viewer.dataset.seat3dInitialized === "true") return;
|
||||
if (!viewerHasLayout(viewer)) {
|
||||
deferSeat3dUntilVisible(viewer, options);
|
||||
return;
|
||||
}
|
||||
viewer.dataset.seat3dInitialized = "true";
|
||||
|
||||
const markReady = (fallback = false) => {
|
||||
@@ -387,6 +418,24 @@
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
let viewerWasVisible = false;
|
||||
function synchronizeViewport({ reset = false } = {}) {
|
||||
if (!viewerHasLayout(viewer)) {
|
||||
viewerWasVisible = false;
|
||||
return false;
|
||||
}
|
||||
resize();
|
||||
if (reset || !viewerWasVisible) resetOrbit();
|
||||
viewerWasVisible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const scheduleViewportSync = () => {
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
|
||||
synchronizeViewport();
|
||||
}));
|
||||
};
|
||||
|
||||
function onHealingState(event) {
|
||||
const detail = event.detail || {};
|
||||
(detail.axes || []).forEach((axis) => {
|
||||
@@ -404,6 +453,11 @@
|
||||
|
||||
function animate() {
|
||||
window.requestAnimationFrame(animate);
|
||||
if (!viewerHasLayout(viewer) || canvas.dataset.contextLost === "true") {
|
||||
viewerWasVisible = false;
|
||||
return;
|
||||
}
|
||||
if (!viewerWasVisible) synchronizeViewport({ reset: true });
|
||||
for (let index = 0; index < current.axes.length; index += 1) {
|
||||
current.axes[index] += (desired.axes[index] - current.axes[index]) * 0.055;
|
||||
}
|
||||
@@ -486,10 +540,23 @@
|
||||
window.addEventListener(stateEvent, onHealingState);
|
||||
window.addEventListener(resetEvent, resetOrbit);
|
||||
|
||||
if (window.ResizeObserver) new ResizeObserver(resize).observe(viewer);
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
resetOrbit();
|
||||
if (window.ResizeObserver) {
|
||||
const resizeObserver = new ResizeObserver(() => synchronizeViewport());
|
||||
resizeObserver.observe(viewer);
|
||||
}
|
||||
window.addEventListener("resize", scheduleViewportSync);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
|
||||
canvas.addEventListener("webglcontextlost", (event) => {
|
||||
event.preventDefault();
|
||||
canvas.dataset.contextLost = "true";
|
||||
viewer.classList.add("context-lost");
|
||||
});
|
||||
canvas.addEventListener("webglcontextrestored", () => {
|
||||
delete canvas.dataset.contextLost;
|
||||
viewer.classList.remove("context-lost");
|
||||
synchronizeViewport({ reset: true });
|
||||
});
|
||||
synchronizeViewport({ reset: true });
|
||||
animate();
|
||||
window.requestAnimationFrame(() => markReady());
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v116";
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v117";
|
||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||
const APP_SHELL = [
|
||||
@@ -6,7 +6,7 @@ const APP_SHELL = [
|
||||
"/index.html",
|
||||
"/styles.css?v=dual-seat-9",
|
||||
"/network.js?v=android-pad-1",
|
||||
"/app.js?v=dual-seat-80",
|
||||
"/app.js?v=dual-seat-81",
|
||||
"/gesture-control.js?v=android-pad-7",
|
||||
"/pwa.js?v=android-pad-1",
|
||||
"/console-v2.css?v=desktop-refactor-106",
|
||||
@@ -17,8 +17,8 @@ const APP_SHELL = [
|
||||
"/self-calibration.js?v=calibration-6",
|
||||
"/self-repair.css?v=repair-21",
|
||||
"/self-repair.js?v=repair-20",
|
||||
"/self-repair-seat3d.js?v=repair-18",
|
||||
"/assets/models/n7_seat.glb",
|
||||
"/self-repair-seat3d.js?v=repair-19",
|
||||
"/assets/models/n7_seat.glb?v=e7f50f03",
|
||||
"/manifest.webmanifest",
|
||||
"/icons/app-icon-192.png",
|
||||
"/icons/app-icon-512.png",
|
||||
|
||||
Reference in New Issue
Block a user