The project file¶
What it is¶
ps2ui.json describes one blob. ps2ui build reads it, compiles every screen with ps2ui-layout, bakes the results with ps2ui-bake and writes the previews. ps2ui check, ps2ui dev and ps2ui serve read the same file. Two keys are required, screens and css. Every other key has a default. A key the loader does not know is an error that names the key.
The file has no variants block. A second blob from the same sources is a second ps2ui build with flags, see -o moves the intermediates.
Minimal example¶
The smallest project is two keys:
That file builds build/ui.uib with build/preview.png beside it. The memcard example adds a montage, examples/memcard/ps2ui.json:
{
"screens": ["ui/library.html", "ui/saves.html"],
"css": "ui/library.css",
"preview": "build/preview.png",
"montage": "build/states.png"
}
Build it from the directory that holds it:
Or name the file from anywhere. The last lines of the transcript name every file written:
...
ps2ui-layout: 89 paint commands, 9 focusables -> build/library.json
...
ps2ui-layout: 43 paint commands, 7 focusables -> build/saves.json
...
ps2ui-bake: 2 screen(s), 1062 records, 11 textures (128 KiB baked), 1 CLUTs -> build/ui.uib
ps2ui-bake: arena 1662 bytes (static uint8_t arena[1662] __attribute__((aligned(16))))
ps2ui-bake: preview -> build/preview.png
ps2ui-bake: montage -> build/states.png
Reference table¶
The reaches column names the tool under ps2ui that receives the key. The mapping lives in compile_screens, bake_argv, cmd_check and cmd_dev in ps2ui.py. The defaults live in DEFAULTS in project.py.
| key | type | default | reaches |
|---|---|---|---|
screens |
list of string or object | required | layout · bake · dev |
css |
string | required unless every screen sets its own | layout · dev |
fonts |
string | fonts/fonts.json beside the project if present, else the baker default |
layout · bake · dev |
out |
string | build/ui.uib |
bake · check · dev |
preview |
string or false |
build/preview.png |
bake |
montage |
string or false |
none | bake |
previewDisplay |
string or false |
none | bake |
mode |
string | none | layout · dev, see video modes |
canvas |
string WxH |
none | layout · dev |
displayAspect |
string W:H |
none | layout · dev |
strict |
boolean | false |
layout · check · dev |
minFontSize |
integer px | none | layout · dev |
focusWrap |
boolean | false |
layout · dev, per screen |
palettizeImages |
boolean | false |
bake · dev |
vramBudget |
integer bytes | none | bake · check, see VRAM budget |
limits |
object | see below | layout · bake · dev, one key per cap |
The test class behind the table ran in this session:
An entry in screens is a path or an object. The object form takes these keys and no others:
| key | type | default | reaches |
|---|---|---|---|
html |
string | required | layout · dev |
css |
string | the top-level css |
layout · dev |
focusWrap |
boolean | the top-level focusWrap |
layout · dev |
The channel6 example uses the object form for one screen, examples/channel6/ps2ui.json:
Behaviour¶
Paths resolve against the project file¶
Every path in the file joins onto the directory that holds the file. The working directory plays no part. ps2ui build changes into that directory for the run, prints every path relative to it, and restores the previous directory before it returns. The build above ran from the repository root against a copy of memcard outside the tree. Its build/ landed beside the project file:
A screen's name is the HTML file's stem. The name is the intermediate's file stem and the screen's name inside the blob.
Fonts¶
The fonts key names a manifest. Without it, fonts/fonts.json beside the project is used when that file exists. Without either, no --fonts is passed and the baker applies its own default, which is the repository's fonts/fonts.json and exists only in a checkout. The tutorial project sets no fonts key, docs/tutorial-uc3.md; it relies on ps2ui fontgen having written fonts/fonts.json beside it. The three shipped examples set no fonts key either and build against the checkout default.
A directory argument¶
A directory in place of the file means <dir>/ps2ui.json. ps2ui check accepts the same argument and never builds:
...
ok 63 - every texture is drawn or belongs to a font
1..63
# build/ui.uib: 640x448 at 4:3, 2 screen(s), 1062 commands, 11 textures, 6 slots
PASS: 63 checks, 0 error(s), 0 warning(s)
The output path moves the intermediates¶
ps2ui build -o NEW writes the blob at NEW and moves the per-screen IR files with it. The IR files land in NEW's directory. Their stems take a suffix derived from the two blob stems, set_out_override in project.py:
| override | intermediate for screen games |
rule |
|---|---|---|
-o dist/ui.uib |
dist/games.json |
same stem as out, no suffix |
-o build/ui-16x9.uib |
build/games-16x9.json |
NEW's stem extends the out stem, the remainder is the suffix |
-o build/widescreen.uib |
build/games-widescreen.json |
no shared stem, the whole NEW stem is the suffix |
The previews keep their configured names. Rename them with --preview, --montage and --preview-display, or pass none to skip one. This is the second build line of examples/channel6/build.sh, run here against a copy of channel6 that had already been built once:
ps2ui build channel6/ps2ui.json --mode ntsc16x9 -o build/ui-16x9.uib \
--preview-display build/preview-16x9-display.png --preview none --montage none
...
ps2ui-layout: 90 paint commands, 9 focusables -> build/games-16x9.json
...
ps2ui-layout: 99 paint commands, 8 focusables -> build/probe-16x9.json
...
ps2ui-bake: 2 screen(s), 1242 records, 25 textures (180 KiB baked), 9 CLUTs -> build/ui-16x9.uib
ps2ui-bake: arena 10624 bytes (static uint8_t arena[10624] __attribute__((aligned(16))))
ps2ui-bake: display preview 796x448 at 16:9 -> build/preview-16x9-display.png
games-16x9.json
games.json
preview-16x9-display.png
preview-display.png
preview.png
probe-16x9.json
probe.json
states.png
ui-16x9.uib
ui.uib
Nothing the first build wrote was replaced.
Overrides on ps2ui build¶
ps2ui build takes --mode, -o, --preview, --montage and --preview-display. Each replaces the key of the same name for that run. The three preview flags accept none, which suppresses the file.
Suppressing a preview in the file¶
Set preview, montage or previewDisplay to false to write no such file. A copy of memcard with "preview": false and no montage key wrote no PNG at all:
Resource caps¶
New in 0.10.0. limits is an object, one key per cap, and every value is a positive
integer:
Those are the defaults. canvasDim bounds each canvas dimension,
nodes the elements on a screen after data-repeat expands, depth
how far they nest, and imagePixels what a source image may decode to.
The first three are enforced by the layout compiler and the fourth by
the baker; ps2ui build sends each one to the tool that checks it, and
each takes a --limit NAME=N on that tool's own command line.
A theme is a file somebody else wrote, so the caps refuse rather than warn: a PlayStation 2 cannot display a 30000px canvas, and there is no version of that request worth an exemption. The numbers come from the examples in this repository, where the largest screen is 93 elements at depth 5 and the largest source image is 1984x1408, so each sits well above the biggest real one. Raise a cap here when your project needs it.
Keys that reach the checker¶
New in 0.6.0. ps2ui check forwards strict and vramBudget to ps2ui-check, so a project means the same thing to the build and to the check, CHANGELOG.md. The forwarded set is not a hand-written list. The test derives it from DEFAULTS and the checker's own --help, and fails when a key gains a checker flag and is not forwarded:
cd packages/baker/tests && python3 -m unittest \
test_baker.TestProjectFile.test_every_project_key_the_checker_accepts_actually_reaches_it -v
test_every_project_key_the_checker_accepts_actually_reaches_it (test_baker.TestProjectFile.test_every_project_key_the_checker_accepts_actually_reaches_it)
The mapping, enumerated rather than remembered. ... ok
Limits and errors¶
Every refusal is one message with no traceback and exit status 1. An unknown key:
ps2ui: ps2ui.json: unknown key(s) 'colour'.
A project takes: canvas, css, displayAspect, focusWrap, fonts, limits, minFontSize, mode, montage, out, palettizeImages, preview, previewDisplay, screens, strict, vramBudget
The full list, each message produced in this session by ps2ui build over a project written to trigger it:
| message | cause | fix |
|---|---|---|
ps2ui: missing.json: no such project file. followed by the two-key example |
the path, or <dir>/ps2ui.json, does not exist |
create the file or name the right directory |
ps2ui: bad-json.json: not valid JSON -- Expecting property name enclosed in double quotes: line 1 column 3 (char 2) |
the file does not parse | fix the JSON at the position named |
ps2ui: not-object.json: the top level must be an object |
the top level is a list or a scalar | wrap the keys in { } |
ps2ui: no-screens.json: "screens" is required and must not be empty |
no screens, or an empty list |
list at least one screen |
ps2ui: screens-string.json: "screens" must be a list |
screens is a string |
write "screens": ["ui/a.html"] |
ps2ui: ps2ui.json: unknown key(s) 'colour'. followed by the accepted list |
a key outside the table above, including a misspelling | use a key from the list |
ps2ui: screens[0] is 7; a screen is a path, or an object with "html" and optionally "css" or "focusWrap" |
a screen entry that is neither a string nor an object | write a path or an object |
ps2ui: screens[0] has unknown key(s) 'focuswrap'; a screen takes css, focusWrap, html |
an object screen with a key outside the per-screen table | use html, css or focusWrap |
ps2ui: screens[0] has no "html" |
an object screen without html |
add html |
ps2ui: screens[0] (ui/a.html) has no stylesheet: set "css" at the top level for every screen, or on this one |
no css at the top level and none on the screen |
set css in either place |
ps2ui: build/ui.uib: no blob to check. Runps2ui buildfirst -- this does not build, so that a check can never report on a blob it just made and nobody has seen. |
ps2ui check on a project whose out does not exist |
run ps2ui build |
One limit:
| limit | detail |
|---|---|
| one blob per file | a second blob is a second ps2ui build with --mode, -o and the preview flags |
Related pages¶
- ps2ui, the umbrella command and its subcommands
- ps2ui-layout and ps2ui-dev, what
mode,canvas,displayAspect,strict,minFontSizeandfocusWrapdo - ps2ui-bake, what
out,preview,montage,previewDisplay,palettizeImagesandvramBudgetdo - ps2ui-check, what
strictandvramBudgetdo at check time - Video modes, the values
modetakes - VRAM budget, the number
vramBudgetoverrides