implements PLN-0073 render contract specs

This commit is contained in:
bQUARKz 2026-05-25 11:35:49 +01:00
parent 2b69be0f11
commit 96a23e5419
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
5 changed files with 165 additions and 149 deletions

View File

@ -1,5 +1,5 @@
{"type":"meta","next_id":{"DSC":39,"AGD":39,"DEC":31,"PLN":87,"LSN":47,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0035","status":"done","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0044","file":"discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
{"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}

View File

@ -2,7 +2,7 @@
id: PLN-0073
ticket: render-frame-packet-boundary
title: Render Contract Specs
status: open
status: done
created: 2026-05-25
ref_decisions: [DEC-0030]
tags: [gfx, renderer, runtime, frame-composer, architecture, ui, pipeline]

View File

@ -9,7 +9,29 @@ Didactic companion: [`../learn/mental-model-gfx.md`](../runtime/learn/mental-mod
The **GFX** peripheral is responsible for generating images in PROMETEU.
It is an explicit 2D graphics device based on:
`DEC-0030` defines the current logical render boundary. PROMETEU render
production is split from render implementation:
```text
domain buffers during logical frame
-> RenderManager closes buffers
-> RenderSubmission snapshot
-> render surface / implementation consumes submission
-> RGBA8888 surface publication
```
The GFX peripheral remains the classic local raster implementation for
PROMETEU's 2D output. Logical render APIs do not target `Gfx` or the
framebuffer directly.
`RenderSubmission` is the closed snapshot passed across the render boundary. It
MUST contain a frame id, the active app mode, and one typed packet:
`Game2DFramePacket` for `AppMode::Game` or `ShellUiFramePacket` for
`AppMode::Shell`. Once closed, producers MUST treat the submission as
immutable. The runtime backpressure policy is latest-complete-submission-wins;
it MUST NOT accumulate an unbounded frame queue.
The current 2D graphics model is based on:
- framebuffer
- tilemaps
@ -48,19 +70,19 @@ palette, host presentation, or compatibility contract.
## 3. Double Buffering
The GFX maintains two buffers:
The render surface implementation maintains the concrete buffers needed to
publish a frame. The classic software implementation uses:
- **Back Buffer** — where the frame is built
- **Front Buffer** — where the frame is displayed
Per-frame flow:
1. The system prepares the logical frame
2. Canonical game composition is rendered into the back buffer
3. Deferred final overlay/debug primitives are drained on top of the completed game frame
4. Calls `present()`
5. Buffers are swapped
6. The host displays the front buffer
1. Game or Shell code mutates mode-specific domain buffers during the logical frame.
2. `RenderManager` closes the active buffers into an immutable `RenderSubmission`.
3. The render surface implementation consumes the submission and rasterizes to its back buffer.
4. The render surface publishes the completed RGBA8888 surface.
5. The host displays the published surface.
This guarantees:
@ -192,14 +214,20 @@ Access:
---
## 10. Canonical Game Projection to the Back Buffer
## 10. Canonical Game Projection
For each frame:
Game mode uses a typed Game 2D submission. `composer.*` owns high-level Game 2D
frame composition: scene binding, camera, sprites, HUD, and frame orchestration.
`gfx2d.*` owns Game 2D primitives only. Both domains are mutable while the
logical frame is being produced and are closed by `RenderManager` into a
`Game2DFramePacket`.
For each Game 2D packet:
1. For each Tile Layer, in order:
- Rasterize visible tiles from the cache
- Apply scroll, flip, and transparency
- Write to the back buffer
- Write to the render surface's working buffer
2. Draw sprites:
- With priority between layers
@ -207,9 +235,11 @@ For each frame:
3. Draw HUD layer last
This section describes only the canonical game composition path.
4. Draw buffered `gfx2d.*` primitives according to the Game 2D packet contract.
`gfx.*` primitives such as `draw_text`, `draw_line`, and `draw_disc` are not part of this canonical game projection order. In v1 they belong to a deferred final overlay/debug stage that is drained after canonical game composition is complete.
This section describes only the Game 2D packet rendering path. Shell/system UI
uses `gfxui.*` and `ShellUiFramePacket`; it is never part of Game HUD or
`composer.*`.
---
@ -227,15 +257,15 @@ Base order:
4. Tile Layer 3
5. Sprites (by priority between layers)
6. HUD Layer
7. Scene Fade
8. HUD Fade
9. Deferred `gfx.*` overlay/debug primitives
7. Buffered `gfx2d.*` Game primitives
Normative boundary:
- Items 1 through 8 belong to canonical game-frame composition.
- Item 9 is a separate overlay/debug stage.
- Deferred `gfx.*` primitives MUST NOT be interpreted as scene, sprite, or canonical HUD content.
- Items 1 through 6 belong to `composer.*` Game-frame composition.
- Item 7 belongs to `gfx2d.*`.
- `gfx2d.*` primitives MUST NOT be interpreted as scene, sprite, camera, HUD,
or frame orchestration.
- Shell/system UI belongs to `gfxui.*` and `ShellUiFramePacket`, not Game HUD.
---
@ -287,7 +317,8 @@ Everything is:
- Blending occurs during drawing
- For canonical game composition, the result goes to the back buffer during composition
- For deferred `gfx.*` overlay/debug primitives, the result is applied during the final overlay/debug drain stage
- For `gfx2d.*` and `gfxui.*` primitives, the result is applied when the render
surface consumes the closed packet for the active app mode
- There is no automatic GPU-style post-processing pipeline
---
@ -301,6 +332,7 @@ By design:
- HDR
- Gamma correction
- RGB565 compatibility framebuffers
- fade fields, fade syscalls, or fade packet members
- multi-format backend selection
- render-thread ownership as part of this contract
@ -318,104 +350,24 @@ By design:
---
## 17. Special PostFX — Fade (Scene and HUD)
## 17. Transitions and Removed Fade Contract
PROMETEU supports **gradual fade** as a special PostFX, with two independent
controls:
The previous special fade model is not part of the canonical render contract.
Current render packets, syscalls, and ABI domains MUST NOT expose scene fade,
HUD fade, fade levels, fade colors, or equivalent inherited fade state.
- **Scene Fade**: affects the entire scene (Tile Layers 03 + Sprites)
- **HUD Fade**: affects only the HUD Layer (always composed last)
In v1, deferred `gfx.*` overlay/debug primitives are drained after both fades and therefore are not themselves part of scene or HUD fade application.
The fade uses a **discrete integer level** (0..31), which in practice produces an
"almost continuous" visual result in Prometeu's `480x270` pixel-art framebuffer.
---
### 17.1 Fade Representation
Each fade is represented by:
- `fade_level: u8` in the range **[0..31]**
- `0` → fully replaced by the fade color
- `31` → fully visible (no fade)
- `fade_color: RGBA8888`
- color the image will be blended into
Registers:
- `SCENE_FADE_LEVEL` (0..31)
- `SCENE_FADE_COLOR` (RGBA8888)
- `HUD_FADE_LEVEL` (0..31)
- `HUD_FADE_COLOR` (RGBA8888)
Common cases:
- Fade-out: `fade_color = BLACK`
- Flash/teleport: `fade_color = WHITE`
- Special effects: any RGBA8888 color
---
### 17.2 Fade Operation (Blending with Arbitrary Color)
For each RGBA8888 pixel `src` and fade color `fc`, the final pixel `dst` is calculated per channel.
1) Extract components:
- `src_r8`, `src_g8`, `src_b8`, `src_a8`
- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8`
2) Apply integer blending:
```
src_weight = fade_level // 0..31
fc_weight = 31 - fade_level
r8 = (src_r8 * src_weight + fc_r8 * fc_weight) / 31
g8 = (src_g8 * src_weight + fc_g8 * fc_weight) / 31
b8 = (src_b8 * src_weight + fc_b8 * fc_weight) / 31
a8 = (src_a8 * src_weight + fc_a8 * fc_weight) / 31
```
- `src_r8`, `src_g8`, `src_b8`, `src_a8`
- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8`
3) Repack:
```
dst = pack_rgba8888_rgba(r8, g8, b8, a8)
```
Notes:
- Deterministic operation
- Integers only
- Can be optimized via LUT
---
### 17.3 Order of Application in the Frame
The frame composition follows this order:
1. Rasterize **Tile Layers 03** → Back Buffer
2. Rasterize **Sprites** according to priority
3. (Optional) Extra pipeline (Emission/Light/Glow etc.)
4. Apply **Scene Fade** using:
- `SCENE_FADE_LEVEL`
- `SCENE_FADE_COLOR`
5. Rasterize **HUD Layer**
6. Apply **HUD Fade** using:
- `HUD_FADE_LEVEL`
- `HUD_FADE_COLOR`
7. `present()`
Future visual transitions between Shell and Game belong to `RenderManager`.
They are not owned by `composer.*`, `gfx2d.*`, `gfxui.*`, `Game2DFramePacket`,
or `ShellUiFramePacket`.
Rules:
- Scene Fade never affects the HUD
- HUD Fade never affects the scene
- render domain packets MUST NOT contain fade fields;
- public render syscalls MUST NOT expose fade controls;
- render implementations MUST NOT treat fade as an inherited post-processing
habit;
- transition work requires an explicit `RenderManager` contract or a later
decision.
---
@ -570,8 +522,13 @@ The system can measure:
Graphics-related public ABI in v1 is split between:
- `gfx.*` for direct drawing/backend-oriented operations;
- `composer.*` for frame orchestration operations.
- `composer.*` for Game 2D high-level frame composition;
- `gfx2d.*` for Game 2D primitives only;
- `gfxui.*` for Shell UI primitives only.
`composer.*` and `gfx2d.*` are available to `AppMode::Game`.
`gfxui.*` is available to `AppMode::Shell`. Renderers and capabilities may
differ by app mode.
Only operations with real operational rejection paths return explicit status values.
@ -585,29 +542,32 @@ Fault boundary:
| Syscall | Return | Policy basis |
| ----------------------- | ------------- | --------------------------------------------------- |
| `gfx.clear` | `void` | no real operational failure path in v1 |
| `gfx.fill_rect` | `void` | no real operational failure path in v1 |
| `gfx.draw_line` | `void` | no real operational failure path in v1 |
| `gfx.draw_circle` | `void` | no real operational failure path in v1 |
| `gfx.draw_disc` | `void` | no real operational failure path in v1 |
| `gfx.draw_square` | `void` | no real operational failure path in v1 |
| `gfx.draw_text` | `void` | no real operational failure path in v1 |
| `gfx2d.clear` | `void` | no real operational failure path in v1 |
| `gfx2d.fill_rect` | `void` | no real operational failure path in v1 |
| `gfx2d.draw_line` | `void` | no real operational failure path in v1 |
| `gfx2d.draw_circle` | `void` | no real operational failure path in v1 |
| `gfx2d.draw_disc` | `void` | no real operational failure path in v1 |
| `gfx2d.draw_square` | `void` | no real operational failure path in v1 |
| `gfx2d.draw_text` | `void` | no real operational failure path in v1 |
| `gfxui.*` primitives | `void` | no real operational failure path in v1 |
| `composer.bind_scene` | `status:int` | status-returning API, but missing scene glyph dependencies are fatal runtime errors |
| `composer.unbind_scene` | `status:int` | explicit orchestration-domain operational result |
| `composer.set_camera` | `void` | no real operational failure path in v1 |
| `composer.emit_sprite` | `status:int` | explicit orchestration-domain operational rejection |
### 19.1.a Deferred overlay/debug semantics for `gfx.*`
### 19.1.a Primitive domain semantics
The public `gfx.*` primitive family remains valid in v1, but its stable operational meaning is:
The primitive domains have stable operational meaning:
- deferred final overlay/debug composition;
- screen-space and pipeline-agnostic relative to `composer.*`;
- outside `FrameComposer`;
- above scene, sprites, and canonical HUD;
- drained after `hud_fade`.
- `gfx2d.*` is Game 2D primitive command buffering;
- `gfx2d.*` is screen-space and primitive-only relative to `composer.*`;
- `gfx2d.*` is outside scene, camera, sprites, HUD, and Game 2D frame orchestration;
- `gfxui.*` is Shell UI primitive command buffering;
- `gfxui.*` does not contain widget or layout policy.
This means callers MUST NOT rely on stable immediate writes to the working back buffer as the public contract for `gfx.draw_text(...)` or sibling primitives.
Callers MUST NOT rely on stable immediate writes to the working back buffer as
the public contract for primitive drawing. Primitive calls mutate domain command
buffers that close into the active typed submission.
### 19.1.b Scene dependency fatal boundary

View File

@ -116,26 +116,26 @@ Hardware differences:
The graphics system:
- operates on a logical RGBA8888 framebuffer
- produces typed logical render submissions that render to RGBA8888 output
- uses an indexed palette
- does not depend on a specific GPU
The platform layer:
- only displays the framebuffer
- does not reinterpret graphics commands
- consumes closed render submissions through a render-surface implementation
- **may overlay technical HUDs without modifying the logical framebuffer**
- may transport the logical framebuffer into a host presentation surface where a host-only overlay layer is composed
- may transport published RGBA8888 output into a host presentation surface where a host-only overlay layer is composed
The host presentation layer MUST treat RGBA8888 as the canonical logical
framebuffer format. RGB565 conversion is not part of the normal host
presentation contract.
Host presentation SHOULD be driven by published logical frames and explicit host-owned invalidation, not by perpetual redraw polling.
Host presentation SHOULD be driven by published render submissions and explicit
host-owned invalidation, not by perpetual redraw polling.
In particular:
- a stable logical frame MAY remain visible across multiple host wakeups without recomposition;
- a stable published submission MAY remain visible across multiple host wakeups without recomposition;
- a host MAY redraw the same logical frame again when its own surface is invalidated by resize, expose, or host-only overlay/debug changes;
- a host MUST NOT invent intermediate logical frames or require continuous redraw merely to discover whether a new logical frame exists.

View File

@ -220,29 +220,78 @@ For `asset.load`:
- JSON-on-the-wire bank inspection payloads are not valid public ABI;
- `bank.info` returns stack values, not textual structured payloads.
### GFX surface (`gfx`, v1)
### Render surfaces (`composer`, `gfx2d`, `gfxui`, v1)
The public GFX ABI uses format-neutral operation names. API and syscall names
MUST NOT encode RGB565 or any other pixel format suffix.
`DEC-0030` splits logical render production from render implementation. Public
render syscalls mutate app-mode-specific domain buffers. They do not directly
publish a framebuffer and do not call host presentation APIs.
The canonical flow is:
```text
domain buffers during logical frame
-> RenderManager closes buffers
-> RenderSubmission snapshot
-> render surface / implementation consumes submission
-> RGBA8888 surface publication
```
`RenderSubmission` is a typed closed snapshot containing `frame_id`, `app_mode`,
and exactly one packet: `Game2DFramePacket` for `AppMode::Game` or
`ShellUiFramePacket` for `AppMode::Shell`. Producers may mutate domain buffers
before closure only. Once `RenderManager` closes a submission, producers MUST
NOT mutate it. Backpressure is latest-complete-submission-wins; the runtime
MUST NOT expose an unbounded submission queue as part of the ABI.
Render API and syscall names MUST NOT encode RGB565 or any other pixel format
suffix.
#### Game 2D primitive surface (`gfx2d`, v1)
The `gfx2d` module is a Game profile primitive surface. It is limited to Game
2D primitive commands and does not own scene, camera, sprites, HUD, or frame
orchestration.
Canonical operations in v1 include:
- `gfx.clear(color) -> void`
- `gfx.fill_rect(x, y, w, h, color) -> void`
- `gfx.draw_line(x0, y0, x1, y1, color) -> void`
- `gfx.draw_circle(x, y, radius, color) -> void`
- `gfx.draw_disc(x, y, radius, color) -> void`
- `gfx.draw_square(x, y, size, color) -> void`
- `gfx.draw_text(x, y, text, color) -> void`
- `gfx2d.clear(color) -> void`
- `gfx2d.fill_rect(x, y, w, h, color) -> void`
- `gfx2d.draw_line(x0, y0, x1, y1, color) -> void`
- `gfx2d.draw_circle(x, y, radius, color) -> void`
- `gfx2d.draw_disc(x, y, radius, color) -> void`
- `gfx2d.draw_square(x, y, size, color) -> void`
- `gfx2d.draw_text(x, y, text, color) -> void`
#### Shell UI primitive surface (`gfxui`, v1)
The `gfxui` module is a Shell profile primitive surface. It contains Shell UI
primitive commands only. Widget and layout policy belongs in Shell/UI code or
stdlib code, not in the host/render-surface implementation.
Canonical operations in v1 include primitive shapes equivalent to the subset
needed by Shell UI:
- `gfxui.clear(color) -> void`
- `gfxui.fill_rect(x, y, w, h, color) -> void`
- `gfxui.draw_line(x0, y0, x1, y1, color) -> void`
- `gfxui.draw_circle(x, y, radius, color) -> void`
- `gfxui.draw_disc(x, y, radius, color) -> void`
- `gfxui.draw_square(x, y, size, color) -> void`
- `gfxui.draw_text(x, y, text, color) -> void`
Rules:
- `color` arguments are packed RGBA8888 values using RGBA channel order.
- RGB565 raw values are not a public ABI contract.
- `Gfx*565` syscall names and `gfx.*_565` canonical identities are not valid
- `Gfx*565` syscall names and `gfx*.*_565` canonical identities are not valid
current ABI.
- The runtime framebuffer exposed across the host boundary is RGBA8888, not
`u16` RGB565.
- The old primitive `gfx.*` ABI is not the canonical render domain. PBS stdlibs
may expose ergonomic high-level names, but generated host bindings must map
to `gfx2d.*` in Game mode or `gfxui.*` in Shell mode.
- Render packets and public render syscalls MUST NOT expose fade fields or fade
controls.
### Composition surface (`composer`, v1)
@ -251,6 +300,11 @@ The canonical frame-orchestration public ABI uses module `composer`.
The `composer` module is a game profile surface. It is not inherited by
`System` profile apps as their public UI/composition API.
`composer` owns Game 2D high-level frame composition: scene binding, camera,
sprites, HUD, and Game 2D frame orchestration. It closes into a
`Game2DFramePacket` through `RenderManager`; it does not publish or present a
framebuffer directly.
Canonical operations in v1 are:
- `composer.bind_scene(bank_id) -> (status)`
@ -264,6 +318,8 @@ For mutating composer operations:
- `bind_scene`, `unbind_scene`, and `emit_sprite` are status-returning;
- `set_camera` remains `void` in v1;
- no caller-provided sprite index or `active` flag is part of the canonical contract.
- no fade level, fade color, or transition control is part of the canonical
composer ABI.
Fatal boundary clarification for `bind_scene`: