cutan.characters.validate¶
Whether an art package is one the compiler can actually render.
The artist-facing contract, checked offline. Wave 4 (#78) exists because the previous check had no teeth in two separate ways:
It checked file existence only. A part that was present but drew nothing passed, and then rendered invisibly — the one failure mode with no diagnostic anywhere in the pipeline (
misc/docs/wave4_research.md§4).It returned a bespoke report type, so the orchestrator’s typed-error routing did not apply to any character problem. Findings here are
an.verify._base.Finding, the same type every verifier emits, withir_pathpointing at the file or slot that needs the fix.
Everything here is offline and free: no render, no browser, no network. That is the point — an illustrator should be able to run it before delivering, and a contract they cannot check themselves is a contract that gets them paid for work that cannot land.
Module Attributes
Elements an art package may not contain. |
|
SVG, or raster with the suffixes |
|
Elements that put ink on the canvas. |
|
Severity for a problem that stops the part rendering correctly. |
|
Severity for a problem worth fixing that still renders. |
|
Severity for a fact about the art worth knowing, not a problem. |
|
nothing steps, so its walks glide (the locomotion chain's last link) and nothing reads them. |
|
How far a declared box's aspect may differ from its art's before the containment is worth saying (a rounding of a pixel or two is not). |
Functions
|
A short human-readable rendering, for the CLI. |
The artist-facing spec, generated from the schema and the checks above. |
|
|
Check an art package against the contract, offline. |
- cutan.characters.validate.ADVISORY: str = 'warning'¶
Severity for a problem worth fixing that still renders.
- cutan.characters.validate.BLOCKING: str = 'error'¶
Severity for a problem that stops the part rendering correctly.
- cutan.characters.validate.DECLARED_ASPECT_TOLERANCE: float = 0.01¶
How far a declared box’s aspect may differ from its art’s before the containment is worth saying (a rounding of a pixel or two is not).
- cutan.characters.validate.DRAWABLE_ELEMENTS: frozenset[str] = frozenset({'circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect', 'text', 'use'})¶
Elements that put ink on the canvas. A part containing none of these is blank, whatever else it contains.
- cutan.characters.validate.LEG_PARTS: tuple[str, ...] = ('leg_l', 'leg_r')¶
nothing steps, so its walks glide (the locomotion chain’s last link) and nothing reads them. Required again as soon as a skin draws a leg slot.
- Type:
The required parts a figure with no leg pair leaves out (cutan#35)
- cutan.characters.validate.NOTE: str = 'info'¶
Severity for a fact about the art worth knowing, not a problem.
- cutan.characters.validate.PART_SUFFIXES: tuple[str, ...] = ('.svg', '.png', '.jpg', '.jpeg', '.webp')¶
SVG, or raster with the suffixes
an.stage.rasterreads (an#211). Order is the lookup order for a required part, so an SVG wins when both exist.- Type:
The part file formats an art package may ship
- cutan.characters.validate.PROHIBITED_ELEMENTS: dict[str, str] = {'foreignObject': 'embeds non-SVG content that most rasterisers drop', 'image': 'raster embed; ship the raster as its own part instead (parts/<name>.png, with alpha — an#211)', 'script': 'executable content; a part is a drawing, not a program'}¶
Elements an art package may not contain.
Not a security perimeter — the renderer loads these files into a headless browser we control — but a portability one: each of these makes a part render differently, or not at all, depending on the rasteriser, and a part that depends on script execution is not a drawing.
- cutan.characters.validate.format_report(report, *, name)[source]¶
A short human-readable rendering, for the CLI.
- Return type:
- cutan.characters.validate.render_contract()[source]¶
The artist-facing spec, generated from the schema and the checks above.
Every line here is read out of a live object: the required parts and mouth shapes from
cutan.characters.schema, the slot and attachment layout from a freshly-built descriptor, the prohibitions fromPROHIBITED_ELEMENTS, and the drawable set fromDRAWABLE_ELEMENTS. Nothing is retyped, so the document and the validator cannot disagree.- Return type:
- cutan.characters.validate.validate_character(char_dir, *, name=None)[source]¶
Check an art package against the contract, offline.
Reports a
Findingper problem: a missing or unparseable descriptor, absent required parts or mouth shapes, a part that draws nothing, a prohibited construct, a letterboxed part, a joint name colliding with a part id, and an unpopulatedAssetSource.>>> import tempfile, pathlib >>> with tempfile.TemporaryDirectory() as d: ... report = validate_character(d, name="nobody") >>> report.passed False >>> any("character.json" in f.description for f in report.findings) True- Return type:
VerificationReport