mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
SCENES > VCAM pairs a phone through a QR code and turns it into a handheld camera, after Unreal's Live Link VCAM and Blender's VirtuCamera: - Android Chrome tracks 6DoF through WebXR immersive-ar; iPhone Safari, which has no WebXR AR, tracks rotation through DeviceOrientation, and thumb sticks dolly, truck, crane and pan. - A motion scale (1:1 walk to 1:10000 orbit), smoothing, height and horizon locks, hold/clutch and recenter, none of which make the camera jump. Focal length and scale-aware depth of field with tap-to-focus. - The phone shows the app's render as a monitor (newest-frame JPEG pull). - REC records a take as a version-7 track shot in the selected scene. - The rig claims the camera through the navigation seam (Cockpit refuses it) and holds on any other navigation, scene run or globe input. Pairing never exposes the app: a loopback-only session request starts a separate HTTPS listener (VCAM_PORT, default 4174) that serves only the static phone page and a token-paired relay, and stops after the last session. Its certificate comes from a local CA built with node:crypto, which an iPhone can trust once; without it the phone falls back from WebSocket to HTTPS requests, which iOS allows past a certificate warning. scripts/qa-vcam.mjs drives it end to end: the real phone page over the HTTPS fallback, a scripted 6DoF phone, a recorded and replayed take, depth of field and camera handoff. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_015H1iLusTzWpVKitGic2AW8
40 lines
1.6 KiB
JavaScript
40 lines
1.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { orientationQuaternion } from './orientation.js';
|
|
import { rotateByQuaternion } from '../../../src/vcam/rig.js';
|
|
|
|
const close = (actual, expected, message) =>
|
|
actual.forEach((value, i) =>
|
|
assert.ok(Math.abs(value - expected[i]) < 1e-9, `${message}: ${actual} vs ${expected}`),
|
|
);
|
|
const axes = (q) => ({
|
|
forward: rotateByQuaternion(q, [0, 0, -1]),
|
|
up: rotateByQuaternion(q, [0, 1, 0]),
|
|
});
|
|
|
|
test('an upright portrait phone looks out of its back along the Y-up forward axis', () => {
|
|
// beta 90: stood up from flat, screen toward the user, back toward north.
|
|
const { forward, up } = axes(orientationQuaternion(0, 90, 0, 0));
|
|
close(forward, [0, 0, -1], 'faces north (-z)');
|
|
close(up, [0, 1, 0], 'top edge up');
|
|
});
|
|
|
|
test('alpha turns the phone counterclockwise seen from above', () => {
|
|
const { forward } = axes(orientationQuaternion(90, 90, 0, 0));
|
|
close(forward, [-1, 0, 0], 'faces west');
|
|
});
|
|
|
|
test('a landscape screen reports the picture\'s up, not the device\'s top edge', () => {
|
|
// Rotated a quarter turn counterclockwise: the top edge points west and the
|
|
// right edge up, the back still faces north, and the screen angle is 90.
|
|
const { forward, up } = axes(orientationQuaternion(90, 0, -90, 90));
|
|
close(forward, [0, 0, -1], 'still faces north');
|
|
close(up, [0, 1, 0], 'picture up is world up');
|
|
});
|
|
|
|
test('a phone lying flat, screen up, looks straight down', () => {
|
|
const { forward, up } = axes(orientationQuaternion(0, 0, 0, 0));
|
|
close(forward, [0, -1, 0], 'down');
|
|
close(up, [0, 0, -1], 'top edge toward north');
|
|
});
|