Skip to content

Diagnostics

Search this page for the text you were shown. Each row names what produced the message and what to change. The last column is the page that explains the mechanism behind it.

Two severities exist and nothing sits between them. An error ends its stage with a non-zero exit and writes no output file. A warning is printed and the stage carries on at exit 0. ps2ui-layout --strict promotes every compiler warning to exit 1. ps2ui-check --strict promotes every check warning to exit 1. Neither flag can pick out one rule.

Each stage prefixes its own lines. Placeholders below are written <n>, <name> and <prop>. The rest of every message is verbatim.

$ ps2ui-layout ok.html c2.css --fonts fonts/fonts.json -o x.json
error: css: line 1: border-color: bad color "orange"
$ echo $?
1

HTML parse

html.js raises eleven errors. Ten carry a line <n>: prefix. ps2ui-layout prints each as error: <message> on stderr and exits 1. The parser emits no warnings.

message severity cause fix page
html: line <n>: unexpected end of input in tag error input ends between the tag name and > close the tag HTML
html: line <n>: malformed attribute error an attribute name is empty, such as a leading = or a stray / inside the tag delete the stray character HTML
html: line <n>: attribute <name> must be quoted error = is followed by something other than " or ' quote the value HTML
html: line <n>: unterminated attribute <name> error input ends before the closing quote close the quote HTML
html: line <n>: unterminated comment error <!-- has no --> close the comment HTML
html: line <n>: closing </tag> with no open element error a close tag appears with the stack empty delete the close tag HTML
html: line <n>: closing </tag> but <open> (line <m>) is open error the close tag does not match the innermost open element close the elements in order HTML
html: line <n>: bare "<" in content; write &lt; error < is followed by something that cannot start a tag name write &lt; HTML
html: line <n>: unterminated <tag> error a head, style, script or title element has no close tag close it HTML
html: <tag> opened on line <n> is never closed error the open-element stack is not empty at end of input close the element HTML
html: line <n>: malformed tag <tag> error unreachable; parseAttrs returns only on > or />, and the caller handles both nothing to fix HTML

CSS

css.js raises 30 errors and pushes 6 warnings. An error prints as error: <message> and exits 1. A warning prints as warning: <message> and the compile continues. Every message here carries a line number, and it is the line of the DECLARATION rather than of the rule that holds it.

A compile reports every CSS error it finds, one error: line each, sorted by line. A stylesheet with three mistakes took three builds to clear when each pass stopped at the first.

message severity cause fix page
css: line <n>: unsupported selector syntax near "<c>" in "<s>" error a combinator outside type, .class, #id, *, descendant and :focus rewrite as a descendant selector CSS
css: line <n>: "<s>": :<name> does not exist on this target. plus the sentence naming :focus error a pseudo-class other than :focus; there is no pointer, so no hover, active or visited state exists drop it, or use :focus CSS
css: line <n>: unterminated comment error /* has no */ close the comment CSS
css: line <n>: malformed declaration "<d>" error a declaration with no : add the colon CSS
css: line <n>: selector without a block error the file ends after a selector add the block CSS
css: line <n>: unterminated block error a rule block has no } close the block CSS
css: line <n>: <prop>: "<value>" is not a length error the value does not parse as a length at all write a px length CSS
css: line <n>: <prop>: unitless "<value>" — write "<value>px" error a bare number other than 0 on a px-only property add px CSS
css: line <n>: <prop>: only px supported, got "<value>" error a length in %, em, rem, vw or vh on a px-only property convert to px CSS
css: line <n>: display: only "flex" and "none" exist on this target (got "<value>") error any other display value use flex or none CSS
css: line <n>: overflow: only visible\|hidden (there is no scrolling on a memory card browser) error any other overflow value use hidden and a list window Lists
css: line <n>: <prop>: unknown value "<value>". <prop> takes <set> error a misspelled keyword on one of the eight checked properties spell it from the set the message lists CSS
css: line <n>: <prop>: "<value>" is real CSS that this target does not implement -- <what it would have done>. <prop> takes <set> error space-evenly, baseline, justify, pre, pre-wrap, pre-line, break-spaces pick a value the solver has; the message names the layout it would otherwise have produced CSS
css: line <n>: padding: 1-4 values error five or more values in the shorthand give one to four CSS
css: line <n>: margin: 1-4 values error five or more values in the shorthand give one to four CSS
css: line <n>: border: unsupported token "<token>" (only solid borders exist) error a style keyword other than solid or none in the shorthand write <width> solid <color> CSS
css: line <n>: border-color: bad color "<value>" error the value is not one of the eight names, a hex form, rgb() or rgba() use a supported colour form CSS
css: line <n>: <prop>: bad color "<value>" (flat colors only — gradients are a texture you bake yourself) error the same, on background or background-color bake the gradient as a PNG Images
css: line <n>: color: bad color "<value>" error the same, on color use a supported colour form CSS
css: line <n>: opacity: bad value error parseFloat cannot read the value write a number from 0 to 1 CSS
css: line <n>: :focus may not change "<prop>" — focus is a paint-only delta. Both states share one baked layout; move the geometry to the base rule. error one of the 33 geometry properties inside a :focus rule move it to the base rule CSS
css: line <n>: :focus may not change "<prop>" -- it is read from the base style when the line is emitted, so a value here is parsed, applied and then dropped. Move it to the base rule. error letter-spacing, text-align or text-overflow inside a :focus rule move it to the base rule CSS
css: line <n>: "<selector>" matches <tag> line <n>, but no element in that selector has the focusable attribute, so the :focus delta can never show. Add focusable, or drop the :focus. warning a :focus rule whose element carries no focusable attribute add the attribute, or drop the :focus CSS
css: <tag> line <n>: a :focus rule changes font-weight to <w>, so this text is measured for the heavier face and wraps to <a> lines where the unfocused text alone needs <b>... warning a :focus weight delta on wrapping text whose line count changes under the heavier face widen the box, or move the weight to the base rule CSS
css: line <n>: <name>: "<value>" is not a color, and ps2ui custom properties are colors only -- geometry is baked, so a themeable length would be a different and much larger design error a :root custom property holding anything but a colour bake the geometry instead Theming
css: line <n>: "<head>" -- @theme takes one identifier, e.g. "@theme light". A theme is selected by index at runtime and the name exists so a human can say which index they meant, so an unparseable one is refused rather than numbered error the @theme head is not one identifier starting with a letter name the theme Theming
css: line <n>: unterminated @theme block error the @theme block has no } close the block Theming
css: line <n>: @theme <name> is declared twice error two blocks share one name; reusing root appends -- "root" is the theme :root defines, and it is always index 0 merge the blocks Theming
css: line <n>: @theme <name> { <prop>: ... } -- a theme supplies custom properties and nothing else. Sizes, fonts and layout are baked geometry; a themeable length would be a different and much larger design error an ordinary property inside a theme block move it to a rule Theming
css: line <n>: @theme <name> defines <prop>, which :root does not. A name only reaches a use site through :root, so this value could never be drawn error the theme sets a name :root never defined define it in :root Theming
css: line <n>: @theme <name> sets <prop> twice error one block sets one name twice delete one Theming
css: line <n>: @theme <name>: <prop>: "<value>" is not a color error a theme block's custom property holds a non-colour write a colour Theming
css: line <n>: <prop>: var(<name>, ...) has a fallback. A role is one colour per theme; a fallback is a second value for the same name and there is nothing here to choose between them error a var() fallback delete the fallback Theming
css: line <n>: <prop>: malformed var(<name><rest>) error tokens after the name inside var() and no comma write var(--name) alone Theming
css: line <n>: <prop>: <name> is not defined in :root. Undefined names are refused rather than falling back to a literal, because a theme that cannot reach a colour is exactly the defect this mechanism exists to prevent error a var() name with no :root definition define it in :root Theming
css: line <n>: property "<prop>" not supported on this target; ignored warning a property applyDeclaration has no case for, position included delete it CSS
css: line <n>: at-rule "<name>" ignored warning any at-rule but @theme, body discarded delete it CSS
css: <tag> line <n> sets <prop>: <v>% but its container has no definite <axis>, so the percentage cannot resolve and is treated as auto warning New in 0.7.0. A percentage size whose containing size is indefinite, such as the main axis of a shrink-to-fit row; 0.6.0 resolved it to auto and said nothing give the container a definite size on that axis, or state the size in px CSS
css: <tag> line <n> sets overflow: hidden with border-radius: <r>px; the clip is a rectangle, so children are cut at the square edge and the rounded corners only cover the background behind them warning New in 0.7.0. One box sets both; either alone is silent. 0.6.0 clipped square and said nothing drop the radius, or drop the clip and size the children to fit CSS
css: line <n>: ":root { <prop>: ... }" is ignored -- :root defines custom properties on this target, not inherited style warning an ordinary property inside :root move it to a rule Theming
css: line <n>: custom property "<name>" outside :root is ignored -- ps2ui resolves names globally, so an element-scoped value would silently mean the :root one warning a --name declared on any other selector move it into :root Theming
css: line <n>: @theme <name> does not set <prop> (defined at line <m>), so it keeps the :root value -- a theme that covers some of the palette recolours some of the screen warning the theme omits a name :root defines set it, or accept the :root value Theming
css: line <n>: <prop>: "<token>" is a literal in a sheet that declares a theme, so no theme can move it -- name it in :root, or leave it if staying fixed is deliberate warning a colour literal on color, background, background-color, border-color or border in a themed sheet name it in :root Theming

Layout

box.js, the flex solver and the display-list builder produce these. An error prints as error: <message> and exits 1. A warning prints as warning: <message>. Two rows are unreachable from any sheet, and are listed so a search for them ends here.

message severity cause fix page
layout: <tag> line <n>: data-slot needs a name error data-slot="" name the slot Dynamic text
layout: <tag> line <n>: a data-slot element must contain exactly one text node (the placeholder), no child elements error the slot element has an element child or no child hold one text node Dynamic text
layout: data-slot "<name>" placeholder wraps to <n> lines — slots are single-line; add white-space: nowrap or widen the box error the placeholder does not fit on one line add white-space: nowrap or widen the box Dynamic text
layout: duplicate data-slot name "<name>" error two slots in one document share a name rename one, or add {i} under a repeat Dynamic text
layout: <img> on line <n> has no src attribute (or data-tex-slot, for a slot the app fills at runtime) error an <img> with neither attribute add src or data-tex-slot Images
layout: <img src="<src>"> on line <n>: relative path but no asset base — compile from files (compileFiles) or pass options.assetDir error a relative src compiled from strings compile from files Images
image: cannot read "<path>": <code> error the file named by src cannot be opened fix the path Images
image: "<path>" is not a PNG — only PNG is supported at build time; convert other formats before compiling error the 8-byte PNG signature does not match convert to PNG Images
image: "<path>": malformed PNG (IHDR not first chunk) error the first chunk is not IHDR re-encode the file Images
image: "<path>": zero-sized PNG error the IHDR width or height is 0 re-encode the file Images
layout: <img> on line <n>: data-tex-slot needs a name with no leading or trailing whitespace — it is how the app addresses the slot at runtime, matched byte for byte, and "<value>" would not match what it reads here error the attribute value has surrounding whitespace trim the name Images
layout: <img> on line <n>: data-tex-slot="<name>" and src are mutually exclusive — a slot is either baked from a file or filled at runtime, and carrying both would leave it ambiguous which one the console draws error both attributes on one <img> keep one Images
layout: <img> on line <n>: palettize is not supported on a streamed slot — quantizing needs the art, which does not exist until runtime. Supply PSMCT32 texels to ps2ui_tex_set error palettize on a data-tex-slot element delete palettize Images
layout: <img data-tex-slot="<name>"> needs an explicit width and height — a streamed slot has no file to take its intrinsic size from, and the reservation is sized from these error a streamed slot with no CSS width and height set both Images
layout: <tag> line <n>: nested focusable inside another focusable — the D-pad model has one focus ring; flatten the hierarchy. error focusable inside another focusable's subtree flatten the markup Focus and navigation
layout: <tag> line <n>: data-repeat on the root element has nothing to repeat into; put it on a child error data-repeat on the document root move it to a child Lists
layout: <tag> line <n>: data-repeat="<raw>" is not a whole number. The count is baked, so it cannot come from data. error the count does not match /^\d+$/ write a decimal integer Lists
layout: <tag> line <n>: data-repeat="<n>" is out of range 1..256. Every copy costs commands, and a focusable one costs a focus node, so this is a budget you want to feel. error a count of 0, or above 256 lower the count Lists
layout: <tag> line <n>: data-repeat inside data-repeat. Only one index is in scope, so the inner {i} would be ambiguous. error a repeat inside a repeat subtree write the inner rows out Lists
layout: root element is display: none error the root element resolves to display: none give it display: flex CSS
layout: <n> container(s) lay out two or more children without stating flex-direction: then one <tag> line <n> (<m> children) per offender, then There is no default. CSS's initial value is row, ps2ui once used column, so either silent answer is wrong for half of all authors — add flex-direction: row or column to each. error a container with two or more children and no flex-direction declaration declare flex-direction on each named container CSS
no font metrics at <path>. then five remedy lines naming ps2ui-fontgen, --font-dir and --fonts error --font-dir points at a directory missing default.metrics.json or default-bold.metrics.json generate the metrics, or pass --fonts Text and fonts
<path>: cannot be read as a fonts.json manifest (<reason>). It maps "regular" and "bold" to { ttf: [...], metrics: "..." }; ps2ui-bake reads the same file. error --fonts names a file JSON.parse rejects fix the manifest Text and fonts
<path>: no "<face>" face with a "metrics" path. Generate one with: ps2ui-fontgen <font.ttf> default <400\|700> <out.metrics.json> error the manifest has no metrics for that face add the metrics key Text and fonts
layout: internal: <what> has <n> theme values, expected <m> error reachable from a sheet that declares @theme and defines no :root custom property add one :root name Theming
layout: internal: <what> carries the name <var> but no per-theme values -- a themed colour resolved through a path that did not carry the vector error unreachable; resolveColorValue sets the name and the vector together at every return nothing to fix Theming
bad direction <dir> error unreachable; findTarget is called only from the four-entry direction loop nothing to fix Focus and navigation
warning: unknown attribute: <tag> line <n>: <attr> is not read by anything, then — did you mean <known>? or — known: <sorted list> warning a data- attribute outside the six the compiler reads; one line per typo correct the spelling HTML
layout: <tag> line <n>: data-repeat="<n>" but no {i} or {n} anywhere inside, so every copy is identical. Add {i} to the ids and data-slot names, or the copies cannot be told apart. warning a count above 1 with no index substitution in the subtree add {i} to the ids and slot names Lists
focus: "<name>" is unreachable from the initial focus by D-pad warning the breadth-first walk from initial never reaches that node move the element, or pass --focus-wrap Focus and navigation

| layout: canvas <axis> <n> exceeds 2048, the largest framebuffer dimension the GS can scan out. plus the mode list and the canvasDim override | error, exit 1 | --canvas or a project canvas past 2048 on either axis | pick a real mode, or raise "limits": {"canvasDim": N} | The project file | | layout: more than <n> elements after data-repeat expansion. plus the largest shipped screen and the nodes override | error, exit 1 | a screen with more elements than the cap after data-repeat expands, so a runaway repeat or a generated file | fix the repeat, or raise "limits": {"nodes": N} | The project file | | layout: elements nested <n> deep (deepest at line <l>), past the limit of <m>. plus the deepest shipped screen and the depth override | error, exit 1 | nesting past the cap; the line names the deepest element, and the check is iterative so it reports instead of overflowing | flatten the nesting, or raise "limits": {"depth": N} | The project file |

Lints

lint.js pushes ten warnings over eight rule names. Each prints as warning: <rule>: <message> and leaves the exit code at 0. A lint from a theme row above 0 is prefixed @theme <name>:. data-nocontrast is the only per-rule opt-out, and it silences contrast alone.

message severity cause fix page
aspect-distortion: <n> rounded corner(s) draw <p>% <wider\|narrower> than tall at PAR <par>; divide the radius by <par> to look round warning abs(par - 1) > 0.08 and at least one rect has a radius divide the radius by the PAR CRT linter
aspect-distortion: <n> image(s) draw <p>% <wider\|narrower> than tall at PAR <par>; pre-squash the art or set an explicit width warning the same PAR test, with at least one image command pre-squash the art CRT linter
interlace-flicker: 1px line at (<x>,<y>) will shimmer on an interlaced CRT; use 2px warning border-width: 1px, or a filled rect one pixel tall use 2px CRT linter
ntsc-red-bleed: saturated red fill rgb(<r>,<g>,<b>) at (<x>,<y>) smears on composite video warning a fill with r > 200, g < 80 and b < 80 desaturate the fill CRT linter
min-font-size: "<text>" is <n>px; below <m>px is unreadable from a couch warning a text command below the floor, 14px by default raise font-size, or pass --min-font-size CRT linter
overscan: text "<text>" at (<x>,<y>) leaves the title-safe area; a CRT may crop it warning the text origin sits inside the 5 percent inset, or its baseline runs past the bottom inset move the text inward CRT linter
charset: codepoint U+<hex> in "<text>": non-Latin text wrapping is untested warning the first codepoint above U+24FF outside the five allowed blocks keep to the shipped charset Text and fonts
contrast: "<text>" contrast <r>:1 < <m>:1<, over a <bright\|dark> frame showing through the <p>%-transparent background> — CRTs crush shadows harder than your monitor warning the WCAG ratio against the composited background is below 3.0 recolour the text or its background, or set data-nocontrast CRT linter
focus-target-size: focusable "<name>" is <w>x<h>px; smaller than 24px is hard to see highlighted from 3 meters warning a focusable narrower or shorter than 24px enlarge the focusable CRT linter
overscan: focusable "<name>" extends past the action-safe area warning the focusable's rect leaves the canvas; the message names an inset the check never computes shrink the focusable CRT linter

Bake

ps2ui-bake prints error: <message> for the IR and cap refusals. It prints ps2ui-bake: <message> for anything it caught as an exception. Every refusal happens before the first write, so no .uib appears. Compiler warnings carried in the IR are re-printed as warning (layout <stem>): <message>.

$ ps2ui-bake deep.json -o deep.uib --fonts fonts/fonts.json
  runtime tables: 0 textures, 0 CLUTs, 0 slots, 1 screens
error: scissor nesting: 9 levels reaches PS2UI_MAX_SCISSOR_DEPTH = 8. ps2ui_render has a fixed stack and cannot report an overflow, so the deepest subtree would draw under its parent's clip instead of its own. Flatten the nesting or raise PS2UI_MAX_SCISSOR_DEPTH in runtime/ps2ui.h.
$ echo $?
1
message severity cause fix page
error: <path>: IR version <n>, expected 1 error an IR file the compiler did not write, or a stale one recompile the screen ps2ui-bake
error: duplicate screen name '<stem>' (file stems must be unique) error two IR paths share a file stem rename one IR file ps2ui-bake
ps2ui-bake: no font manifest. The built-in default is the repository's fonts/fonts.json, which only exists in a checkout. plus a template and two remedy lines error no --fonts and no fonts/fonts.json three directories above the package write a manifest and pass --fonts ps2ui-bake
ps2ui-bake: <path>: no such fonts.json. It maps "regular" and "bold" to {ttf: [...], metrics: "..."}; generate the metrics with ps2ui-fontgen, and ps2ui-layout reads the same file via --fonts. error --fonts names a file that does not exist fix the path ps2ui-bake
ps2ui-bake: fonts.json: no candidate TTF for '<face>' exists: [...] error every ttf candidate for that face is missing add a path that exists Text and fonts
ps2ui-bake: '<key>' error the manifest is missing a key the loader indexes, such as ttf add the key ps2ui-bake
ps2ui-bake: the IR and the font manifest describe different fonts: then one line per mismatch and a remedy line error the compiler measured with one face and the baker would draw another pass one manifest to both commands ps2ui-bake
ps2ui-bake: image: cannot decode '<src>': <reason> error the file passed the PNG header check and Pillow still refuses it re-encode the file Images
ps2ui-bake: image: '<src>' is an indexed PNG at <w>x<h> but is laid out at <w>x<h>. Indexed sources are baked verbatim to preserve their palette, which resizing cannot do. Author it at the laid-out size, or remove `palettize` to have it requantized instead. error palettize on an indexed PNG whose file size differs from its laid-out size author it at the laid-out size Images
ps2ui-bake: image: streamed slot '<name>' is laid out at <w>x<h> in one place and <w>x<h> in another; a slot has one reservation, so give them the same size or different names error one data-tex-slot name at two sizes match the sizes, or split the names Images
ps2ui-bake: screen '<name>': canvas <a> differs from <b> — all screens share one video mode error two IR files baked together carry different canvases compile every screen at one mode ps2ui-bake
ps2ui-bake: unknown IR command op: <op> error an IR command the flattener has no case for recompile the screen ps2ui-bake
ps2ui-bake: slot name '<name>' is on screen '<a>' and screen '<b>'; slot names resolve over the whole file, so only the first would ever be reachable from the app error two screens in one bake declare one slot name prefix the names per screen Dynamic text
ps2ui-bake: slot "<name>": letter-spacing <n>px does not fit the format's i16 field (-32768..32767px). If this is not a typo, the .uib slot entry is the thing to change. error letter-spacing on a slot outside the i16 range use a plausible value Dynamic text
error: scissor nesting: <n> levels reaches PS2UI_MAX_SCISSOR_DEPTH = 8. ps2ui_render has a fixed stack and cannot report an overflow, so the deepest subtree would draw under its parent's clip instead of its own. Flatten the nesting or raise PS2UI_MAX_SCISSOR_DEPTH in runtime/ps2ui.h. error eight or more nested overflow: hidden boxes on one screen flatten the nesting ps2ui-bake
error: <textures\|slots\|screens\|cluts>: <n> does not fit the format's uint16 count field. This is the format's own limit, not a runtime one. error a table longer than 65535 entries split the blob ps2ui-bake
error: slot '<name>': capacity <n> does not fit the format's uint16 capacity field. error data-slot-capacity above 65535 lower the capacity Dynamic text
error: texture VRAM footprint exceeds budget (see breakdown above; override with --vram-budget) error the page-rounded texture total is over the budget printed above it palettize, shrink the art, or raise the budget VRAM budget
warning: '<src>' is an indexed PNG at <w>x<h> laid out at <w>x<h>; --palettize-images requantized it, so its authored palette and index values did not survive. Author it at the laid-out size to keep them. warning --palettize-images met an indexed PNG at the wrong size author it at the laid-out size Images
warning (layout <stem>): <message> warning a warning the compiler recorded in that IR file fix the compiler warning ps2ui-bake
tint vector has <n> themes, expected <m> error a writer invariant; the compiler refuses a short vector first nothing to fix Theming
tint vector row 0 <rgba> does not match the colour it belongs to <rgba> error a writer invariant on the live row nothing to fix Theming
more than 65536 distinct tints error the interned tint table passes the uint16 index ceiling reuse colours through var() names Theming
channel <n> outside 0..255 error a host-side colour crossing was handed a value outside the sRGB byte range nothing to fix ps2ui-bake
GS alpha <n> outside 0..128 error the inverse crossing was handed a value outside the GS alpha domain nothing to fix Previewer

| error: image: <src> is <w>x<h> = <n> pixels, past the limit of <m>. plus the drawn size and the imagePixels override | error, exit 1 | a source image whose pixel count is past the cap. Read from the PNG header, before any decode, so a decompression bomb costs a stat | scale the asset down, or raise "limits": {"imagePixels": N} | The project file | | error: image: <src> is too large to decode: <detail> | error, exit 1 | Pillow's own decompression-bomb guard, reported in the baker's voice instead of a traceback | scale the asset down | Images | | the two framebuffer-arithmetic lines, then error: canvas <w>x<h> cannot be scanned out of GS VRAM | error, exit 1 | a canvas whose framebuffers alone exceed VRAM. Checked separately from the budget, because the budget charges textures and a framebuffer is not a texture, so no --vram-budget reaches this | use a canvas the GS can scan out | VRAM budget |

Check

ps2ui-check writes TAP on stdout. A passed check is ok <n> - <label>. A failed warning is ok <n> - <label> # TODO warning. A failed error is not ok <n> - <label>. A blob it cannot read produces no TAP at all: one ps2ui-check: <path>: <message> line on stderr and exit 2.

$ ps2ui-check --vram-budget 1 examples/memcard/build/ui.uib | sed -n '/not ok/p'
not ok 60 - VRAM 160 KiB within budget 0 KiB
message severity cause fix page
ps2ui-check: <path>: truncated header error, exit 2 the file is shorter than the 84-byte header rebake ps2ui-check
ps2ui-check: <path>: not a .uib (magic 0x<n>) error, exit 2 the first four bytes are not 0x31424955 check the path ps2ui-check
ps2ui-check: <path>: version <n>, expected 7 error, exit 2 a blob from another format version rebake with this toolchain Compatibility
ps2ui-check: <path>: unknown feature bits 0x<n> error, exit 2 a feature bit outside the known 0x1F rebake with this toolchain Errors and constants
ps2ui-check: <path>: crc mismatch (file 0x<a>, computed 0x<b>) error, exit 2 the file was edited or truncated after the bake rebake ps2ui-check
ps2ui-check: <path>: truncated (blob extends past EOF) error, exit 2 the header's blob extent runs past the file rebake ps2ui-check
ps2ui-check: <path>: n_theme is 0 (a themeless blob still has one row) error, exit 2 the theme count is zero rebake Theming
ps2ui-check: <path>: <n> themes without FEAT_ROLE_TINTS -- tints keyed on the resolved colour cannot diverge between themes error, exit 2 more than one theme row with bit 4 clear rebake Theming
ps2ui-check: <path>: <kind> <i> <which> index <n> is past the <m>-entry tint table error, exit 2 a command or slot points outside the tint table rebake ps2ui-check
ps2ui-check: <path>: the <table> table (<n> entries at offset <off>) runs past the end of the <size>-byte file error, exit 2 a header count or offset puts a table beyond the file; ps2ui_load refuses the same blob with PS2UI_ERR_TRUNCATED rebake Errors and constants
ps2ui-check: <path>: the <table> table is at offset <off>, not a multiple of 4; the runtime refuses it (PS2UI_ERR_ALIGN) error, exit 2 a table the runtime would read at an address a 32-bit load faults on rebake Errors and constants
ps2ui-check: <path>: font <i>'s <glyph\|kern> table (<n> entries at blob offset <off>) runs past the <size>-byte blob, or ... is at blob offset <off>, not a multiple of 4; the runtime refuses it (PS2UI_ERR_ALIGN) error, exit 2 a font's glyph or kern array outside the blob, or where a 32-bit load faults rebake Errors and constants
ps2ui-check: <path>: texture <i> has format <n>; the runtime reads only PSMCT32 and PSMT8 error, exit 2 a texture format the runtime refuses with PS2UI_ERR_BOUNDS rebake Errors and constants
not ok <n> - <label> error one of the catalogue's structural checks failed; the label names the invariant and lists the offending indices follow the label ps2ui-check
ok <n> - <label> # TODO warning warning one of the three CRT checks failed: hairlines, dead commands, undrawn textures fix the geometry, or declare the count ps2ui-check
not ok <n> - VRAM <u> KiB within budget <b> KiB plus -- the default budget is unusable at this canvas, see notes under an impossible default error the blob's texture total is over the budget palettize, shrink the art, or set vramBudget VRAM budget
ok <n> - <m> <noun>, but <k> declared deliberate (--allow-<dead\|hairline>): <k> of the instruments that count names is gone, and the check can no longer see what it measures # TODO warning warning --allow-dead and --allow-hairline are exact counts, so fewer than declared warns too set the flag to the count the blob has ps2ui-check

Project and CLI

ps2ui prints ps2ui: <message> and exits 1 for every project failure. ps2ui serve is the exception and prints ps2ui serve: <message>. An argparse rejection exits 2 from any subcommand. ps2ui-layout, ps2ui-dev and ps2ui-fontgen answer a malformed command line with a usage line and exit 2.

message severity cause fix page
ps2ui: <path>: no such project file. plus four lines showing the two required keys error the path names no ps2ui.json write the project file ps2ui
ps2ui: <path>: not valid JSON -- <parser message> error the project file does not parse fix the JSON The project file
ps2ui: <path>: this is a .uib blob, not a project file. plus two lines naming ps2ui-check and spelling the command out error a baked blob was handed to ps2ui check, which takes a project; the first four bytes are UIB1 run ps2ui-check <blob> instead ps2ui-check
ps2ui: <path>: not a project file -- it is not UTF-8 text, so it cannot be a ps2ui.json. plus three lines showing the two required keys error the path names a binary file that is not a blob either point it at a ps2ui.json The project file
ps2ui: <path>: the top level must be an object error the file holds a list or a scalar wrap it in an object The project file
ps2ui: <path>: unknown key(s) '<k>'. then A project takes: <every key> error a misspelt or invented top-level key use a key from the list The project file
ps2ui: <path>: "screens" is required and must not be empty error screens is absent or empty name at least one screen The project file
ps2ui: <path>: "screens" must be a list error screens holds something else write a list The project file
ps2ui: screens[<i>] is <repr>; a screen is a path, or an object with "html" and optionally "css" or "focusWrap" error a screen entry is neither a string nor an object write a path or an object The project file
ps2ui: screens[<i>] has unknown key(s) '<k>'; a screen takes css, focusWrap, html error a misspelt key on a screen entry use one of the three The project file
ps2ui: screens[<i>] has no "html" error a screen object with no markup path add html The project file
ps2ui: screens[<i>] (<html>) has no stylesheet: set "css" at the top level for every screen, or on this one error neither the project nor the screen names a stylesheet set css The project file
ps2ui: no fonts for this project: <path> does not exist. plus the ps2ui fontgen line that writes one error, exit 1 ps2ui build or ps2ui dev on a project whose font manifest does not exist, with no fallback beside the package run ps2ui fontgen <regular.ttf> <bold.ttf>, or point fonts in ps2ui.json at a manifest you have ps2ui-fontgen
ps2ui: cannot find ps2ui-layout, which compiles the HTML and CSS. plus three remedy lines error no PS2UI_LAYOUT, no ps2ui-layout on PATH and no checkout beside the package install @ophtml/layout, or set PS2UI_LAYOUT ps2ui
ps2ui: ps2ui-layout failed on <html> (exit <n>) error the compiler refused that screen and already said why fix what the compiler printed ps2ui
ps2ui: <path>: no blob to check. Run `ps2ui build` first -- this does not build, so that a check can never report on a blob it just made and nobody has seen. error ps2ui check ran before any build run ps2ui build ps2ui
ps2ui: no screen named '<name>' in ps2ui.json. It has: <names> error ps2ui dev --screen names a screen the project lacks use a listed name ps2ui
ps2ui: ps2ui dev watches one screen and this project has <n>. Name one: ps2ui dev --screen <name>, where <name> is one of: <names> error ps2ui dev on a multi-screen project with no --screen pass --screen ps2ui
ps2ui: <files> in <dir> <differ\|differs> from the runtime this toolchain ships, so nothing was written. plus the mixed-pair explanation error ps2ui vendor-runtime found an edited ps2ui.c or ps2ui.h in the destination pass --force, or move your copy aside ps2ui
ps2ui: two copies of the runtime disagree, so this will not guess which one you meant. plus the two paths and a rebuild line error a staged package-data runtime is out of date against the checkout rebuild the package, or delete the staged directory ps2ui
ps2ui: no C runtime to vendor. plus the two directories looked in and a packaging note error an installed wheel shipped without its runtime install from the sdist ps2ui
ps2ui-fontgen: this Pillow has no Raqm layout engine, so kerning cannot be extracted; refusing to write a metrics file without it. plus a platform-specific remedy error, exit 2; 0.8.0 and earlier only those releases measured through Pillow's Raqm, and PIL.features.check("raqm") is false pip install --upgrade ophtml: 0.9.0 has no such check Installation
usage: python -m ps2ui_bake.fontgen <font.ttf> <family> <weight> <out.metrics.json> [charset-file] error, exit 2 fewer than four positional arguments pass all four ps2ui-fontgen
ps2ui-fontgen: needs the uharfbuzz package, which `pip install ophtml` installs. From a checkout, install it yourself: pip install uharfbuzz error, exit 1 a checkout run without uharfbuzz; an installed ophtml always has it pip install uharfbuzz ps2ui-fontgen
usage: ps2ui-layout <page.html> <page.css> -o <ui.json> [--mode ntsc\|ntsc16x9\|pal\|pal16x9] [--display-aspect W:H] [--canvas WxH] [--font-dir DIR] [--fonts fonts.json] [--focus-wrap] [--strict] [--min-font-size PX] [--limit NAME=N] [--version] error, exit 2 a missing positional, a missing -o, an unknown --mode, a --canvas that is not WxH, or a --limit that is not NAME=N for a cap this compiler has correct the command line ps2ui-layout
ps2ui-layout: --min-font-size takes a positive integer error, exit 2 --min-font-size given zero or a non-number pass a positive integer CRT linter
ps2ui-layout: --strict: <n> warning(s) error, exit 1 --strict and at least one warning in the IR fix the warnings CRT linter
usage: ps2ui-dev <page.html> <page.css> -o <outdir> [--mode ntsc\|pal] [--canvas WxH] [--font-dir DIR] [--fonts fonts.json] [--focus-wrap] [--strict] [--min-font-size PX] [--limit NAME=N] [--montage] [--palettize-images] [--once] [--version] error, exit 2 the same argument faults, in the watcher correct the command line ps2ui-dev
bake failed error, exit 1 under --once ps2ui-dev compiled the screen and the bake step returned non-zero read the baker's own line above it ps2ui-dev
aspect: "<text>" is not a ratio like 4:3 or 16:9 error, exit 1 --display-aspect given anything but <digits>:<digits>; printed as a Node stack trace, not an error: line write 4:3 or 16:9 Video modes
aspect: "<text>" has a zero term error, exit 1 --display-aspect given a zero numerator or denominator; also a stack trace write a non-zero ratio Video modes

| ps2ui-layout: --limit takes NAME=N, got "<text>" (and the same from ps2ui-dev) | error, exit 2 | a --limit argument with no =, or nothing before it | write NAME=N | ps2ui-layout | | ps2ui-layout: --limit: unknown cap "<name>". Known: canvasDim, nodes, depth (and the same from ps2ui-dev) | error, exit 2 | a cap name this compiler does not have, including a misspelling | use a name from the list | ps2ui-layout | | ps2ui-layout: --limit <name> takes a positive integer, got "<text>" (and the same from ps2ui-dev) | error, exit 2 | a value that is not an integer, or is below 1. A cap of 0 is a typo rather than "no limit" | pass a positive integer | ps2ui-layout | | error: --limit takes NAME=N, got '<text>' | error, exit 2 | the same shape fault, on ps2ui-bake | write NAME=N | ps2ui-bake | | error: --limit: unknown cap '<name>'. Known: canvasDim, depth, imagePixels, nodes | error, exit 2 | a cap name no tool has. The list is every cap the project file takes, not just this tool's | use a name from the list | ps2ui-bake | | error: --limit <name> is a layout cap and ps2ui-layout enforces it; this tool enforces imagePixels. plus the ps2ui build route | error, exit 2 | a real cap, spelled correctly, passed to the tool that does not enforce it | set it in the project file, or pass it to ps2ui-layout | The project file | | error: --limit imagePixels takes a positive integer, got '<text>' | error, exit 2 | a bad value for the one cap ps2ui-bake enforces | pass a positive integer | ps2ui-bake |

Previewer

ps2ui serve refuses before or at the bind, printing ps2ui serve: <message> with exit 1 from both ps2ui serve and python -m ps2ui_bake.serve. Once it is running, a bad /input body is answered with HTTP 400 and a JSON {"error": ...} body, and the server stays up. The ps2ui_bake.preview module raises ValueError to Python callers.

message severity cause fix page
ps2ui serve: no screen named '<name>'. The blob has: <names> error --screen names a screen the blob lacks use a listed name Previewer
ps2ui serve: no theme <n>; the blob has <m> error --theme is at or past the tint table's row count pass a row that exists Previewer
ps2ui serve: the first build failed, so there is nothing to serve: then the pipeline's summary line error the project did not compile on the first pass fix what the compiler printed to the terminal Previewer
ps2ui serve: watch mode compiles HTML and CSS, which needs the Node half. plus three remedy lines error no compiler is reachable and no --uib was given install @ophtml/layout, or pass --uib Previewer
ps2ui serve: port <n> is already in use. plus two lines saying an explicit port is not moved error --port named a port something else holds; naming one turns the walking off drop --port, or name a free one Previewer
ps2ui serve: ports <a>-<b> are all busy error every port from 8080 to 8099 is taken pass --port Previewer
{"error": "no recognised field in ['<k>', ...]"} error, HTTP 400 a /input body with none of key, screen, theme, aspect, slot post one recognised field Previewer
{"error": "'<name>'"} error, HTTP 400 /input named a screen the blob lacks; the body is the bare value post a screen the blob carries Previewer
{"error": "<n>"} error, HTTP 400 /input named a theme row past the end post a row that exists Previewer
{"error": "'<mode>'"} error, HTTP 400 /input named an aspect outside the four modes post framebuffer, authored, force-4:3 or force-16:9 Previewer
no screen named '<name>' error preview.render(uib, screen=...) was given a name the blob lacks pass an index or a real name Previewer
theme <n> is past the <m>-row tint table error preview.render(uib, theme=...) was given a row past the end pass a row that exists Theming
offset (<x>, <y>) does not fit the int16 pair on the context; ps2ui_offset_set returns PS2UI_ERR_RANGE for this error preview.render(uib, offset=...) was given a value outside int16 stay inside the int16 range Moving and hiding
slot '<name>': <n> bytes of texels for a <w>x<h> PSMCT32 reservation (<m> B). ps2ui_tex_set would return PS2UI_ERR_SIZE for this. error tex_fills handed preview.render the wrong payload length send exactly the reservation Streaming art
texture format <n> error a texture format the previewer cannot draw; read_uib admits only two nothing to fix Previewer
op <n> error a command op the previewer has no case for; read_uib admits only four nothing to fix Previewer
unbalanced scissor stack in command list error a screen whose pushes and pops do not balance; ps2ui-check refuses one first run ps2ui-check ps2ui-check

Runtime load

ps2ui_load returns a negative code and touches nothing. The checks run in this order, so the first failure is the one reported. The codes are in runtime/ps2ui.h.

message severity cause fix page
PS2UI_ERR_TRUNCATED (-1) error the file is shorter than the 84-byte header, or a table extent or the blob region runs past size pass the real byte count Errors and constants
PS2UI_ERR_MAGIC (-2) error the header magic is not 0x31424955 load a .uib Errors and constants
PS2UI_ERR_VERSION (-3) error the header version is not 7 rebake with this toolchain Compatibility
PS2UI_ERR_FEATURES (-7) error a feature bit outside PS2UI_FEAT_KNOWN, or a streamed texture with bit 3 clear rebake with this toolchain Errors and constants
PS2UI_ERR_BOUNDS (-4) error n_screen 0, n_theme 0, or any cross-reference in the per-table loops rebake, and run ps2ui-check on the blob Errors and constants
PS2UI_ERR_TINTS (-14) error n_theme > 1 with PS2UI_FEAT_ROLE_TINTS clear rebake with this toolchain Theming
PS2UI_ERR_CRC (-6) error crc32 over the file with the crc field zeroed does not match the header rebake, or reread the file Errors and constants
PS2UI_ERR_ALIGN (-8) error the blob region address, a baked texture's data_off, or the arena is not 16-aligned; or the blob address, a table, or a font's glyph or kern table is not 4-aligned align the buffer to 16 bytes; a misaligned table means the file was not written by this baker, so rebake it Integrating the runtime
PS2UI_ERR_TOO_MANY (-5) error the counts are legal and the arena carve exceeds the target's size_t shrink the UI Errors and constants
PS2UI_ERR_ARENA (-9) error the arena is NULL, or smaller than ps2ui_arena_size() size the arena from the bake's arena line ps2ui-bake

Runtime calls

Only ps2ui_load, ps2ui_tex_set, ps2ui_clut_set, ps2ui_theme_set and ps2ui_offset_set return a PS2UI_ERR_ code. ps2ui_upload returns 0 or -1. Everything else reports failure as 0, NULL or -1, and the runtime prints nothing at all.

message severity cause fix page
PS2UI_ERR_BOUNDS (-4) error a null context passed to ps2ui_clut_set, ps2ui_theme_set or ps2ui_offset_set pass the context Errors and constants
PS2UI_ERR_NOT_STREAMED (-10) error ps2ui_tex_set with a null context, GS global or texel pointer, an unknown name, or a baked texture name a data-tex-slot reservation Streaming art
PS2UI_ERR_ALIGN (-8) error ps2ui_tex_set was given a texel buffer that is not 16-aligned align the buffer to 16 bytes Streaming art
PS2UI_ERR_SIZE (-11) error ps2ui_tex_set len differs from the reservation, or ps2ui_clut_set ncolors is above the baked count pass the payload figure the bake printed VRAM budget
PS2UI_ERR_RANGE (-12) error a CLUT index at or past n_clut, a theme at or past n_theme, or an offset outside int16 stay inside the blob's counts Errors and constants
PS2UI_ERR_STATE (-13) error ps2ui_clut_set called before ps2ui_upload upload first Streaming art
-1 from ps2ui_upload error the VRAM preflight exceeds 4 MiB; nothing is transferred and the context stays not-uploaded cut the texture footprint VRAM budget
0, NULL or -1 from a query silent an unknown name in ps2ui_focus_set, ps2ui_slot_set, ps2ui_visible_set or ps2ui_screen_set; an out-of-window list row check the name against the blob C API reference