Hex dump
inspired by WerWolv, ImHex3
An xxd dump of a Linux executable’s first bytes. One string-table name is selected, the cursor just past it.
Made with Claude Opus 5.5
- Technique
- text characters
- Shape
- Any screen
- Added
- 27 September 2026
Colours
- #1C1B1Abackground
- #DAD8CEforeground
- #CF6A4Caccent
Export
FormatThis browser can’t make WebP files.
Shapecropped from 16:9
Crop
SizeThis browser can’t draw a file that large.
Notes
The bytes follow a 64-bit ELF file: its header, one program header, the first instructions of a function, then the names of its sections and symbols. The selected name breaks across two lines, and the rows around it stand out a little from the rest.
On a tall screen the dump shows eight bytes per line instead of sixteen, as xxd -c 8 prints it.
Sources
- Juergen Weigert, xxd.
- Executable and Linkable Format.
- WerWolv, ImHex. ↑
Source code
wallpapers/glyph-hexdump/design.py, 126 lines
"""An xxd dump of an ELF binary in bitmap glyphs, fading at top and bottom, one string selected."""
from walldye import (
ACCENT,
ACCENT_7,
ACCENT_HI,
BG,
BG_ALT,
UI,
UI_ALT,
Canvas,
Colour,
P,
Path,
Rng,
design,
mix,
smoothstep,
)
from walldye.pixel import glyphs
PX, FW, FH = 2, 8, 16
CW, CH = FW * PX, FH * PX # text cell
STR = 0x10F # string table start; splits "fireproof" as fire|proof across a row break
WORD = b"fireproof" # the selected string
SIZE = 1024 # bytes generated, more than the tallest screen shows
LIT = (1.0, 0.6, 0.25) # how far rows 0, 1 and 2 away from the selection brighten
FADE = 6 # tone steps from the top and bottom rows to the middle
def blob(r: Rng) -> bytes:
"""The first SIZE bytes of a plausible x86-64 ELF: header, a program header, code, the
string table at STR, then sparse data."""
hdr = bytes.fromhex(
"7f454c46020101000000000000000000"
"03003e00010000004010000000000000"
"4000000000000000b832000000000000"
"00000000400038000d00400020001f00"
"06000000040000004000000000000000"
"40000000000000004000000000000000"
"d802000000000000d802000000000000"
"0800000000000000"
)
code = bytes.fromhex("f30f1efa554889e54883ec10897dfc488975f0bf00000000e8")
code += bytes(r.randrange(256) for _ in range(STR))
strs = b"\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.rodata\0.comment\0"
strs += WORD + b"\0main\0_start\0GCC: (GNU) 14.2.1\0"
tail = bytes(r.choice([0, 0, 0, r.randrange(256)]) for _ in range(SIZE))
return ((hdr + code)[:STR] + strs + tail)[:SIZE]
@design(aspects="any")
def draw(s: Canvas) -> None:
# xxd -c 16 on landscape screens, -c 8 on portrait ones: same glyph size, a narrower block
n = 16 if s.landscape else 8
hex0, hex1 = 10, 10 + n // 2 * 5 - 1 # hex columns, in groups of two bytes
asc0 = hex1 + 2 # ASCII columns
cols, rows = asc0 + n, s.h // CH
data = blob(s.rng(5))
lo = data.index(WORD)
hi = lo + len(WORD) # selected bytes [lo, hi); the cursor sits on hi
# Start the dump so the selection sits a little below the middle row.
top = max(0, lo // n - round(0.62 * rows))
base = top * n
sel_rows = range(lo // n - top, (hi - 1) // n - top + 1)
lines = []
for r in range(rows):
a = base + r * n
chunk = data[a : a + n]
hx = " ".join(chunk[k : k + 2].hex() for k in range(0, n, 2))
asc = "".join(chr(b) if 32 <= b < 127 else "." for b in chunk)
lines.append(f"{a:08x}: {hx} {asc}")
# 0.6125 puts the block's left edge on the first third of a 16:9 screen (x=640)
c = s.pick(landscape=(0.6125, 0.5), portrait=(0.5, 0.5), snap=PX)
x0, y0 = c - (cols * CW // 2, rows * CH // 2)
def cell(a: int) -> tuple[int, int, int]:
"""Row, hex column and ASCII column of byte `a`."""
r, k = divmod(a - base, n)
return r, hex0 + k // 2 * 5 + k % 2 * 2, asc0 + k
def addr(c: int, r: int) -> int | None:
"""Byte address under text cell (c, r), or None for offset and spacing cells."""
if hex0 <= c < hex1 and (c - hex0) % 5 != 4:
return base + r * n + (c - hex0) // 5 * 2 + (c - hex0) % 5 // 2
if asc0 <= c < cols:
return base + r * n + c - asc0
return None
def span(d: Path, r: int, c0: int, c1: int) -> Path:
"""`d` with text cells c0..c1 of row r, inclusive, added as one rect."""
return d.rect(x0 + c0 * CW, y0 + r * CH, (c1 - c0 + 1) * CW, CH)
# selection: one rect per row across the hex groups and one across the ASCII gutter
band = P()
for r in sel_rows:
a0, a1 = max(lo, base + r * n), min(hi, base + (r + 1) * n) - 1
(_, h0, g0), (_, h1, g1) = cell(a0), cell(a1)
span(span(band, r, h0, h1 + 1), r, g0, g1)
s.fill(band, ACCENT_7)
r, h, g = cell(hi)
s.fill(span(span(P(), r, h, h + 1), r, g, g), ACCENT_HI)
def paint(c: int, r: int, _ch: str) -> Colour | None:
a = addr(c, r)
if a is not None and lo <= a < hi:
return ACCENT
if a == hi:
return BG # knocked out of the cursor block
edge = min(r + 0.5, rows - r - 0.5) / (rows / 2)
step = round(smoothstep(0.05, 0.95, edge) * FADE)
if step == 0:
return None # the outermost rows would sit within a few levels of BG; skip them
near = min(abs(r - k) for k in sel_rows)
lit = LIT[near] if near < len(LIT) else 0 # the dump brightens around the selection
if c < hex0:
tone = mix(BG_ALT, UI, 0.2)
elif c >= asc0:
tone = mix(mix(BG_ALT, UI, 0.6), UI, lit)
else:
tone = mix(UI, UI_ALT, lit)
return mix(BG, tone, 0.1 + 0.9 * step / FADE)
glyphs(s, lines, paint, at=(x0, y0), font="8x16", px=PX)"""An xxd dump of an ELF binary in bitmap glyphs, fading at top and bottom, one string selected."""
from walldye import (
ACCENT,
ACCENT_7,
ACCENT_HI,
BG,
BG_ALT,
UI,
UI_ALT,
Canvas,
Colour,
P,
Path,
Rng,
design,
mix,
smoothstep,
)
from walldye.pixel import glyphs
PX, FW, FH = 2, 8, 16
CW, CH = FW * PX, FH * PX # text cell
STR = 0x10F # string table start; splits "fireproof" as fire|proof across a row break
WORD = b"fireproof" # the selected string
SIZE = 1024 # bytes generated, more than the tallest screen shows
LIT = (1.0, 0.6, 0.25) # how far rows 0, 1 and 2 away from the selection brighten
FADE = 6 # tone steps from the top and bottom rows to the middle
def blob(r: Rng) -> bytes:
"""The first SIZE bytes of a plausible x86-64 ELF: header, a program header, code, the
string table at STR, then sparse data."""
hdr = bytes.fromhex(
"7f454c46020101000000000000000000"
"03003e00010000004010000000000000"
"4000000000000000b832000000000000"
"00000000400038000d00400020001f00"
"06000000040000004000000000000000"
"40000000000000004000000000000000"
"d802000000000000d802000000000000"
"0800000000000000"
)
code = bytes.fromhex("f30f1efa554889e54883ec10897dfc488975f0bf00000000e8")
code += bytes(r.randrange(256) for _ in range(STR))
strs = b"\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.rodata\0.comment\0"
strs += WORD + b"\0main\0_start\0GCC: (GNU) 14.2.1\0"
tail = bytes(r.choice([0, 0, 0, r.randrange(256)]) for _ in range(SIZE))
return ((hdr + code)[:STR] + strs + tail)[:SIZE]
@design(aspects="any")
def draw(s: Canvas) -> None:
# xxd -c 16 on landscape screens, -c 8 on portrait ones: same glyph size, a narrower block
n = 16 if s.landscape else 8
hex0, hex1 = 10, 10 + n // 2 * 5 - 1 # hex columns, in groups of two bytes
asc0 = hex1 + 2 # ASCII columns
cols, rows = asc0 + n, s.h // CH
data = blob(s.rng(5))
lo = data.index(WORD)
hi = lo + len(WORD) # selected bytes [lo, hi); the cursor sits on hi
# Start the dump so the selection sits a little below the middle row.
top = max(0, lo // n - round(0.62 * rows))
base = top * n
sel_rows = range(lo // n - top, (hi - 1) // n - top + 1)
lines = []
for r in range(rows):
a = base + r * n
chunk = data[a : a + n]
hx = " ".join(chunk[k : k + 2].hex() for k in range(0, n, 2))
asc = "".join(chr(b) if 32 <= b < 127 else "." for b in chunk)
lines.append(f"{a:08x}: {hx} {asc}")
# 0.6125 puts the block's left edge on the first third of a 16:9 screen (x=640)
c = s.pick(landscape=(0.6125, 0.5), portrait=(0.5, 0.5), snap=PX)
x0, y0 = c - (cols * CW // 2, rows * CH // 2)
def cell(a: int) -> tuple[int, int, int]:
"""Row, hex column and ASCII column of byte `a`."""
r, k = divmod(a - base, n)
return r, hex0 + k // 2 * 5 + k % 2 * 2, asc0 + k
def addr(c: int, r: int) -> int | None:
"""Byte address under text cell (c, r), or None for offset and spacing cells."""
if hex0 <= c < hex1 and (c - hex0) % 5 != 4:
return base + r * n + (c - hex0) // 5 * 2 + (c - hex0) % 5 // 2
if asc0 <= c < cols:
return base + r * n + c - asc0
return None
def span(d: Path, r: int, c0: int, c1: int) -> Path:
"""`d` with text cells c0..c1 of row r, inclusive, added as one rect."""
return d.rect(x0 + c0 * CW, y0 + r * CH, (c1 - c0 + 1) * CW, CH)
# selection: one rect per row across the hex groups and one across the ASCII gutter
band = P()
for r in sel_rows:
a0, a1 = max(lo, base + r * n), min(hi, base + (r + 1) * n) - 1
(_, h0, g0), (_, h1, g1) = cell(a0), cell(a1)
span(span(band, r, h0, h1 + 1), r, g0, g1)
s.fill(band, ACCENT_7)
r, h, g = cell(hi)
s.fill(span(span(P(), r, h, h + 1), r, g, g), ACCENT_HI)
def paint(c: int, r: int, _ch: str) -> Colour | None:
a = addr(c, r)
if a is not None and lo <= a < hi:
return ACCENT
if a == hi:
return BG # knocked out of the cursor block
edge = min(r + 0.5, rows - r - 0.5) / (rows / 2)
step = round(smoothstep(0.05, 0.95, edge) * FADE)
if step == 0:
return None # the outermost rows would sit within a few levels of BG; skip them
near = min(abs(r - k) for k in sel_rows)
lit = LIT[near] if near < len(LIT) else 0 # the dump brightens around the selection
if c < hex0:
tone = mix(BG_ALT, UI, 0.2)
elif c >= asc0:
tone = mix(mix(BG_ALT, UI, 0.6), UI, lit)
else:
tone = mix(UI, UI_ALT, lit)
return mix(BG, tone, 0.1 + 0.9 * step / FADE)
glyphs(s, lines, paint, at=(x0, y0), font="8x16", px=PX)
Run it yourself
$ git clone https://github.com/nickolaj-jepsen/walldye && cd walldye$ uv run walldye render glyph-hexdump --theme fireproof -o glyph-hexdump-fireproof-16x9.svg