Login
320x240 Message Window Typesetting Contract (v1)
Login

This document defines deterministic rendering for the message window only. It is intentionally independent of host UI framing.

Scope

  1. Target surface: 320x240 message window.
  2. Output forms:
  3. web text rendering for copy/paste
  4. badge/window raster output (320x240)
  5. Out of scope:
  6. host UI bars, status, nav, trust badges, and other outer layout concerns

Fixed window geometry

All coordinates are absolute pixels inside the 320x240 window.

  1. Window rect: x=0, y=0, w=320, h=240
  2. Content rect: x=8, y=8, w=304, h=224
  3. Content rect is the only drawing region for message text and inline artifacts.

Text profile

  1. Font size: 16px
  2. Line height: 18px
  3. Max lines for right|left|none: 12
  4. Max lines for top|bottom: 6
  5. Font IDs: nsm, ns, ser, atk, ibm

Supported markdown subset

  1. Paragraphs and explicit newlines
  2. Headings # through ######
  3. Block quotes (>)
  4. Ordered/unordered lists
  5. Task items (- [ ], - [x])
  6. Inline code and fenced code blocks
  7. Links [label](url) and bare URLs
  8. Horizontal rules (---, ***, ___)
  9. Table-like rows (| cell | cell |)
  10. Strikethrough (~~text~~)

Typst-style message directives (non-printing)

  1. #font("nsm"|"ns"|"ser"|"atk"|"ibm")
  2. #place(loc)[content] where loc uses Typst-style alignment tokens (left, right, top, bottom, center, none) joined with +
  3. #qr("https://example.com")
  4. #event("YYYY-MM-DD HH:MM", "Title", "Location")
  5. #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

  1. right (default):
  2. text rect x=0, y=0, w=200, h=224
  3. artifact rect x=208, y=0, w=96, h=224
  4. max artifacts: 2

  5. left:

  6. text rect x=104, y=0, w=200, h=224

  7. artifact rect x=0, y=0, w=96, h=224

  8. max artifacts: 2

  9. top:

  10. text rect x=0, y=104, w=304, h=120

  11. artifact rect x=0, y=0, w=304, h=96

  12. max artifacts: 3

  13. bottom:

  14. text rect x=0, y=0, w=304, h=120

  15. artifact rect x=0, y=128, w=304, h=96

  16. max artifacts: 3

  17. none:

  18. text rect x=0, y=0, w=304, h=224

  19. no artifact rect

  20. max artifacts: 0

Location expression mapping:

  1. If left or right is present, use side profile (left or right), with optional top|bottom|center vertical alignment for artifacts.
  2. Else if top or bottom is present, use row profile (top or bottom), with optional left|right|center horizontal alignment for artifacts.
  3. none disables artifact rendering.

Parsing and shaping phases

  1. Normalize:
  2. convert line endings to \n
  3. trim trailing whitespace per line

  4. Parse:

  5. tokenize supported markdown

  6. parse non-printing directives

  7. extract artifact payloads from URLs and directives

  8. Shape:

  9. measure with selected font profile

  10. wrap deterministically within placement text rect width

  11. Fit check:

  12. enforce line and artifact capacity for selected placement

  13. overflow is invalid for v1 (no pagination fallback)

  14. Paint:

  15. render text + inline artifacts into 320x240

  16. web and badge derive from the same shaped model

Output contract

For each render:

  1. render_spec_version
  2. render_profile_id (msg_320x240_v1)
  3. page_index=1, page_count=1
  4. plain_text (as rendered in the window)
  5. image_320x240
  6. qr_artifacts

Repeatability constraints

  1. No dynamic font scaling in v1
  2. No variable content padding/margins in v1
  3. No adaptive pagination in v1
  4. Line/artifact placement depends only on:
  5. normalized message
  6. directive values
  7. fixed geometry
  8. 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.