{"id":"e4439e4c-96f1-48a3-bc50-bf9e157345a0","slug":"zhoushoujianwork-lvgl-preview-skill","kind":"skill","name":"lvgl-preview-skill","summary":"Claude Code skill: design embedded LVGL (MicroPython) UIs with a headless render→PNG feedback loop. Auto-adapts LVGL 8.x/9.x. Validated on K230 CanMV.","owner":"zhoushoujianwork","repoUrl":"https://github.com/zhoushoujianwork/lvgl-preview-skill","license":"MIT","licenseTier":"permissive","trust":"community","stars":3,"match":null,"fewStars":true,"format":"skill","createdAt":"2026-05-31T03:48:57.000Z","addedAt":"2026-10-14T05:16:07.532Z","logoUrl":"https://avatars.githubusercontent.com/u/40590631?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["browser-web","developer-tools","design-media"],"tags":[],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T22:49:18.974Z","sample":false,"url":"https://conduits.dev/tools/zhoushoujianwork-lvgl-preview-skill","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# lvgl-preview\n\nA **Claude Code skill** for designing embedded **LVGL** (MicroPython) UIs with a tight\nvisual feedback loop: write a `build(scr)` function, render it headless to a PNG on your\ncomputer, and have the agent *read the image* to confirm the result — no device, no\nbrowser, no flashing. Edit, render, look, iterate in seconds.\n\nAuto-adapts to **LVGL 8.x and 9.x** (fonts / `line` / `qrcode` / display binding branch on\nversion), so the same `build(scr)` runs on a v8 desktop preview *and* a v9 device like the\n**K230 CanMV**.\n\n![K230 access-control UI, 7 screens rendered on real hardware](examples/k230-access-control-7screens.png)\n\n> The gallery above is the K230 vision-gate access-control UI (standby / detecting /\n> extracting / success / failure / binding / sleep) — designed entirely through this\n> skill's desktop preview, then deployed pixel-faithfully to the real ST7701 panel.\n\n## Why\n\nIterating on an embedded LCD UI normally means flash → look at the panel → repeat, which is\nslow and invisible to an AI agent. This skill renders the **LVGL widget tree** through a\nheadless `lv_micropython` (SDL unix port) straight to a PNG, so:\n\n- **Edit → render → read PNG → iterate** in seconds, no hardware in the loop.\n- An AI agent can *see* its own UI and self-correct.\n- The exact same UI code ships to the device (only display init changes).\n\n## Install\n\nClone once, then `install.sh` **symlinks** the repo into your Claude Code skills dir — so\nyou develop in this one repo and every project picks up edits live (no copy, no re-sync):\n\n```bash\ngit clone https://github.com/zhoushoujianwork/lvgl-preview-skill.git\ncd lvgl-preview-skill\n./install.sh                      # -> ~/.claude/skills/lvgl-preview (all projects)\n./install.sh --project /path/app  # -> <app>/.claude/skills/lvgl-preview (one project)\n./install.sh --uninstall          # remove the link\n```\n\nThe skill triggers on phrases like \"lvgl preview\", \"渲染 LVGL\", \"embedded UI preview\".\n\n> ⚠️ **Symlink caveat for on-device dev:** `mpremote mount` does **not** follow symlinks.\n> If you mount a dir that imports `lvkit`, the mounted dir needs a **real** `lvkit.py`\n> (copy `lib/lvkit.py` in before mounting — see your device runner). The symlink install\n> above is for the host-side skill + desktop renderer, which follow symlinks fine.\n\n## Quickstart\n\n1. Build the desktop runtime once (needs SDL2 + a C toolchain):\n\n   ```bash\n   bash scripts/build_runtime.sh            # LVGL v8 (release/v8), default\n   # bash scripts/build_runtime.sh ~ v9     # or LVGL v9 (master)\n   export LVMP_BIN=$HOME/lv_micropython/ports/unix/micropython\n   ```\n\n   macOS arm64 / clang17 pitfalls are baked into the script. Linux: `apt install libsdl2-dev`.\n\n2. Write a UI module exposing `build(scr, **state)` (see `templates/ui_example.py`).\n\n3. Render it:\n\n   ```bash\n   python3 scripts/lvgl_preview.py templates/ui_example.py --out preview.png --size 480x800\n   ```\n\n4. Open `preview.png`. Adjust, re-render, repeat.\n\n## What's inside\n\n```\nlvgl-preview/\n  SKILL.md                  # the skill spec (Claude Code reads this)\n  scripts/\n    lvgl_preview.py         # host orchestrator: find binary -> render -> PNG\n    render.py               # headless renderer, auto-detects LVGL v8/v9 disp binding\n    raw2png.py              # BGRA frame -> PNG (Pillow)\n    build_runtime.sh        # build lv_micropython unix (v8 or v9)\n  lib/\n    lvkit.py                # version-aware primitives + CJK FreeType font helper\n  templates/\n    ui_example.py           # minimal build(scr) starter\n  docs/\n    device-binding.md       # copy-paste v8/v9 disp binding + CJK + screenshot-readback\n  examples/\n    k230-access-control-7screens.png   # real-hardware showcase\n```\n\n## The v8 / v9 story\n\nThe renderer and `lvkit.py` detect the LVGL major version once\n(`_V8 = hasattr(lv, \"disp_drv_t\")`) and branch the parts that differ between 8.x and 9.x:\n\n| | LVGL 8.x | LVGL 9.x |\n|---|---|---|\n| display | `disp_draw_buf_t` + `disp_drv_t` | `disp_create` + `set_draw_buffers` |\n| CJK font | `ft_info_t().font_init()` | `freetype_font_create(ttf, size, 0)` |\n| line points | `point_t` | `point_precise_t` |\n| qrcode | ctor args | object + setters |\n\nYour `build(scr)` uses the `lvkit` wrappers, so it stays version-agnostic. Going to a real\ndevice is just swapping the display init — `docs/device-binding.md` has the validated\nv8 and v9 snippets (plus CJK fonts and a screenshot-readback trick for headless debugging).\n\n## Requirements\n\n- A C toolchain + SDL2 (for `lv_micropython` unix). macOS: `brew install sdl2`. Linux: `libsdl2-dev`.\n- Python 3 with Pillow (`pip3 install Pillow`) for the PNG conversion.\n\n## License\n\nMIT — see [LICENSE](LICENSE). LVGL and lv_micropython are MIT-licensed by their authors.\n"}