PWNagotchi · Volume 7

PWNagotchi Volume 7 — Fancygotchi: the color-display theme engine

What Fancygotchi is, how it sits on top of jayofelony, how the theme JSON + sprite system works, and how to write custom faces

Fancygotchi (by fmatray) is a Pwnagotchi mod — really a partial re-implementation of the display pipeline — that does three things mainline Pwnagotchi does not:

  1. Color e-ink support. Mainline drives the b/w Waveshare 2.13” and the Pimoroni Inky pHAT (3-color) only. Fancygotchi adds drivers for the Pimoroni Inky Impression family (4”/5.7”/7.3” 7-color e-paper) and Waveshare’s larger ACEP color panels.
  2. Themable faces. Mainline ships a fixed set of ~20 pixel-art face expressions hardcoded in the daemon. Fancygotchi turns the face into a theme — a directory of PNG sprites plus a JSON descriptor — that you swap at runtime via a CLI command.
  3. A configurable UI layout. Mainline’s UI position (status row at top, face in the middle, log at bottom) is fixed. Fancygotchi exposes the layout as JSON: where the face goes, where the log goes, what fonts to use, what icons to show in the status row.

The name “Fancygotchi” is exactly what it sounds like — a “fancier-looking gotchi.” The underlying agent, bettercap engine, plugins, and config are all unchanged. You install jayofelony first, then Fancygotchi on top.

The community-meaning of “Fancygotchi” has drifted: some users use it to mean any Pwnagotchi running a custom theme; others use it strictly for the fmatray engine. This volume uses the strict meaning — the engine, not “any Pwnagotchi with a cool face.”

2. Why Fancygotchi exists

Mainline Pwnagotchi shipped with a fixed, small set of Waveshare/Inky drivers because evilsocket wrote the device for himself + a few friends. As the community grew, two pressure points hit:

  • The 7-color Pimoroni Inky Impression hit the market (~2019-2020) and quickly became the most-wanted display for hobbyist e-paper projects generally. No mainline driver existed.
  • Builders wanted their gotchis to be visually distinct. The fixed pixel-art face meant every Pwnagotchi looked identical, which is at odds with the “this is my pet” framing.

fmatray scratched both itches at once. Fancygotchi v1 (~2021) added the Inky Impression driver and a basic theme-swap. Subsequent releases broadened the theme system, added a small CLI tool (fancygotchi-theme), and integrated a handful of community-contributed themes shipped as a bundle.

3. Installation on top of jayofelony

The recommended install path:

  1. Flash jayofelony Pwnagotchi image (Vol 8). First-boot, SSH in, edit /etc/pwnagotchi/config.toml, confirm the gotchi runs in its stock UI.
  2. SSH into the Pi as root.
  3. Clone the Fancygotchi repo:
    cd /usr/local/share
    sudo git clone https://github.com/fmatray/Fancygotchi.git fancygotchi
  4. Run the installer:
    cd /usr/local/share/fancygotchi
    sudo ./install.sh
    The installer:
    • Patches the Pwnagotchi ui/ module to load Fancygotchi’s display dispatcher instead of mainline’s
    • Drops /etc/pwnagotchi/fancygotchi/ with the theme manager + default themes
    • Adds a fancygotchi-theme CLI to /usr/local/bin/
    • Restarts the pwnagotchi.service to pick up the patched UI
  5. Confirm with:
    fancygotchi-theme list
    Should print available themes.

If install.sh complains about Python version mismatch or missing PIL — those are jayofelony image version drift issues. The Fancygotchi README is kept up-to-date with which jayofelony versions are tested; consult before installing.

3.1 Configuring the display driver

Fancygotchi installs alongside the mainline Pwnagotchi display drivers. The config in /etc/pwnagotchi/config.toml:

[ui.display]
enabled = true
type = "inky_impression_4"            # NEW — Fancygotchi-provided driver
color = "auto"                         # Fancygotchi uses the full panel palette
rotation = 0

Driver types Fancygotchi adds:

Driver stringPanelNative resolution
inky_impression_4Pimoroni Inky Impression 4” 7-color640×400
inky_impression_5_7Pimoroni Inky Impression 5.7” 7-color600×448
inky_impression_7_3Pimoroni Inky Impression 7.3” 7-color800×480
waveshare_4in_7colorWaveshare 4.01” 7-color ACEP640×400
waveshare_5_65in_7colorWaveshare 5.65” 7-color ACEP600×448
waveshare_7_5in_7colorWaveshare 7.5” 7-color ACEP800×480

(Fancygotchi also re-exposes the mainline drivers — waveshare_4, inkyphat, etc. — so you can install it on a normal Pi + 2.13” build and just use it for the theming, even without color.)

4. The theme system

Fancygotchi themes live under /etc/pwnagotchi/fancygotchi/themes/. Each theme is a directory containing:

themes/
└── my_theme/
    ├── theme.json              # the theme descriptor
    ├── faces/                  # face sprite PNGs
    │   ├── awake.png
    │   ├── sleeping.png
    │   ├── happy.png
    │   ├── sad.png
    │   ├── excited.png
    │   ├── lonely.png
    │   ├── angry.png
    │   ├── intense.png
    │   ├── friend.png
    │   ├── broken.png
    │   ├── debug.png
    │   ├── upload.png
    │   └── ...                # one PNG per face state the daemon emits
    ├── icons/                  # status-row icons
    │   ├── battery.png
    │   ├── wifi.png
    │   └── peers.png
    └── fonts/                  # optional — bundled font files
        └── status.ttf

The face PNGs are at the panel’s native resolution (or scaled). The theme JSON is the wiring:

4.1 theme.json schema

{
  "name": "my_theme",
  "author": "tjscientist",
  "version": "1.0",
  "target_panel": "inky_impression_4",
  "background_color": "white",
  "palette": ["black", "white", "red", "yellow", "blue", "green", "orange"],
  "layout": {
    "face": {
      "position": [120, 80],
      "size": [400, 200]
    },
    "status_row": {
      "position": [0, 0],
      "items": [
        { "type": "icon",   "name": "battery", "position": [10, 10] },
        { "type": "text",   "name": "name",    "position": [50, 10], "font": "status.ttf", "size": 18 },
        { "type": "icon",   "name": "wifi",    "position": [580, 10] }
      ]
    },
    "counters": {
      "position": [10, 300],
      "items": [
        { "label": "APs",  "field": "ap_count",       "color": "blue" },
        { "label": "STAs", "field": "client_count",   "color": "green" },
        { "label": "SHK",  "field": "handshake_count","color": "red" }
      ]
    },
    "log": {
      "position": [10, 350],
      "size": [620, 40],
      "lines": 2,
      "font": "status.ttf",
      "size_pt": 12
    }
  },
  "faces": {
    "awake":     "faces/awake.png",
    "sleeping":  "faces/sleeping.png",
    "happy":     "faces/happy.png",
    "sad":       "faces/sad.png",
    "excited":   "faces/excited.png",
    "lonely":    "faces/lonely.png",
    "angry":     "faces/angry.png",
    "intense":   "faces/intense.png",
    "friend":    "faces/friend.png",
    "broken":    "faces/broken.png"
  }
}

Key fields:

  • target_panel — informs the engine which native resolution to render against.
  • palette — for color panels, this is the explicit color list and ordering (the IO order of e-paper colors is panel-specific; the engine handles the mapping).
  • layout.face.position — where the face PNG renders (top-left corner in pixels).
  • layout.status_row.items — array of UI elements with their positions, types (icon / text), and optional sources.
  • faces.* — mapping from daemon-emitted face state names to PNG files.

The daemon emits face state names (awake, sad, happy, etc.) as the gotchi cycles through its emotion machine. Fancygotchi renders the corresponding sprite. If a state is missing from the theme JSON, the engine falls back to the awake sprite + logs a warning.

4.2 The bundled themes

Fancygotchi ships with several themes in its repo’s themes/ directory:

ThemeAestheticTarget panel
defaultA faithful color port of the mainline pixel-art faceInky Impression 4”
kawaiiAnime-style, big eyes, pastel paletteInky Impression 4”
noirBlack-and-white film-noir aesthetic — works on 2-color panels tooWaveshare 2.13” v4
retro1980s arcade-cabinet style with chunky pixelsInky Impression 5.7”
tamaDirect visual quote of the original 1996 Tamagotchi (the irony returns)Any panel — adaptive

Switching themes:

fancygotchi-theme list                          # list available
fancygotchi-theme show my_theme                 # validate without applying
sudo fancygotchi-theme apply tama               # apply + restart pwnagotchi

4.3 Creating your own theme

  1. Copy default/ to your_theme/.
  2. Edit theme.json — at minimum, change name and author.
  3. Replace sprite PNGs in faces/. Use any image editor (GIMP, Inkscape exporting to PNG, Photoshop). For color panels, save with a palette matching palette exactly — otherwise the e-paper driver does a closest-color match that can be ugly.
  4. Test:
    sudo fancygotchi-theme show your_theme        # validate JSON
    sudo fancygotchi-theme apply your_theme       # apply
  5. Watch the e-ink redraw. The first frame may take 25-30 seconds on a 7-color panel; subsequent frames are similar (no partial refresh on color).

Pro tip: develop your sprites against a screen mockup before flashing them to e-ink. Fancygotchi ships a fancygotchi-render utility that renders the theme to a PNG file on disk so you can preview without burning panel cycles:

sudo fancygotchi-render your_theme --state happy --output /tmp/preview.png

5. Animated faces

Mainline Pwnagotchi’s faces are static (one PNG per state). Fancygotchi supports animation via a multi-frame PNG sequence convention:

faces/
├── happy/
│   ├── 0.png
│   ├── 1.png
│   ├── 2.png
│   └── 3.png

If theme.json references "happy": "faces/happy/" (a directory, not a file), Fancygotchi cycles through 0.pngN.png at the panel’s refresh rate. On an Inky Impression (25-30s per frame) this is impractical — animation works only on partial-refresh panels (Waveshare v3/v4 b/w; some Inky pHAT modes).

Realistic animation use cases: a 2-frame happy/eating cycle (chew open, chew closed) on a Waveshare v4 b/w, alternating ~once per second. Anything more sophisticated burns the panel for marginal visual gain.

6. Color e-paper palette wrangling

The 7-color e-paper panels (Inky Impression / Waveshare ACEP) have a fixed palette the panel hardware supports. The colors are not arbitrary RGB — they’re specific to the e-paper’s pigment chemistry. For the Inky Impression 4” 7-color:

IndexColorApproximate RGB
0Black#000000
1White#FFFFFF
2Green#00FF00 (approximation)
3Blue#0000FF
4Red#FF0000
5Yellow#FFFF00
6Orange#FFA500

When designing a theme:

  • Restrict your sprite palette to these 7 colors. Anti-aliased PNGs look terrible on e-paper (the driver dithers across the limited palette, producing speckled gradients).
  • Use solid blocks of color with crisp edges. The screen-printed-poster aesthetic is the genre.
  • Test by converting your sprite through Pillow with quantize(colors=7) and inspecting the result — if it survives that, the e-paper will render it well.

7. The compatibility matrix

Not every theme works on every panel. The Fancygotchi engine validates target_panel against the configured display at apply time; mismatches log a warning and either degrade gracefully or fall back to the default.

Theme targetWorks onNotes
inky_impression_4 (640×400, 7-color)Inky Impression 4”; degraded on 5.7” / 7.3” (centered, padded)Native fit
inky_impression_5_7 (600×448, 7-color)Inky Impression 5.7”; degraded on 4” (cropped)
waveshare_2_13_v4 (250×122, b/w)Waveshare 2.13” v3 / v4Themes designed for this are b/w-only
inkyphat (212×104, 3-color)Pimoroni Inky pHATUses 3-color palette only

A theme that targets a color panel can be force-applied to a b/w panel — Fancygotchi falls back to a 2-color quantization. The result is usually ugly. Better: maintain a separate b/w-target version of your theme for the small panels.

8. Distributing your own theme

If you want to share:

  1. Tarball your your_theme/ directory.
  2. License it explicitly — a LICENSE file inside the theme. Most community themes are CC-BY or MIT.
  3. Upload to GitHub or the Pwnagotchi community wiki.
  4. Optional: submit a pull request to the Fancygotchi repo to add it to the bundled themes.

The community-shared theme repo isn’t a formal registry — just informal git-share between users. The Reddit r/pwnagotchi and the Pwnagotchi Discord channel #fancygotchi are the discovery channels.

9. Fancygotchi + mainline Pwnagotchi feature parity

Fancygotchi only changes the display path. All other Pwnagotchi features work identically:

FeatureSame?
bettercap engine + capture pipelineYes
pwngrid social modeYes
A2C agentYes
All plugins (PiSugar, GPS, web UI, etc.)Yes — they emit events to the daemon; Fancygotchi only changes how face/status renders
config.tomlYes — Fancygotchi reads the same [ui.display] block, with extra driver types
Auto-updateYes (separately for jayofelony and Fancygotchi — they update independently)

The one thing to be aware of: if you uninstall Fancygotchi (a ./uninstall.sh script is provided), the daemon reverts to the mainline UI rendering. Your themes don’t disappear — they’re still in /etc/pwnagotchi/fancygotchi/themes/ — but they’re not loaded.

10. Failure modes specific to Fancygotchi

SymptomCauseFix
Theme apply succeeds but display unchangedPwnagotchi daemon needs restart to pick up the patched UIsudo systemctl restart pwnagotchi
Theme renders, but colors are wrongSprite PNG isn’t in the panel’s palette — the closest-color match is producing speckleRe-quantize sprite to the 7-color palette explicitly
Theme renders, but layout is broken (overflowing)position + size in theme JSON doesn’t match the actual panel resolutionCheck target_panel matches the installed panel
Animated face never animatesPanel doesn’t support partial refresh (Waveshare v1/v2, color panels)Use static frames; animation isn’t viable on slow panels
Daemon crashes on Fancygotchi loadMismatch between Fancygotchi version + jayofelony Pwnagotchi versionCheck Fancygotchi README for jayofelony version compat; update one or the other

11. Cheatsheet updates from this volume

Items to roll into Vol 12 (laminate-ready cheatsheet):

  • “Fancygotchi = theme engine + color e-paper drivers; install on top of jayofelony.” (§1, §3)
  • “Theme = directory under /etc/pwnagotchi/fancygotchi/themes/ with theme.json + face PNG sprites.” (§4)
  • “Apply: sudo fancygotchi-theme apply <name> + restart daemon.” (§4.2)
  • “Preview without burning panel cycles: fancygotchi-render.” (§4.3)
  • “Color sprites must use the panel’s native 7-color palette — don’t anti-alias.” (§6)