Merge remote-tracking branch 'origin/pr1201' into codex/cctv-shared-batch-20261019

This commit is contained in:
Said committed 2026-10-19 13:51:25 +01:00
commit 695cce967d
3 files changed
+33 -8

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
- Draw CCTV stills at their source aspect on the monitor plane instead of
stretching them to the 16:9 canvas. Most DOT cameras publish 4:3 frames, so
every still was widened; they are now centered and pillarboxed on the dark
the placeholder already ends on (Danielslay86, #1201).
+1 -1
View File
@@ -4378,7 +4378,7 @@ silently demoting every later lookup for the session.
- **FIRMS**: no ground clamping (zero 3D-tiles height sampling), ≤18 screen-decluttered ambient labels, click-to-inspect detail card, 2.5k/3k sprite budgets viewport-clipped by FRP.
- **CCTV v2 foundation:** a pitched
frustum wireframe (4 corner rays + far-cap rectangle) with a monitor plane at the frustum's
far cap, retargeting the existing video/canvas texture pipeline. Manual calibration only —
far cap, retargeting the existing video/canvas texture pipeline. Stills are drawn at their source aspect, centered on the placeholder dark (`#01070c`), instead of being stretched to the 16:9 canvas. Manual calibration only —
auto-calibration and the drape mesh pipeline are deleted. A one-shot activation obstruction
probe (`pickFromRay` on camera activation, clamping the plane short of the first hit) remains;
ground placement is superseded by the shared-floor v3 behavior below. Calibration persists to
+28 -7
View File
@@ -12,6 +12,28 @@ import {
PLACEHOLDER_REPAINT_MS,
} from './policy.js';
function fitToProjection(sourceW, sourceH) {
if (!sourceW || !sourceH)
return {
x: 0,
y: 0,
w: PROJECTION_CANVAS_WIDTH,
h: PROJECTION_CANVAS_HEIGHT,
};
const scale = Math.min(
PROJECTION_CANVAS_WIDTH / sourceW,
PROJECTION_CANVAS_HEIGHT / sourceH,
);
const w = Math.round(sourceW * scale);
const h = Math.round(sourceH * scale);
return {
x: Math.round((PROJECTION_CANVAS_WIDTH - w) / 2),
y: Math.round((PROJECTION_CANVAS_HEIGHT - h) / 2),
w,
h,
};
}
export function createFrames({ state: layerState, services, parts, source }) {
/**
* FNV-1a over the RGB channels of a downsampled frame. Pure (takes the raw
@@ -328,19 +350,18 @@ export function createFrames({ state: layerState, services, parts, source }) {
return;
}
runtime.lastFrameSignature = signature;
runtime.ctx.clearRect(
runtime.ctx.fillStyle = '#01070c';
runtime.ctx.fillRect(
0,
0,
PROJECTION_CANVAS_WIDTH,
PROJECTION_CANVAS_HEIGHT,
);
runtime.ctx.drawImage(
runtime.image,
0,
0,
PROJECTION_CANVAS_WIDTH,
PROJECTION_CANVAS_HEIGHT,
const fit = fitToProjection(
runtime.image.naturalWidth,
runtime.image.naturalHeight,
);
runtime.ctx.drawImage(runtime.image, fit.x, fit.y, fit.w, fit.h);
runtime.canvasStamp = (runtime.canvasStamp || 0) + 1;
runtime.lastPlaceholderPaintAt = 0;
}