# PXE menu theme — research for next-release follow-up

Status: queued. v0.4.63 keeps the ASCII-banner fallback + `console --picture`
compositor wired; this note captures the design for the menu-theming work
that lands once iPXE rebuilt with `IMAGE_PNG` is published.

## How iVentoy actually does it

iVentoy is closed-source for its menu, but the supporting bits are
public at https://github.com/ventoy/PXE — a vanilla iPXE snapshot
(`iPXE/ipxe-bd13697`) used to produce the loader binaries iVentoy
serves over TFTP (`pxeboot.efi`, `iventoy_loader_16000`,
`iventoy_loader_16000_uefi`).

The graphical menu itself is rendered by iPXE's framebuffer console
with a baked-in PNG background via `console --picture` — same
primitive OpenPXE already uses in `crates/http-api/src/ipxe_script.rs`.
Evidence:

- The iPXE build in `ventoy/PXE` is configured with `CONSOLE_FRAMEBUFFER`
  + `IMAGE_PNG` + `CONSOLE_CMD` (the three flags `console --picture`
  needs).
- iVentoy issue #11 confirms "iventoy using default 1024x768"; users
  report 800x600 / 1024x768 / 1280x720 / 1280x1024 / 1920x1080 as
  selectable resolutions from the iVentoy web UI **Configuration tab**,
  not via EDID auto-detect. iPXE has no EDID parsing; the daemon writes
  a resolution-tagged script per boot and serves the matching PNG.
- iVentoy docs explicitly state both Free and Pro editions **do not
  support** modifying the boot background/title — it's baked into the
  shipped PNG assets.
- Chrome is iPXE's native `menu` / `item` / `choose` widgets (single
  highlight bar, no borders) painted on top of the PNG, with margins
  set via `console --left/--right/--top/--bottom` to keep the text off
  the logo. Not GRUB, not syslinux — UEFI iVentoy uses iPXE's
  `snponly.efi` / `pxeboot.efi`, and `--picture` does work under UEFI
  GOP despite older folklore.

Do not conflate this with Ventoy-USB, which is a separate codebase and
uses GRUB2 themes (`theme.txt`, `background_ventoy.png`, `select_c.png`).

## Rust ingredients to replicate / surpass

Most of these already exist in the workspace.

1. **Compositor (extend, don't replace)** — extend
   `crates/iso-store/src/pxe_logo.rs` to emit per-resolution PNGs
   (1024x768, 1280x1024, 1920x1080 as the v1 set). `image` +
   `imageproc` crates handle scaling; `ab_glyph` / `fontdue` for raster
   text (subtitle, hostname, version). One source SVG/logo, three to
   five rendered PNGs cached on disk.
2. **Script generator** — `ipxe_script.rs` already emits
   `console --picture … || console`. Add a `?res=` query param (or
   per-MAC client hint persisted in `hosts.json`) and serve the matching
   PNG plus matching `console --x --y` line. Keep the text-console
   fallback already in place.
3. **Resolution selection** — iPXE exposes `${vesa-x}` / `${vesa-y}` on
   BIOS; UEFI side we can probe firmware vars at chain-time. The simpler
   v1 is a "low-res / hi-res" toggle in Settings plus a per-host
   override — mirrors iVentoy's UX, no kernel helper needed. True EDID
   parsing is overkill for the first cut.
4. **Chrome upgrades over iVentoy** — iPXE menus are limited (single
   highlight, no borders). To look distinctly cooler without leaving
   iPXE: paint border / title / footer **into the PNG**, leave a window
   in the middle, then `console --left/--right/--top/--bottom` to inset
   the iPXE menu exactly into that window. ASCII box-drawing inside the
   menu remains fragile (iPXE mangles non-ASCII on some builds — already
   noted in `ipxe_script.rs`).

## Recommended architecture for the next OpenPXE release

- Build a `pxe_theme` module beside `pxe_logo.rs`: takes operator logo
  + theme tokens (accent colour, title, footer) and renders a layered
  PNG (background gradient → framing chrome → logo → title bar → footer
  with `${hostname}` / `${version}` / `${ip}`) at the three target
  resolutions. Cache by hash of inputs.
- Serve at `/branding/pxe-menu-{w}x{h}.png`. Default 1024x768; expose a
  Settings dropdown.
- In `ipxe_script.rs`, emit
  `console --picture …/pxe-menu-1024x768.png --left 80 --right 80 --top 180 --bottom 60 || console`,
  then the existing `menu` / `item` / `choose` block — text now lands
  inside the framed window.
- Compile iPXE with `CONSOLE_FRAMEBUFFER`, `IMAGE_PNG`, `CONSOLE_CMD`,
  `CONSOLE_VESAFB` (BIOS) and `CONSOLE_EFIFB` (UEFI). The v0.4.61 image
  attempted this in-Docker via QEMU emulation and hit `cc1` segfaults.
  The follow-up will use a Gitea Actions runner pinned to native
  `linux/amd64` (an Unraid host already exists for this).
- Stretch goal: a second "theme pack" that ships a layered PNG with
  subtle scanlines / grid — iPXE can't animate, but a well-designed
  static composite beats iVentoy's plain centered logo handily.

## Source URLs

- https://github.com/ventoy/PXE
- https://github.com/ventoy/PXE/tree/master/iPXE
- https://github.com/ventoy/PXE/issues/11 — 1024x768 default
- https://github.com/ventoy/PXE/issues/59 — iVentoy iPXE EFI loader
- https://ipxe.org/cmd/console — `--picture` and compile flags
- https://github.com/ipxe/ipxe/discussions/945 — background image how-to
- https://github.com/ipxe/ipxe/discussions/802 — `CONSOLE_FRAMEBUFFER`
  requirement
- https://github.com/ipxe/ipxe/discussions/1006 — picture resolution
  behaviour
- https://www.iventoy.com/en/doc_edition.html — background / title not
  user-customisable
- https://kingtam.win/archives/iventoy.html — third-party iPXE-based
  iVentoy alternative
