mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-22 02:56:52 +03:00
Plates gate refuses a comp crop shipped as a plate; text readings include letter-spacing
From the final review batch: 'bad asset crop (crops are never allowed)' twice, 'letter spacing way too wide'. A crop resampled to the region scores 99.8% structure against the raw region; a produced plate scores 30-60. AI-assisted (Claude Code).
This commit is contained in:
@@ -68,7 +68,8 @@ import { fileURLToPath } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
import { decodePng, loadRaster } from './lib/png.mjs';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { crop, createImage, blit } from './lib/raster.mjs';
|
||||
import { crop, createImage, blit, resize } from './lib/raster.mjs';
|
||||
import { structureScore } from './lib/image-metrics.mjs';
|
||||
import { compare, verdictFor, alignBuild, bestShift } from './comp-diff.mjs';
|
||||
import { textRegionCheck, chromeStripCheck, inventedInk, plateClipCheck } from './lib/hero-checks.mjs';
|
||||
import { SPEC_PATH, BUILD_DIR, loadSpec, plateReference } from './comp-spec.mjs';
|
||||
@@ -294,6 +295,15 @@ export function gatePlates(state, { specPath = SPEC_PATH } = {}) {
|
||||
score = res.whole;
|
||||
const v = plateVerdict(r, score);
|
||||
for (const reason of v.reasons) reasons.push(`plate ${file}: ${reason}`);
|
||||
// A plate that matches the comp crop almost exactly is the comp crop,
|
||||
// upscaled past the size floor: the comp's grain, its neighbours'
|
||||
// edges, and its resolution ship as the artwork. Crops are never
|
||||
// plates; the crop is the reference the plate is generated from.
|
||||
if (!isTexture) {
|
||||
const raw = crop(comp, r.px.x, r.px.y, r.px.w, r.px.h);
|
||||
const same = structureScore(raw, resize(img, raw.width, raw.height));
|
||||
if (same >= 0.95) reasons.push(`plate ${file} is the comp crop of region ${r.id} (structure ${(same * 100).toFixed(0)}% against the raw region, a resample of the same pixels): a crop of the comp is never a plate; generate the plate from the crop as reference (generate-image.mjs --plate ${r.id})`);
|
||||
}
|
||||
}
|
||||
plates.push({ id: r.id, file, status: 'ok', size: `${img.width}x${img.height}`, score: score ? score.overall : null });
|
||||
}
|
||||
|
||||
@@ -74,6 +74,11 @@ export function textRegionCheck(region, compCrop, buildCrop, { capTol = 0.22, mi
|
||||
if (Math.abs(dp) > 0.2) findings.push(`text ${region.id}: line pitch ${Math.round(pb)}px in the build, ${Math.round(pa)}px in the comp (${dp > 0 ? '+' : ''}${Math.round(dp * 100)}%); set line-height so ${comp.lines} lines stand ${Math.round(ba0.h)}px tall`);
|
||||
}
|
||||
}
|
||||
// tracking: the gap between glyphs in cap units, when both sides read it
|
||||
if (comp.gap != null && bfp.gap != null && Math.abs(capDelta) <= capTol && comp.glyphs >= 8 && bfp.glyphs >= 8) {
|
||||
const dg = bfp.gap - comp.gap;
|
||||
if (Math.abs(dg) > Math.max(0.03, comp.gap * 0.5)) findings.push(`text ${region.id}: letter-spacing is ${dg > 0 ? 'wider' : 'tighter'} than the comp's (gap ${bfp.gap.toFixed(3)} vs ${comp.gap.toFixed(3)} of the cap height); set letter-spacing to ${dg > 0 ? 'close' : 'open'} it by about ${Math.abs(Math.round(dg * comp.capHeightPx))}px`);
|
||||
}
|
||||
// weight: compare ink density of tall glyphs when both sides have it and
|
||||
// the sizes agree (density at a different cap is a different reading)
|
||||
if (comp.densTall != null && bfp.densTall != null && Math.abs(capDelta) <= capTol) {
|
||||
|
||||
Reference in New Issue
Block a user