This document defines deterministic rendering for the message window only. It is intentionally independent of host UI framing.
Scope
- Target surface:
320x240message window. - Output forms:
- web text rendering for copy/paste
- badge/window raster output (
320x240) - Out of scope:
- host UI bars, status, nav, trust badges, and other outer layout concerns
Fixed window geometry
All coordinates are absolute pixels inside the 320x240 window.
- Window rect:
x=0, y=0, w=320, h=240 - Content rect:
x=8, y=8, w=304, h=224 - Content rect is the only drawing region for message text and inline artifacts.
Text profile
- Font size:
16px - Line height:
18px - Max lines for
right|left|none:12 - Max lines for
top|bottom:6 - Font IDs:
nsm,ns,ser,atk,ibm
Supported markdown subset
- Paragraphs and explicit newlines
- Headings
#through###### - Block quotes (
>) - Ordered/unordered lists
- Task items (
- [ ],- [x]) - Inline code and fenced code blocks
- Links
[label](url)and bare URLs - Horizontal rules (
---,***,___) - Table-like rows (
| cell | cell |) - Strikethrough (
~~text~~)
Typst-style message directives (non-printing)
#font("nsm"|"ns"|"ser"|"atk"|"ibm")#place(loc)[content]wherelocuses Typst-style alignment tokens (left,right,top,bottom,center,none) joined with+#qr("https://example.com")#event("YYYY-MM-DD HH:MM", "Title", "Location")#contact("Name", "phone", "email", "https://url")
Example:
#place(bottom + right)[#qr("https://bbb.io/badge")]
Directive content is control-only and does not consume message text lines.
Placement profiles
right(default):- text rect
x=0, y=0, w=200, h=224 - artifact rect
x=208, y=0, w=96, h=224 max artifacts:
2left:text rect
x=104, y=0, w=200, h=224artifact rect
x=0, y=0, w=96, h=224max artifacts:
2top:text rect
x=0, y=104, w=304, h=120artifact rect
x=0, y=0, w=304, h=96max artifacts:
3bottom:text rect
x=0, y=0, w=304, h=120artifact rect
x=0, y=128, w=304, h=96max artifacts:
3none:text rect
x=0, y=0, w=304, h=224no artifact rect
max artifacts:
0
Location expression mapping:
- If
leftorrightis present, use side profile (leftorright), with optionaltop|bottom|centervertical alignment for artifacts. - Else if
toporbottomis present, use row profile (toporbottom), with optionalleft|right|centerhorizontal alignment for artifacts. nonedisables artifact rendering.
Parsing and shaping phases
- Normalize:
- convert line endings to
\n trim trailing whitespace per line
Parse:
tokenize supported markdown
parse non-printing directives
extract artifact payloads from URLs and directives
Shape:
measure with selected font profile
wrap deterministically within placement text rect width
Fit check:
enforce line and artifact capacity for selected placement
overflow is invalid for v1 (no pagination fallback)
Paint:
render text + inline artifacts into
320x240web and badge derive from the same shaped model
Output contract
For each render:
render_spec_versionrender_profile_id(msg_320x240_v1)page_index=1,page_count=1plain_text(as rendered in the window)image_320x240qr_artifacts
Repeatability constraints
- No dynamic font scaling in v1
- No variable content padding/margins in v1
- No adaptive pagination in v1
- Line/artifact placement depends only on:
- normalized message
- directive values
- fixed geometry
- selected font metrics
Bit-exact fixture source
Use typst/social-badge/layout.typ and scripts/check_typst_layouts.cr to
generate and verify deterministic PNG hashes from raw message-content test
cases.