Overview
Render TSX / JSX + Tailwind-style layouts into 800x480 images, then wrap them in minimal TRMNL markup.
The default visual direction is not a colorful web UI screenshot, but a black-and-white industrial poster suited to e-ink displays: high contrast, typography-driven, pixel-friendly, and still effective for long-term static display.
Default path:
- Write or modify a Takumi scene (
.tsx) - render locally into
webp/png/jpeg - Place the image at a URL accessible to LaraPaper
- Use
wrap_image_markup.pyto generate minimal Blade markup (by default prioritize addingimage-dither) - hand off to
trmnl-paper-screenfor pushing when needed
When to use
Prefer this skill for:
- Poster-style single screens
- Pixel art / pixelated key visuals
- Screenshot-style, illustration-style, cover-style layouts
- Content better suited to "render into an image first, then wrap it in TRMNL"
Switch to trmnl-paper-blade:
- Mainly KPI, lists, tables, rich text, item, table, progress
- Need to directly reuse
<x-trmnl::...>components - Need to edit local modules long-term later, rather than replacing the entire image
Current skill boundaries
Takumi upstream officially supports more than the current skill, such as raw HTML,measure()、renderAnimation()、raw frames、ImageResponse, emoji paths, etc.
Current trmnl-paper-takumi only wraps the most commonly used subset:
.tsxscene → local static image- persistent images(
--image key=path) - Optional Google Fonts dynamic loading
- External image URL → minimal TRMNL wrapper
When a more complete upstream boundary is needed, first read references/takumi-basics.md and references/api_reference.md。
Design direction
- By default prioritize black text on a white background; keep only a very small amount of grayscale as a supporting layer, and do not build hierarchy through multiple levels of transparency
- Keep only one absolute main focal point per screen, and demote the rest of the information to secondary / tertiary
- Hierarchy mainly relies on font size, font weight, whitespace, position, not shadows, gradients, or glass effects
- For composition, prioritize asymmetry, edge alignment, whitespace; avoid evenly filling the entire canvas with all elements
- Pixel art assets must be scaled by integer factors, and explicitly write
imageRendering: "pixelated" - Do not imagine hover, animation, spring motion, or complex interaction states for TRMNL
- You can absorb from Nothing references: minimalism, typography-driven, industrial feel, data as visual, monospaced labels, segmented progress bars, dot-grid textures; do not directly copy its dark mode tokens, complex grayscale, or interactive control language
For specific rules, counterexamples, and review checklists, read references/design-rules.md。
Workflow
- Determine whether it suits the image-first image-first path
- Choose or create a scene: prioritize copying from
assets/templates/Copy - Run
scripts/render_scene.tsxto generate the image - According to
references/design-rules.mdvisually inspect the composition, black-and-white hierarchy, whitespace, and readability - Upload the image to an accessible URL
- Run
scripts/wrap_image_markup.pyto generate a minimal wrapper (by default prioritize enablingimage-dither) - Use
trmnl-paper-blade/scripts/validate_markup.pyto validate the structure - When pushing is needed, hand off to
trmnl-paper-screen
Generation rules
- Canvas default
800x480 - The root node always explicitly writes width and height
- Takumi v1 default
display: inline; when container layout is needed, explicitly writedisplay: "flex"/tw="flex" - Layout first
tw; for precise pixel control, prioritizestyle - When enlarging pixel art, explicitly write
imageRendering: "pixelated" - Use integer dimensions and integer spacing whenever possible
- Default output
webp - Only when exporting from scene
googleFontsor explicitly passing--google-fontwill Google Fonts be loaded remotely - The wrapper is only responsible for placing one image; do not rebuild a complex TRMNL structure here
- The wrapper enables by default with priority
image-dither, because remote 1-bit / e-paper rendering often eats up grayscale, thin text, and thin lines - Only switch to this when you have confirmed that the original image is pure black-and-white hard-edged blocks and a real-device review proves it looks better without it
--no-dither
Available scripts
scripts/render_scene.tsx: Render scene to a local imagescripts/wrap_image_markup.py: Generate a minimal TRMNL wrapper
Suggested reading order
references/takumi-basics.md: Takumi capability boundaries, fonts, images, Google Fontsreferences/design-rules.md: E-ink screen design direction, Nothing style trade-offs, review checklistreferences/render-workflow.md: The entire pipeline from scene to wrapperreferences/trmnl-wrapper.md: Minimal TRMNL wrapping rulesreferences/examples.md: Common command examplesreferences/api_reference.md: Node API quick reference