Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

install-firmware.sh: wrap MrChromebox ROM with AC splash + boot tweaks

Hosted at https://aesthetic.computer/install-firmware.sh — one-liner to
install MrChromebox's UEFI firmware on a supported Chromebook with the
aesthetic.computer boot splash baked in.

curl -fsSL https://aesthetic.computer/install-firmware.sh | sudo bash

The script doesn't re-build coreboot; it inherits MrChromebox's signed
per-board ROMs and just swaps bootsplash.bmp inside CBFS via cbfstool,
then flashes with flashrom. Upstream firmware fixes flow through
automatically on every re-run.

Also shortens etc/boot-menu-wait to 500ms (stock is 2500ms) so the
splash doesn't linger. A backup of the current firmware is written to
/tmp/firmware-backup-<ts>.rom before anything gets written.

Assets the script downloads from /firmware/:
- ac-splash.bmp 1366x768 24-bit BMP replacing the MrChromebox rabbit
- cbfstool static-linked coreboot CBFS editor

TODO (follow-up):
- Commit the actual ac-splash.bmp and cbfstool binary assets.
- Board auto-detect works on ChromeOS-style firmware (crossystem +
DMI). Add a fallback for coreboot/edk2 where neither is reliable.
- Provide a --restore flag that writes the nearby
BACKUP-*-Google_*.rom file if present on the USB.

Docs referenced:
- https://docs.mrchromebox.tech/docs/firmware/
- https://doc.coreboot.org/util/cbfstool/index.html

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+174 -1
+10 -1
system/public/_headers
··· 2 2 Access-Control-Allow-Origin: * 3 3 Cache-Control: no-cache, no-store, must-revalidate 4 4 Pragma: no-cache 5 - Expires: 0 5 + Expires: 0 6 + 7 + # Firmware install script + assets — served as text/plain or 8 + # application/octet-stream so `curl | bash` and raw binary downloads 9 + # both work without content negotiation surprises. 10 + /install-firmware.sh 11 + Content-Type: text/plain; charset=utf-8 12 + Cache-Control: public, max-age=60 13 + /firmware/* 14 + Cache-Control: public, max-age=3600
+20
system/public/firmware/README.md
··· 1 + # Firmware customization assets 2 + 3 + Files referenced by [`/install-firmware.sh`](../install-firmware.sh): 4 + 5 + - `ac-splash.bmp` — 1366×768 24-bit BMP that replaces the MrChromebox 6 + rabbit at boot. Must be uncompressed BMP (coreboot's splash decoder 7 + is minimal); generated from `system/scripts/firmware-splash.mjs`. 8 + - `cbfstool` — statically-linked linux-x86_64 binary used to edit the 9 + coreboot CBFS of the downloaded base ROM. Upstream build recipe 10 + lives at https://doc.coreboot.org/util/cbfstool/index.html. 11 + 12 + Pipeline: 13 + 14 + 1. `install-firmware.sh` downloads the board's signed ROM from 15 + MrChromebox's CDN. 16 + 2. Downloads `ac-splash.bmp` + `cbfstool` from here. 17 + 3. Swaps the splash and tweaks `etc/boot-menu-wait` inside CBFS. 18 + 4. Flashes the composed ROM via `flashrom -p internal -w`. 19 + 20 + Both assets are published by `npm run firmware:publish` (TODO).
+144
system/public/install-firmware.sh
··· 1 + #!/usr/bin/env bash 2 + # install-firmware.sh — install a MrChromebox UEFI firmware with the 3 + # aesthetic.computer boot splash baked in. 4 + # 5 + # Usage (from a ChromeOS developer shell or from ac-native's prompt): 6 + # 7 + # curl -fsSL https://aesthetic.computer/install-firmware.sh | sudo bash 8 + # 9 + # This does NOT re-build coreboot — we inherit Mr Chromebox's signed 10 + # per-board ROM from https://mrchromebox.tech/ and only swap the 11 + # bootsplash.bmp inside CBFS with our own. Upstream firmware fixes flow 12 + # through automatically on each re-run. 13 + # 14 + # Docs we follow: 15 + # https://docs.mrchromebox.tech/docs/firmware/ 16 + # https://doc.coreboot.org/util/cbfstool/index.html 17 + # 18 + # Safety: 19 + # 1. Always backs up current firmware to /tmp/firmware-backup-<ts>.rom 20 + # AND echoes the path so the user can copy it to a USB before reboot. 21 + # 2. Refuses to flash unless `flashrom` is able to read the chip and 22 + # the signed ROM we composed is the expected size. 23 + # 3. `--dry-run` skips the final `flashrom -w` so you can inspect the 24 + # composed ROM first. 25 + 26 + set -euo pipefail 27 + 28 + AC_CDN="${AC_CDN:-https://aesthetic.computer}" 29 + MRC_CDN="${MRC_CDN:-https://mrchromebox.tech/files/firmware/full_rom}" 30 + WORK="${WORK:-/tmp/ac-firmware.$$}" 31 + DRY_RUN="${DRY_RUN:-0}" 32 + 33 + log() { printf "\033[0;36m[ac-fw]\033[0m %s\n" "$*"; } 34 + err() { printf "\033[0;31m[ac-fw]\033[0m %s\n" "$*" >&2; } 35 + die() { err "$*"; exit 1; } 36 + 37 + for arg in "$@"; do 38 + case "$arg" in 39 + --dry-run) DRY_RUN=1 ;; 40 + --help|-h) 41 + sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//' 42 + exit 0 ;; 43 + esac 44 + done 45 + 46 + [ "$(id -u)" = "0" ] || die "Must run as root (use sudo)." 47 + 48 + mkdir -p "$WORK" 49 + trap 'rm -rf "$WORK"' EXIT 50 + 51 + # ── 1. Detect board ──────────────────────────────────────────────── 52 + log "Detecting board…" 53 + BOARD="" 54 + if command -v crossystem >/dev/null 2>&1; then 55 + # ChromeOS-style — most reliable on stock + MrChromebox firmware. 56 + BOARD=$(crossystem hwid 2>/dev/null | awk '{print tolower($1)}' | cut -d- -f1) 57 + fi 58 + if [ -z "$BOARD" ] && [ -f /sys/class/dmi/id/product_name ]; then 59 + BOARD=$(tr -d '\0\n' < /sys/class/dmi/id/product_name | tr '[:upper:] ' '[:lower:]_' | cut -d. -f1) 60 + fi 61 + [ -n "$BOARD" ] || die "Could not detect board. Set BOARD=<name> and re-run." 62 + log " board: $BOARD" 63 + 64 + # ── 2. Tools ─────────────────────────────────────────────────────── 65 + # Mr Chromebox's script already installs flashrom; we need cbfstool too. 66 + # Ship a static-linked cbfstool on our CDN so ac-native's minimal busybox 67 + # init doesn't need a full coreboot toolchain to get this working. 68 + need() { command -v "$1" >/dev/null 2>&1 || return 1; } 69 + fetch() { 70 + local url="$1" out="$2" 71 + curl -fsSL --retry 3 -o "$out" "$url" \ 72 + || die "Download failed: $url" 73 + } 74 + 75 + if ! need flashrom; then 76 + die "flashrom not installed. On ChromeOS dev shell: 'sudo pacman -Sy flashrom' or install via your distro." 77 + fi 78 + 79 + CBFSTOOL="$WORK/cbfstool" 80 + if need cbfstool; then 81 + cp "$(command -v cbfstool)" "$CBFSTOOL" 82 + else 83 + log "Fetching cbfstool from $AC_CDN/firmware/cbfstool…" 84 + fetch "$AC_CDN/firmware/cbfstool" "$CBFSTOOL" 85 + chmod +x "$CBFSTOOL" 86 + fi 87 + "$CBFSTOOL" -h >/dev/null 2>&1 || die "cbfstool unusable — try reinstalling." 88 + 89 + # ── 3. Download base ROM from MrChromebox ───────────────────────── 90 + BASE_ROM="$WORK/base.rom" 91 + MRC_URL="$MRC_CDN/coreboot_tiano-$BOARD-mrchromebox.rom" 92 + log "Fetching MrChromebox ROM for '$BOARD'…" 93 + fetch "$MRC_URL" "$BASE_ROM" 94 + BASE_SIZE=$(stat -c%s "$BASE_ROM") 95 + log " size: $((BASE_SIZE / 1024 / 1024))MB ($BASE_SIZE bytes)" 96 + 97 + # ── 4. Apply aesthetic.computer customizations ──────────────────── 98 + AC_ROM="$WORK/ac.rom" 99 + cp "$BASE_ROM" "$AC_ROM" 100 + 101 + # Swap the bootsplash. BMP must be 1366x768 24/32-bit uncompressed 102 + # (coreboot's splash decoder is minimal). AC ships a pre-baked copy at 103 + # /firmware/ac-splash.bmp — overrideable via env SPLASH_URL. 104 + SPLASH_URL="${SPLASH_URL:-$AC_CDN/firmware/ac-splash.bmp}" 105 + if curl -fsSL --head "$SPLASH_URL" >/dev/null 2>&1; then 106 + SPLASH="$WORK/splash.bmp" 107 + log "Fetching splash: $SPLASH_URL" 108 + fetch "$SPLASH_URL" "$SPLASH" 109 + "$CBFSTOOL" "$AC_ROM" remove -n bootsplash.bmp 2>/dev/null || true 110 + "$CBFSTOOL" "$AC_ROM" add -f "$SPLASH" -n bootsplash.bmp -t raw 111 + log " ✓ swapped bootsplash.bmp" 112 + else 113 + log " splash not available at $SPLASH_URL — skipping (keeping MrChromebox rabbit)." 114 + fi 115 + 116 + # Shorten the boot-menu wait. Upstream default is 2500ms; we want 500ms. 117 + "$CBFSTOOL" "$AC_ROM" add-int -i 500 -n etc/boot-menu-wait 2>/dev/null \ 118 + || log " (could not set etc/boot-menu-wait; continuing)" 119 + 120 + # Verify size didn't change. 121 + AC_SIZE=$(stat -c%s "$AC_ROM") 122 + [ "$AC_SIZE" = "$BASE_SIZE" ] || die "Size mismatch after customization: $AC_SIZE vs $BASE_SIZE." 123 + log " customized ROM size OK" 124 + 125 + # ── 5. Backup current firmware ──────────────────────────────────── 126 + BACKUP="/tmp/firmware-backup-$(date +%Y%m%d-%H%M%S).rom" 127 + log "Backing up current firmware → $BACKUP" 128 + flashrom -p internal -r "$BACKUP" 2>&1 | grep -vE "^(flashrom|Calibrating)" || true 129 + [ -s "$BACKUP" ] || die "Backup read failed — refusing to flash." 130 + log " ✓ backup saved ($(du -h "$BACKUP" | cut -f1))" 131 + 132 + # ── 6. Flash ────────────────────────────────────────────────────── 133 + if [ "$DRY_RUN" = "1" ]; then 134 + log "DRY_RUN=1 — stopping before flash." 135 + log " composed ROM: $AC_ROM" 136 + log " current backup: $BACKUP" 137 + exit 0 138 + fi 139 + 140 + log "Flashing customized ROM…" 141 + flashrom -p internal -w "$AC_ROM" 2>&1 | grep -vE "^(Calibrating|Reading old|Erasing|Writing)" || true 142 + 143 + log "✅ Done. Reboot when ready — new splash takes effect next boot." 144 + log " backup: $BACKUP"