fix: vision verify false 'empty scene' on good models

- CaptureBridge forces gl.render(scene,camera) before toDataURL so the
  screenshot is never a pre-render black frame (root cause of the bogus
  "empty scene" critique + pointless auto-refine).
- Verify prompt is now a pure geometry-fidelity check: never judges/refuses
  on subject matter, biases to matches:true unless empty/broken.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
maverick 2026-07-25 13:38:58 +10:00
parent 00faa800e0
commit 38b419d505
2 changed files with 13 additions and 7 deletions

View file

@ -26,9 +26,15 @@ function Model({ stl }: { stl: ArrayBuffer }) {
// Needs preserveDrawingBuffer on the GL context (set on <Canvas> below). // Needs preserveDrawingBuffer on the GL context (set on <Canvas> below).
function CaptureBridge({ captureRef }: { captureRef: MutableRefObject<(() => string | null) | null> }) { function CaptureBridge({ captureRef }: { captureRef: MutableRefObject<(() => string | null) | null> }) {
const gl = useThree((s) => s.gl); const gl = useThree((s) => s.gl);
const scene = useThree((s) => s.scene);
const camera = useThree((s) => s.camera);
useEffect(() => { useEffect(() => {
captureRef.current = () => { captureRef.current = () => {
try { try {
// Force a synchronous render into the (preserved) drawing buffer right
// before reading it — otherwise toDataURL can grab a pre-render black
// frame on the first/heavy model and the verifier thinks it's empty.
gl.render(scene, camera);
return gl.domElement.toDataURL("image/png"); return gl.domElement.toDataURL("image/png");
} catch { } catch {
return null; return null;
@ -37,7 +43,7 @@ function CaptureBridge({ captureRef }: { captureRef: MutableRefObject<(() => str
return () => { return () => {
captureRef.current = null; captureRef.current = null;
}; };
}, [gl, captureRef]); }, [gl, scene, camera, captureRef]);
return null; return null;
} }

View file

@ -62,15 +62,15 @@ You'll be given a script and the runtime error it threw. Fix the bug and return
// Vision judge. Sees a render of the model and the request; decides if it's a // Vision judge. Sees a render of the model and the request; decides if it's a
// faithful match. Deliberately lenient about style/colour/detail — only flags // faithful match. Deliberately lenient about style/colour/detail — only flags
// clear structural or feature mismatches worth an automatic refine. // clear structural or feature mismatches worth an automatic refine.
export const VERIFY_SYSTEM = `You are Chisel's quality checker. You are shown a 3D render of a CAD model and the user's original request. Judge whether the model is a reasonable, recognizable match for what was asked. export const VERIFY_SYSTEM = `You are Chisel's geometry checker for a CAD tool. You are shown a rendered 3D CAD model and the user's text request. Your ONLY job is to judge whether a solid 3D object is present and its shape is a reasonable structural match for the request.
Be pragmatic, not pedantic: Rules:
- Colour is always red and lighting is neutral IGNORE those. - Treat every model as neutral CAD geometry. Do NOT comment on, judge, or refuse based on what the object represents or depicts subject matter is irrelevant to a shape-fidelity check, and this is a purely visual/geometric comparison.
- Minor proportions, surface finish, and small stylistic choices are fine. - The model is always rendered in solid red on a dark grid. IGNORE colour, lighting, materials, and small stylistic/proportion differences.
- ONLY fail if a requested FEATURE is missing/wrong, the object is unrecognizable, the geometry is clearly broken (holes, stray fragments, collapsed shape), or it's obviously not the requested object. - Return matches:false ONLY if: the scene is genuinely empty (literally no object), the geometry is clearly broken (stray disconnected fragments, collapsed/degenerate shape), or the shape is unrecognizable as anything like the request. When in doubt, return matches:true.
Respond with ONLY a JSON object, no prose, no code fence: Respond with ONLY a JSON object, no prose, no code fence:
{"matches": true|false, "critique": "one sentence — if matches:false, the single most important concrete fix, phrased as an instruction (e.g. 'The handle is missing; add a looped handle on one side.')"}`; {"matches": true|false, "critique": "if matches:false, one sentence with the single most important concrete geometry fix, phrased as an instruction"}`;
export function editContext(previousScript: string): string { export function editContext(previousScript: string): string {
return `Here is the current design script. Edit it per my next message and return the full updated script.\n\n\`\`\`javascript\n${previousScript}\n\`\`\``; return `Here is the current design script. Edit it per my next message and return the full updated script.\n\n\`\`\`javascript\n${previousScript}\n\`\`\``;