A prebuilt tool, bin/ludic-ui-preview (built by ludic-dev build, shipped beside ludic-lsp, run as `ludic ui-preview [--font DIR]`): ludic.ui with a backend that records every draw call as a line, and mock component classes the studio describes (load / model / calls). frame t runs ui_show at interface time t; text is measured on the CPU with the game's font.json metrics; locale goes through ludic.i18n; tree / box / rules inspect the frame. No game code, no GPU, no network. The wire protocol is frozen as tools/ui-preview/protocol-v1.md; smoke.txt is a transcript to run. ludic.ui gains, all additive: UiClass.make_of, UiBackend.said / emitted, UiRule.text / at (with comment line breaks kept so rule lines count true, and a class's styles read under its .lss path), and ui_root, ui_find, ui_rules_of, ui_rule_value, ui_building, ui_class, ui_class_load, ui_file_forget, ui_errors_clear; ui_nine_cuts_into exported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
3.6 KiB
Markdown
59 lines
3.6 KiB
Markdown
# ludic ui-preview
|
|
|
|
A game's `ludic.ui` components, previewed for a studio (a UI editor) without the game: `ludic.ui`
|
|
itself, with a backend that records its draw calls instead of drawing them, and component classes
|
|
the studio describes over stdin. No game code is built, nothing touches a GPU, nothing opens a
|
|
network connection. It is the toolchain's own program, shipped prebuilt as `bin/ludic-ui-preview`.
|
|
|
|
```bash
|
|
ludic ui-preview [--font DIR] # the host on stdin/stdout; DIR holds the game's font.json
|
|
```
|
|
|
|
**The wire protocol is [protocol-v1.md](protocol-v1.md)**, frozen: every request, every reply and
|
|
every line format. `smoke.txt` is a scripted session with what each reply must contain.
|
|
|
|
## What it does
|
|
|
|
- **Components are mocks.** `load` registers a `UiClass` named as the component, with the template
|
|
and styles the studio sends (unsaved text is fine), or changes that class in place. Its model is
|
|
the story's (`model`), with the props its parent's tag gives it and whatever its template `set`s
|
|
laid over it; its functions answer from the story's table (`calls`). A component tag the studio
|
|
has not sent yet is an empty class until it is.
|
|
- **The frame is ludic.ui's own.** `frame t` sets the interface clock to `t`, hands over the input
|
|
the studio sent (`input ...`), and calls `ui_show`: build, cascade, layout, pointer and focus,
|
|
draw, then the actions a press ran. The draw list is every `UiBackend` call in painting order.
|
|
- **Text is measured as the game measures it.** `font DIR` (or `--font DIR`) reads the same
|
|
`font.json` ludic.render3d's overlay reads, and the width of a run is the overlay's sum of glyph
|
|
advances at the font's whole-pixel size; each `text` line carries it, so the studio fits its own
|
|
rendering to the game's line breaks.
|
|
- **Languages** are the game's: `locale <file.po>` translates every drawn text with ludic.i18n.
|
|
- **Natives** (a radar, a dial) are game code, so a `native` line is a box for the studio to fill.
|
|
- **Inspection**: `tree`, `box <id>` (box and computed style) and `rules <id>` (the matching rules,
|
|
each with the file and line its selector was written on).
|
|
|
|
## ludic.ui additions it relies on
|
|
|
|
All additive, and none changes what a game draws:
|
|
|
|
- `UiClass.make_of` - a constructor handed the class, so one host function makes every mock.
|
|
- `UiBackend.said` - template errors to the host instead of `print`; `UiBackend.emitted` - every
|
|
`emit`, for the host's log.
|
|
- `UiRule.text` and `UiRule.at` - a rule's selector as written and `file:line`. A stylesheet's
|
|
comments keep their line breaks when stripped, so lines count true; a component's own styles are
|
|
read under its `.lss` path.
|
|
- `inspect.ludic`: `ui_root`, `ui_find`, `ui_rules_of`, `ui_rule_value`, `ui_building`,
|
|
`ui_class_load`, `ui_file_forget`, `ui_errors_clear`; `class.ludic`: `ui_class`;
|
|
`ui_nine_cuts_into` exported.
|
|
|
|
## Limits in v1
|
|
|
|
- An error's column is not known (`col` is 0): ludic.ui records a file and line per element and per
|
|
rule, not a column. A malformed XML file is read leniently by the runtime's parser and does not
|
|
report a syntax error.
|
|
- In a GAME build a component's styles have their `@import`s inlined by the compiler, so a rule's
|
|
line there counts in the inlined text; in the host the studio sends the file as written, and
|
|
lines are the file's.
|
|
- A declaration's value is given as written only when it is plain text; one with `{...}` holes is
|
|
`""` in `rules` (its computed result is in `box`).
|
|
- Images are referenced, not decoded: the studio draws them from its own copies of the game's files
|
|
and atlases, and says a picture's natural size with `image` when `object-fit` needs it.
|