- Phone camera or photo -> WebGL shader that classifies every pixel against the sampled screen colour; colour-blind friendly (stripes, motion, words) - Views: Spill, Screen (flat colour), rough live Key, Evenness - Spill = worse of lean toward the screen hue and the green/blue despill limit, tuned on a real Alexa car-interior plate (teal screen, green bounce) - Plain-English verdict incl. widespread colour cast; tap for readouts - Pick screen / pick white (neutral reference), freeze, exposure/WB lock - Service worker caches each /set page under its own path (spill page no longer overwrites the markers page offline); link from /set Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,16 @@ markers_laptop_1920x1080.png # name is optional
|
||||
Kinds: `phone`, `tablet`, `laptop`, `monitor`. Any other PNG shows under "Other".
|
||||
Bump `CACHE` in `public/set/sw.js` when replacing an existing image so phones fetch the new one.
|
||||
|
||||
## On-set spill checker (`/set/spill`)
|
||||
|
||||
Point a phone camera (or load a photo) at a green or blue screen setup. A WebGL shader
|
||||
classifies every pixel against the sampled screen colour and shows spill as stripe
|
||||
patterns plus a plain-English verdict. It is designed for colour-blind use, so it never
|
||||
relies on red vs green. Views: Spill, Screen (keyed area as one flat colour), Key (rough
|
||||
live key with despill) and Evenness (screen brightness bands). "Pick white" sets a
|
||||
neutral reference, like a white balance pick. The code is in `components/set/SpillChecker.tsx`;
|
||||
thresholds are tuned on a real Alexa car-interior plate. The camera needs https.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import SpillChecker from "@/components/set/SpillChecker";
|
||||
|
||||
// On-set green/blue screen spill checker. Like /set, not linked from the site and
|
||||
// kept out of search results and the sitemap.
|
||||
export const metadata: Metadata = {
|
||||
title: "Spill checker",
|
||||
description: "Two Tales VFX on-set green screen spill checker.",
|
||||
robots: { index: false, follow: false },
|
||||
manifest: "/set/manifest.webmanifest",
|
||||
appleWebApp: { capable: true, title: "Spill", statusBarStyle: "black-translucent" },
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#000000",
|
||||
viewportFit: "cover",
|
||||
};
|
||||
|
||||
export default function SpillPage() {
|
||||
return (
|
||||
<main className="h-dvh bg-black">
|
||||
<SpillChecker />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
||||
import Link from "next/link";
|
||||
import type { Kind, MarkerExtra, MarkerScreen } from "@/lib/markers";
|
||||
|
||||
type Mode = "full" | "edge";
|
||||
@@ -362,6 +363,17 @@ export default function MarkerPicker({ screens, extras }: { screens: MarkerScree
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<Link
|
||||
href="/set/spill/"
|
||||
className="mt-8 flex items-center justify-between rounded-xl bg-white/5 px-4 py-4 transition hover:bg-white/10"
|
||||
>
|
||||
<span>
|
||||
<span className="block font-medium">Spill checker</span>
|
||||
<span className="block text-sm text-muted">Point your phone at the green screen setup to find spill</span>
|
||||
</span>
|
||||
<span aria-hidden className="text-xl text-muted">→</span>
|
||||
</Link>
|
||||
|
||||
<p className="mt-10 text-center text-xs leading-relaxed text-muted">
|
||||
Touch is locked while a marker is up · hold the top-left corner 3 s for controls · screen stays awake
|
||||
</p>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+9
-5
@@ -1,4 +1,4 @@
|
||||
// Offline cache for /set (screen markers). Crews often have no signal on set:
|
||||
// Offline cache for /set (screen markers, spill checker). Crews often have no signal on set:
|
||||
// once the page has loaded once, it and every marker image work offline.
|
||||
// Must match OFFLINE_CACHE in components/set/MarkerPicker.tsx
|
||||
const CACHE = "ttvfx-set-v1";
|
||||
@@ -22,16 +22,20 @@ self.addEventListener("fetch", (event) => {
|
||||
const url = new URL(req.url);
|
||||
if (url.origin !== self.location.origin) return;
|
||||
|
||||
// Page: network first so updates arrive, cached copy when offline
|
||||
// Pages (/set/, /set/spill/): network first so updates arrive, cached copy when offline.
|
||||
// Each page is cached under its own path so one never replaces the other.
|
||||
if (req.mode === "navigate") {
|
||||
const page = url.pathname.endsWith("/") ? url.pathname : url.pathname + "/";
|
||||
event.respondWith(
|
||||
fetch(req)
|
||||
.then((res) => {
|
||||
const copy = res.clone();
|
||||
caches.open(CACHE).then((c) => c.put("/set/", copy));
|
||||
if (res.ok) {
|
||||
const copy = res.clone();
|
||||
caches.open(CACHE).then((c) => c.put(page, copy));
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch(() => caches.match("/set/")),
|
||||
.catch(() => caches.match(page).then((hit) => hit || caches.match("/set/"))),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user