an.stage.fidelity#

How faithfully a compiled scene reproduces the art it was built from.

Wave 4’s instrument (#9, misc/docs/wave4_research.md §2). One number per sprite: the aspect distortion, the factor by which the compiler’s box disagrees with the art’s own raster about shape.

Why this and not a rendered bounding box#

The obvious instrument — render a frame, find the part’s ink, measure its extents — does not work. Measured on the repo’s own art, the same arm_l render is 2, 4, 6 or 8 px wide depending only on the anti-aliasing threshold chosen, so any tolerance asserted against it is really an assertion about a threshold. The scale ratio below is exact, threshold-free, needs no browser and no render at all, and reads straight off the two numbers that actually decide the shape.

What it measures#

makeSvgSprite sets sprite.width and sprite.height independently (runtime.js:164-165); PixiJS turns each into an independent axis scale. So the sprite’s two scale factors are

sx = box_width / raster_width sy = box_height / raster_height

and the art keeps its shape exactly when sx == sy. PartFidelity.aspect_distortion is max(sx, sy) / min(sx, sy) — 1.0 when the art is respected, and the factor by which it is squashed otherwise.

**The invariant this exists to enforce: aspect ratio is intrinsic to the art, and the compiler may never override it.** A part is placed and uniformly scaled, never stretched to fit a box.

Module Attributes

DFLT_ASPECT_TOLERANCE

Ratios within this of 1.0 count as uniform.

SPRITE_KIND

The visual kind whose art comes from a file and can therefore be distorted.

CONTAIN_FIT

Fit policies, mirroring VisualJSON.fit.

Functions

aspect_findings(scene, *, asset_root[, ...])

Report each non-uniformly scaled sprite as a typed Finding.

part_fidelity(scene, *, asset_root[, tolerance])

Measure every svg_sprite in a compiled scene against its source art.

Classes

PartFidelity(node_path, asset_id, src, box, ...)

One sprite's box, its art's raster, and the disagreement between them.

an.stage.fidelity.CONTAIN_FIT: str = 'contain'#

Fit policies, mirroring VisualJSON.fit.

an.stage.fidelity.DFLT_ASPECT_TOLERANCE: float = 1.000001#

Ratios within this of 1.0 count as uniform. Guards float noise only — it is not a tolerance for “close enough”, which is why it is this tight.

class an.stage.fidelity.PartFidelity(node_path, asset_id, src, box, raster, fit='stretch')[source]#

Bases: object

One sprite’s box, its art’s raster, and the disagreement between them.

property aspect_distortion: float#

The factor by which the art is actually reshaped on screen.

The fit policy is what decides this, not the box. Under contain the runtime scales both axes by one factor, so the art keeps its shape whatever the box says and this is 1.0. Under stretch the box wins on both axes and the disagreement is the distortion.

property box_aspect_disagreement: float#

How far the box’s shape is from the art’s. 1.0 when they agree.

Pure geometry, independent of the fit policy. Under contain this is slack — the art still keeps its shape and the box is simply roomier on one axis — so it is a weaker signal than aspect_distortion, but it is what tells you the compiler is sizing from the art rather than from a constant.

an.stage.fidelity.SPRITE_KIND: str = 'svg_sprite'#

The visual kind whose art comes from a file and can therefore be distorted.

an.stage.fidelity.aspect_findings(scene, *, asset_root, severity='error', tolerance=1.000001)[source]#

Report each non-uniformly scaled sprite as a typed Finding.

Uses the existing finding type so the orchestrator’s error routing applies, and sets ir_path to the scene-graph node path so a fix is routed to the part that needs it.

Return type:

list[Finding]

an.stage.fidelity.part_fidelity(scene, *, asset_root, tolerance=1.000001)[source]#

Measure every svg_sprite in a compiled scene against its source art.

asset_root is the directory a texture’s src is relative to — the staged runtime directory, or the mall’s characters-store root with the characters/ prefix retained.

Sprites whose art cannot be read are skipped rather than guessed at; a missing part is #76’s problem, not this function’s.

Return type:

list[PartFidelity]