Milo BRAND + INTERFACE SYSTEM V1.2
40Live Wallpaper

The painting stays. The glyphs read it.

offline's desktop keeps a real painting or park photograph behind everything, in full colour. Over it, small Matrix-style characters re-draw the picture along its own contours and light, in its own colours, and a slow wave of light runs through them. Nothing rains.

LAYER offline.wallpaper-dataPASSES 3 · GPUSETTINGS 31 · PRESETS 3GALLERY 37 · DARK 17 · LIGHT 20SOURCE offline-os lane-c 8af08e48
On the laptop A screenshot of the offline desktop on the laptop: Caravaggio's Conversion of Saint Paul fills the screen in full colour. Tiny characters sit along the arms, the horse's legs and the folds of the cloak, most in the painting's own colours, a few in vermilion and moss. The picture's name card sits bottom left.
Screenshot · wkgd-macbook · 2026-09-26 12:18 · the installed layerCaravaggio · The Conversion of Saint Paul · 1601
1:1 device pixels A close-up at actual size: the horse's hoof, a pale leg and an orange cloak. Glyphs five dots wide follow the edges of the hoof and the folds; flat paint carries only a few; a handful are vermilion on the warm cloak and moss on the cool ground.
computationally transformedSame painting, same shaders, drawn offscreen

Left: a screenshot of the laptop's own screen (2560 × 1600 panel, shown at half size). Right: the same shaders drawn offscreen on the M4 Mac at the default settings, cropped at one device pixel per pixel. Caravaggio, 1601, Santa Maria del Popolo, Rome · public domain, via Wikimedia Commons.

What it is, and why40.0

Matrix glyphs that trace a painting.

The picture is the point. The glyphs are a second, quieter drawing of it: sparse, the painting's own colours one small step lighter or darker, gathered on its edges, lit by a wave that follows its light.

The desktop is the one place a computer shows you something for hours without asking anything of you. offline puts a public-domain painting or a national-park photograph there, untreated, and adds one living layer. The layer reads the picture once — its edges, the way its lines run, where its subject is, where its light falls — and then re-draws it in tiny characters: half-width katakana drawn mirrored as the film drew them, digits, a few marks, and four strokes that follow a contour's direction.

Three things make it Milo and not a screensaver. It reads the picture: no glyph position, colour or motion is invented; each comes from the paint under it. It stays out of the way: most cells are empty, the name card keeps clear air, and the picture shows through everywhere. The accents mean something: vermilion is Milo and moss is offline, so the only colours the layer adds are the two the brand reserves, on the contours, a few in a hundred.

The owner's brief, in his words, and the rules it became11

From the code's own comments, which quote every request: “I want the effect to be almost like its recreated the image underneath. When the image changes a new pattern emerges based on the image.” · “not like to where the underneith image cant be seen” · “match the color of the underlying image, with the bits of vermillion and moss green still” · “doesnt need to rain as much as digitally undulate” · “folo the contours and lights and shadows” · “a sleeker smoother animation that isnt taxing”.

  • The painting is full colour and untouched unless someone turns a treatment on.
  • Glyph colour is the paint beneath, moved in lightness only (OKLab), hue and chroma kept.
  • Glyphs gather on contours, tonal edges and fine detail; plain paint keeps a light floor.
  • Vermilion and moss appear only on contours: vermilion where the paint is warm, moss where it is cool.
  • Every motion is a smooth function of time: no frame holds and then jumps.
  • A new picture brings a new pattern, from its own maps and its own hash.
  • Falling columns, rain, or anything that scrolls.
  • Characters so dense the painting cannot be seen.
  • Colours invented for the layer, or brand colour everywhere.
  • A layer that keeps running when the machine is hot, locked, idle or low on battery.
  • A still that cuts: a new picture fades in, its glyphs arrive lit edges first.
Live demo · the real shaders, in this page40.1

Try it on a real painting.

The three passes ported line for line to WebGL, on the gallery's own cut and the maps the desktop made from it. Move a slider and watch the painting; move the pointer over it and the glyphs part.

Caravaggio's Conversion of Saint Paul with the glyph layer at its default settings.
Loading the painting and its maps…

Caravaggio · The Conversion of Saint Paul · 1601 · Santa Maria del Popolo, Rome · public domain

Stops by itself off-screen.
Picture
Level
How many glyphs: lower is sparser, higher denser.
Lower: heavy glyphs spread over more of the picture. Higher: only its strongest tones.
Low is a hard cut from light glyphs to heavy; high, a slow blend.
How bright the crest is that runs from the lit paint into the shadow. 0 is no wave.
Time between crests at any one place.
How many accent glyphs ride the contours. 0 is none.
How far a glyph stands from its paint, in OKLab lightness.
The haze the crest spreads round the glyphs it lifts, in their own colour.
Screen pixels per glyph dot.
The most frames a second it draws. Lower saves battery and heat.
How this demo differs from the desktop, and what it costs

engine/glyphs.js carries lane-c's three fragment shaders with only two changes WebGL2 needs: plain uniforms instead of Qt's uniform block, and render targets read with their rows flipped. The painting, its shape map and its light map are the files the laptop uses (offline/wallpaper_map.py, 160 × 100 texels); the picture's pattern dials are the same numbers the laptop reported for it. The canvas is the dot grid and the browser scales it up with image-rendering: pixelated, which is what the shell's own un-smoothed layer does.

Differences: there is no name card, so nothing is kept clear; the browser draws at most at the frame-rate cap on its own clock; and the panel's device-pixel ratio is capped at 2. It stops drawing when it scrolls out of view, when the tab is hidden and when paused. Under reduced motion it draws one still frame with the wave and the moments off, exactly as the desktop holds still.

Layers and passes40.2

Read once. Draw three times. Mostly empty.

The expensive reading happens once per picture on the processor. Each frame is three small GPU passes, and the biggest of them only draws dots that are lit.

  1. Once per picture

    Picture

    The painting, cut edge to edge to 2560 × 1600, shown at full colour under everything. A new one crossfades in over 1.4 s.

    1 texture
  2. Once per picture · CPU

    Maps

    wallpaper_map.py reads it at 160 wide: edge strength, subject, contour direction; light and fine detail. Cached by the picture's hash.

    2 × 160 × 100 texels
  3. Once per picture · GPU

    Ground

    glyph-ground.frag: one pixel a cell. Each cell's ink (the paint, one lightness step away) and its tone (how heavy its glyph is). No clock.

    214 × 89 cells on the laptop
  4. Every frame · GPU

    Cells

    glyph-cells.frag: one pixel a cell. Whether it draws, which glyph, how bright, which accent, and the wave's lift.

    19,046 pixels a frame
  5. Every frame · GPU

    Dots

    data-layer.frag: one pixel a glyph dot, reading the atlas; empty dots stay empty unless the crest's haze passes.

    1280 × 800 dots, scaled up crisp
The detail with the layer off: only the painting.
1 · the painting alonelayer off
The glyphs alone on a black ground: they trace the hoof, the leg and the cloak's folds in the painting's colours, with a few vermilion and moss accents.
2 · the glyph passes aloneon carbon
Painting and glyphs together, as the desktop shows them.
3 · togetherthe desktop

All three at 1:1 device pixels, same frame (phase 100 s), default settings. The glyph-only frame shows how little is drawn: a glyph is 5 × 7 dots in a 6 × 9 cell, and most cells are empty.

The maps the glyphs read

Made once per picture by offline/wallpaper_map.py, from the painting alone. Shown here four times larger, one square per texel.

Edge map: bright lines along the limbs, the horse's legs and the cloak's folds on black.
Edge · shape RSobel, floored at the median
Subject map: soft bright blobs over the lit bodies, dark background.
Subject · shape Gfar from the dominant tone
Direction map: short strokes along every strong edge, each turned the way the painting's line runs.
Direction · shape Bstructure tensor
Light map: a soft grey version of the painting's lighting, the lit limbs brightest.
Light · light Rluminance, lightly blurred
Detail map: fine white texture where the brushwork is busiest, black in the soft shadows.
Detail · light Gluminance minus its blur
How a cell decides to draw, and what it draws
Chance to drawA floor everywhere of 9–22% (more where the paint is textured), up to 85 in 100 on a clear contour; tonal edges weigh 0.4 of a contour and soft turns of light 0.25; deep shadow keeps 40% of its chance. Capped at 85%. The look's density multiplies it. Which cells draw is chosen afresh at each re-drawing, by a hash no neighbour shares — no columns.
Which glyphThe cell's tone picks a place on the lighter 70% of the sparse-to-dense ramp, with four steps of variety either side. On a strong contour, 60% of cells draw the stroke that runs the contour's way — - \ | / — never two in a row along it.
Its colourThe paint under the cell (four taps), a tenth of the way into the NOUS tone map, its OKLab lightness moved 0.15 up over dark paint or down over light, through the mid-tones by the cell's Bayer value. Off the strong lines the step is 0.7 of that. Chroma is eased only where the moved colour would leave sRGB.
AccentsVermilion 1.2% and moss 2% of contour glyphs, times 3 on a full contour, more where the paint is vivid; vermilion where the paint is warm, moss where it is cool. The crest's head makes them up to 3.5 times as likely.
Measured on the laptop71–73% of glyphs sit on the strongest 30% of the picture's edges; 11% of the flattest 40% draws; no empty 16 × 16-cell patch, and no columns. docs/evidence/wallpaper/v4/metrics.md, v5/README.md

The glyphs

Sixty-seven characters, each 5 × 7 dots: sixty-three on a ramp from the sparsest to the densest, then the four contour strokes. The katakana are mirrored, as the film drew them; the digits are not.

The light wave40.3

A crest of light, not falling code.

Every eight seconds a crest runs from the painting's lit paint into its shadow along lines of equal light. Under it glyphs brighten, change character and carry the accents; between crests they hold.

Frame at 0 seconds of the crest.
0 s
Frame at 2 seconds: brighter glyphs have moved further into the shadow.
2 s
Frame at 4 seconds.
4 s
Frame at 6 seconds.
6 s

Four moments of one eight-second crest, 1:1, drawn offscreen with lane-c's shaders at the default look.

The real shaders, 40 frames 200 ms apart across one crest. Under reduced motion this is a still.

Brightness has a sharp head and a long tail: it rises in 5% of a period and falls e-fold in a sixth — the Matrix film's glyph brightness, taken off its falling columns and put onto the painting's own light.

A moving sample at actual size: glyphs on the painting brighten in a band that sweeps from the lit leg into the dark, then settle.
The crest on the horse's leg: the glyphs on its lit edge lifted almost white; vermilion and moss hits keep their colour.
The crest on the horse's leg, 1:1offline-os evidence v5
Glow on minus glow off, six times brighter: a thin haze traces the lit edges the crest is passing.
Glow on minus glow off, × 6the haze follows the lit edges
Every other motion, and the numbers7
CrestEvery wave_period (8 s) at any one place; 1.6 crests on screen between the lightest paint and the darkest, bent by the paint's grain; contours catch it a little sooner. It keeps 35% of its light in deep shadow and is 1.6 × brighter on a contour. Lifted glyphs go 60% of the way to white over light ink, keep 55% of their light over dark.
Re-drawingEvery 20–45 s (per picture; the Caravaggio's is 30 s) a front runs from the lit edges into the shadow; each cell it passes scrambles for 1.2 s at 5 characters a second and settles on a fresh variant.
Re-rollEvery glyph changes character on its own clock, 0.25–1.4 times a second, twice as fast off the lines, dipping to 55% as it changes: a fade, not a blink.
CurrentA shimmer runs along the contours both ways at 1.6 cells a second, dimming the glyphs it is not passing by up to 30%.
Contour momentsAbout every 30 s, at an irregular time, a front sweeps 70 cells out from a point along the subject's contours for 2.5 s; glyphs gather there and brighten.
ArrivalA new picture's glyphs arrive over 4 s, lit edges first, while the old slot fades out. After a login or reload the first picture is simply there.
PointerOn the bare desktop the glyphs part round the pointer — about 13.5 cells, stretched along the picture's line — and swirl in a ring just outside. Heard only when the pointer moves there.

Every clock repeats within the shell's 3600 s phase, and no hash is fed a count that grows forever, so there is never a visible jump. Measured on the laptop: 0.2–1.5% of the picture's pixels change every 83 ms — continuous, no hold-then-jump.

Levels40.4

Quiet, Balanced, Vivid.

Three starting points the editor offers. Balanced is every default; Quiet lets the picture lead; Vivid brings more glyphs, more light and more vermilion and moss. Each can be tuned after.

Quiet on the Caravaggio: few, soft glyphs; the painting leads.
Low · Quietdark theme
Balanced on the Caravaggio: glyphs along the hoof and the folds.
Default · Balanceddark theme
Vivid on the Caravaggio: denser, brighter glyphs and more vermilion and moss accents, the painting still clear.
Heavy · Vividdark theme
Quiet on the Pissarro boulevard: very few glyphs among the carriages.
Low · Quietlight theme
Balanced on the Pissarro: glyphs gather on the carriages and the lamp post, darker than the pale street.
Default · Balancedlight theme
Vivid on the Pissarro: many bright glyphs across the street, the crest visible as a lighter band.
Heavy · Vividlight theme

1:1 device pixels, the same frame for each level. Caravaggio, The Conversion of Saint Paul, 1601 · Camille Pissarro, The Boulevard Montmartre on a Winter Morning, 1897, The Met, CC0. On the light picture the accents take the light theme's inks, #F04A24 and #758C3A.

What each level sets13
The three levels are the editor's own presets. Settings not listed stay at their defaults in every level.
SettingQuietBalancedVivid
Glyph densitydensity0.711.4
Glyph brightness stepbrightness_delta0.120.150.2
Vermilion and moss accentsaccents0.512
Animation speedmotion0.711.4
Contour momentscontour_momentsrarenormaloften
See-throughsee_through0.1500
Glyphs in plain areasplain_glyphs0.611.4
Plain-area contrastplain_contrast0.60.70.9
Plain-area change speedplain_pace1.523
Edge emphasisedge_emphasis0.911.2
Light waveundulation0.611.5
Light wave intervalwave_period1286
Glowglow0.30.61.1

Threshold and softness: how heavy the glyphs are

Each picture has its own tone range — the tones that draw its lightest glyph and its heaviest (the 5th and 98th percentile of its light). Heaviness threshold slides that range's middle; Threshold softness widens or narrows it round the middle. The glyphs stay where they are; which character each one draws changes.

Threshold minus 0.4: heavier, denser characters across more of the detail.
threshold −0.4heavy spreads
Threshold 0, the default.
threshold 0default
Threshold plus 0.4: mostly light, sparse characters.
threshold +0.4only the strongest
Softness 0.3: a hard cut between light and heavy characters.
softness 0.3hard cut
Softness 2: characters change weight gradually across the tones.
softness 2.0slow blend
range = [ mid + threshold − half × softness ,  mid + threshold + half × softness ]   clamped to 0…1
mid, half = the picture's own (lo + hi) / 2 and (hi − lo) / 2        Caravaggio: lo 0.031 · hi 0.690

Two more dials worth seeing

Glyph size 2: each character twice as large, fewer of them.
glyph_size 2two device pixels a dot
Light wave 0: the glyphs without the crest, even and quiet.
undulation 0no wave · the reduced-motion look
Every setting40.5

Thirty-one settings, in the editor's three groups.

Moving glyphs, Painting colour & dither, and The picture. Each is bounded: a value outside its range is held at the edge, and a bad one is refused in words.

Stored in ~/.config/offline/wallpaper-look.json, read live by the shell on a file watch — no polling. offline wallpaper look shows, sets, resets and applies presets from the command line; the editor draws its controls from the same table (offline/wallpaper.py LOOK), so the two cannot disagree.

Moving glyphs23
Moving glyphs — The characters that move over the picture: how many, how bright, how fast. 23 settings
SettingRangeDefaultStepWhat it does
Glyph densitydensity0.25 – 210.01How many glyphs: 1 is the settled look, lower is sparser, higher denser.
Glyph brightness stepbrightness_delta0.05 – 0.250.150.005How far a glyph's lightness stands from the painting under it (OKLab L).
Vermilion and moss accentsaccents0 – 310.01How many Vermilion and moss-green glyphs ride the contours; 0 is none.
Animation speedmotion0.25 – 210.01How fast the glyphs re-draw, re-roll and shimmer.
Contour momentscontour_momentsoff · rare · normal · oftennormalHow often a moment runs along the picture's contours: about every minute (rare), half minute (normal) or quarter minute (often).
Glyph sizeglyph_size1 – 311How big each glyph is: device pixels per glyph dot.
See-throughsee_through0 – 0.800.01How much of the painting shows through the glyphs: 0 is full strength.
Glyphs in plain areasplain_glyphs0 – 210.01How many glyphs the plain parts of the picture carry: 0 leaves them bare.
Plain-area contrastplain_contrast0.3 – 1.60.70.01How far a glyph in a plain area stands from its paint, against one on a line.
Plain-area change speedplain_pace0.5 – 420.01How quickly glyphs in plain areas change character, against those on a line.
Edge emphasisedge_emphasis0.5 – 1.210.01How strongly the glyphs gather on the picture's edges and contours.
Pointer clearing sizepointer_size0.5 – 210.01How wide the glyphs part round the pointer on the bare desktop.
Frame rate capframe_rate6 – 30241The most frames a second the glyphs draw: lower saves battery and heat.
Pattern sizepattern_scale0.4 – 2.510.01How large the patches of glyphs are: lower is finer, higher broader.
Glyph change ratechange_rate0.2 – 310.01How often each glyph changes to another character.
Pattern holdredraw0.3 – 310.01How long a pattern holds before the glyphs redraw it: higher holds longer.
Colour from the paintingcolour_follow0 – 210.01How much each glyph takes the painting's colour under it; 0 is plain light and dark.
Light waveundulation0 – 210.01How bright the wave of light is that runs through the glyphs from the picture's lit paint into its shadow; 0 is no wave.
Light wave intervalwave_period3 – 3080.01Seconds between one crest of the light wave and the next at any one place: lower is busier, higher calmer.
Characters changing under the wavewave_flicker0 – 10.60.01How many glyphs change character as the crest passes over them; 0 keeps them still.
Glowglow0 – 20.60.01How far the glyphs the wave lifts glow into the painting round them, in their own colour; 0 is none.
Heaviness thresholdthreshold-0.4 – 0.400.01Where glyphs turn heavy: lower, and heavy glyphs spread over more of the picture; higher, only its strongest tones.
Threshold softnessthreshold_softness0.3 – 210.01How gradually glyphs go from light to heavy: low is a hard cut, high a slow blend.
Painting colour & dither5
Painting colour & dither — Milo's colour and dither over the painting itself. 5 settings
SettingRangeDefaultStepWhat it does
Treatmentpaint_treatmentoff · national-park · nous · archive · paint · field-studyoffMilo's colour and dither over the painting, in one of the brand's named treatments; off is the painting itself.
Treatment strengthpaint_amount0 – 10.60.01How much of the treatment shows over the full-colour painting.
Dither dot sizedither_size1 – 621How big each dither dot is, in screen pixels.
Treatment contrastpaint_contrast0.6 – 1.610.01More or less contrast than the treatment's own.
Tone stepstone_steps2 – 841How many tones the dither separates the painting into.
The painting pass offers five of the brand's recipes, copied from engine/recipes.json. Sublime and Trace are left out: one band reads as a streak across a whole desktop.
TreatmentStopsMatrixStrengthContrastLevels
National Parknational-parkbayer80.71.054
NOUSnousbayer40.91.15
Archivearchivebayer40.516
Paintpaintbayer411.14
Field Studyfield-studybayer411.052
National Park at 0.6 over the Caravaggio: moss shadows, vermilion lights, cream highlights, ordered dither, glyphs on top.
national-park · 0.6dark
NOUS at 0.6: a darker, finer dither, the painting still in its own colours underneath.
nous · 0.6dark
Archive at 0.8 over the Pissarro: carbon and cream in six tones.
archive · 0.8light

Off by default: the pictures are full colour. The painting pass renders one texel per dither dot and never touches the glyph passes.

The picture3
The picture — What sits with the picture: its name card, its labels, how it changes. 3 settings
SettingRangeDefaultStepWhat it does
The picture's nametitle_cardon · offonThe card in the corner naming the painting or photograph, who made it and when.
Labels on the pictureregion_labelson · offonThe small labels some pictures carry on their parts.
Change to the next picturechange_fade0.3 – 61.40.01How many seconds one picture takes to fade into the next.
The switch — kept apart from the look, in wallpaper-overlay.json
Animated wallpaperenabledon · offOff hides the layer; the painting stays.
Frames a secondframes_per_second1 – 30 · 24The layer's own ceiling; the look's frame-rate cap sits under it. 24 on a 60 Hz panel is a steady 20 steps a second.
Pause on low batterypause_below_battery_percent0 – 100 · 30On battery at or under this, the glyphs hold still.
Heat and cost40.6

Full, eased, held.

The layer runs on a hot 2018 Intel MacBook, so it watches the processor's own temperature and slows before the machine does. Warm halves the frames and the speed together; hot eases the motion to a stop.

Below 75 °CFullThe look's frame-rate cap, 24 by default.
75 – 85 °CEasedHalf the frames and half the speed, so each frame moves as far: slower, never choppier.
85 °C · resumes below 80HeldThe motion eases to a stop over 1.5 s and the glyphs stay on screen, frozen. Re-checked every 15 s.

The marks are the sensor's own: its maximum (100 °C on the laptop's coretemp Package) less 15 °C is “hot”. The temperature file is read every 5 s on the layer's own frame clock, so nothing is read while the layer is off. The layer also stops when locked, idle, switched off, or on battery at 30% or less.

The bench numbersbench.json
GPU time per frame on the laptop (Intel Iris Plus 655, Mesa 26.2.2, Qt 6.11.2), one slot rendered offscreen at 2560 × 1600 for 10 s, Caravaggio's Crowning with Thorns. Two runs; the spread is the GPU's clock.
ShadersfpsGPU ms, meanCPU ms a framePackage
Light wave (now)203.43 · 1.590.29 · 0.3463 · 68 °C
Light wave (now)303.72 · 1.810.80 · 0.6763 · 63 °C
Before the wave203.63 · 1.650.62 · 0.6464 · 63 °C
Before the wave304.15 · 1.730.78 · 0.6872 · 70 °C
Painting only, no glyphs200.850.31—

The wave and the glow add no measurable GPU time. The whole desktop shell — glyphs, bar, everything — used about 9–10% of one processor core at 20 fps on the installed build (offline wallpaper usage --json), most of it Qt and the compositor's per-frame work rather than the shaders, which is why the default stays at 24. The pointer parting measured the same within noise: 10.0–12.9% of a core, package 64–69 °C. offline-os docs/evidence/wallpaper/v4/README.md, v5/bench.json

The editor40.8

The real wallpaper is the preview.

Settings › Wallpaper effect, or SUPER + ALT + W. A panel slides in beside the live desktop; every slider moves the wallpaper while the hand moves, and Cancel puts everything back.

Screenshot of the laptop: Caravaggio's Denial of Saint Peter on the left with glyphs on the lit face; on the right the Wallpaper effect panel with Cancel and Save, a live cost readout (0% of one core, 398 MB, 65 °C), the Animated wallpaper switch, saved looks, the Quiet, Balanced and Vivid presets, and the Moving glyphs section with its first slider.

Screenshot of the laptop, 2026-09-26 02:56. Caravaggio, The Denial of Saint Peter, 1610, The Met, CC0.

What it costs nowThe desktop shell's share of one core, its memory and the processor's temperature, measured every couple of seconds while the panel is open — so a slider's cost is visible as it moves. When the layer is held for heat, it says so and says when it will resume.
Cancel · SaveOpening keeps a snapshot of the look and the switch. Cancel writes it back; Save keeps what is on screen. If the effect was off, it is turned on for the preview and turned back off on Cancel.
Start from a lookQuiet, Balanced, Vivid — several settings at once, each tunable after.
Your saved looksName the look on screen (“Evening”, “Quiet desk”) and it comes back with one click; a saved look is re-bounded when worn, never trusted.
DefaultsSet as my default · Reset to my default · Factory settings.
Change pictureHow often the wallpaper moves on, as the macOS menu offers it, and Next picture now.
Two sectionsMoving glyphs, and Painting colour & dither, each opened and closed on its own; each row is a label, a line of plain words, the value and a slider or a choice. Targets are 44 px.
Later · not built40.9

What packaging it for other computers would take

Noted only; nothing here is built. The shaders already run off the laptop — every render on this page came from them on a Mac, through Qt's Metal backend, and the demo above is them in a browser. What is Omarchy-specific is the host around them.

  • A place on the desktop. Omarchy gives the layer a Wayland layer-shell surface under every window. macOS has none: it needs a borderless window at desktop level that ignores clicks, one per screen, or a wallpaper or screen-saver host.
  • Heat, battery, idle and lock. Read from /sys/class/hwmon, UPower and the shell's own services today. macOS would use its thermal-state notifications, IOKit power sources and session notifications.
  • Watching for changes. inotifywait today; FSEvents on macOS.
  • The reading and the gallery. wallpaper_map.py and the gallery tools are plain Python, and portable as they are.
  • The pointer. The layer hears the pointer only over the bare desktop; a desktop-level window on macOS gets the same with no special permission, but it must pass clicks through.
  • Proof before shipping. The same placement and bench measurements this page quotes, on each target.
Credits40.10

Every image on this page is a public-domain work or a render of one, recorded in assets/wallpaper/manifest.json with its source, rights and, for renders, the shaders and settings it was drawn with.

Renders: offline-os lane-c 8af08e48, drawn offscreen by tools/wallpaper/render.py on the M4 Mac (PySide6 6.10, Metal), never on the laptop's screen. Screenshots: the laptop's own screen, from offline-os docs/evidence/screens. Glyph brightness after Rezmason's matrix (github.com/Rezmason/matrix); colour steps in Björn Ottosson's OKLab; cell hash by Dave Hoskins (MIT). Paintings: Caravaggio via Wikimedia Commons, The Met and the Cleveland Museum of Art; Monet, Renoir, Caillebotte, Seurat, Morisot and Sisley via the Art Institute of Chicago; Pissarro and Sisley via The Met; photographs by the U.S. National Park Service via Wikimedia Commons.