Every colour here came from her
Nothing on this page was chosen by hand. The type sits on six colours lifted out of the photograph by median cut, and the accent is the pink of the clip in her hair — pulled from a ninety-pixel crop and raised out of shadow.
The photograph, reduced to ten colours
A 160-pixel proxy quantised by median cut. The percentages are real: how much of the frame each colour actually occupies.
Where the light actually fell
Every pixel of the full-resolution frame counted into sixty-four bins per channel. This is the exposure, measured rather than eyeballed.
A phone camera indoors at night: the curve piles up hard against the left wall, and almost nothing reaches pure white. The bright band on the right is the wall behind her, not the flash.
Eight ways to develop the same frame
Each plate is a real render of the pixels, not a CSS trick laid over the original.
Twenty-two thousand particles
Each one carries the colour of the single pixel it was sampled from, and a spring that pulls it back there. Move your cursor through her — or drag a finger across her on a phone — and tap to scatter.
Sampled on a 150 × 150 grid from the same crop. Every frame each particle is pushed by the cursor, pulled home by a spring and slowed by drag — then written straight into an image buffer rather than drawn shape by shape, which is what keeps twenty-two thousand of them moving at full frame rate.
Pushing a flat frame into relief
The photograph has no depth channel, so I built a stand-in and displaced every pixel through it. Move your cursor — or drag a finger — across her, and the near parts lead while the far parts lag. Left alone, it drifts by itself.
This is not a real depth estimate. It is heavily blurred luminance blended with a radial bias toward her face — bright reads as near, dark as far. It gets the hair and the wall wrong in places, and it is still enough to fool the eye as long as the shift stays small.
Every frame, each output pixel samples the source at an offset proportional to its depth and to how far your cursor sits from centre — a backward map, so no holes open up. Leave the canvas alone and it drifts on its own.
Ninety-six columns of type
Luminance sampled on a 96 × 46 grid and mapped to a ten-step ramp, darkest to lightest: @ % # * + = - : . and a space.
@@@%%%%%%%#*-. ..... ..... .=%@@@@@@@@@@@@@
@@@%@%%##*=: .. .....:::.... :%@@@@@@@@@@@@
@@@@%%#*==: .......:.::.::::--::.. . :#@@@@@@@@@@@
@@@@%#*=+: .....::----=---::---===-::. :#@@@@@@@@@@
@@@%##*+: ...:---===++=+++++====++++++++=-: .#@@@@@@@@@
@@%%#*+: .:---++****#######***************+=-: :#@@@@@@@@
@%%##=: ...:-=+++**######%%%%######**#######**++=-:. -%@@@@@@@
@@##=. ..::::-=+++**##%%%%%%%%%%%###############**+===:. =%%%%@@@
%%*=. ..:----=+++*****##%%@@@@###################**++==-:. .*%%%@@@
%%=. :--===++*****#####%%%%%@@%#################**++++==::. =%%%%@@
%%=.: :=++++******######%%%%%%%%%%%%%#########*****++++++==-: :*%%%@@
@%*:. .:=+++******#########%%%%%%%%%%%#########*****+++++++===-. :+#%%%@
%%#- .-==+*********#######%%%%%%%%%%%##########*******++++++==-. :+##@%@
%#*: :==+++*****#######%%%%%%@%%%%%#################*****++++===: .=+*%%@
%%*=. .:. -=++*******##******##%%%@@%%%%###################*****+++===: . =+++#%%
@#=-:*+: -++********+++++++====--=++***#####%##############*****+++==-. ...=#**#%
-::::=: .=+********++++******++==--==++***###########***++===--=====-- ::.:***#
--::: :=+********+****##%%%%##*++===+++***####****++=-::::::::::--=: .=+::=++
=-.. . -++******+++++===--======++=====++*******+==----=++***++=-:-=. :=*====
-:.. . .-++**###**+==-:..: :::-=---=+****++=-:-=+*###*****++=--= :=++*+=
=:... ...:--+***#######*+===+=:. :+-::-==++*####*=--===-:. .::::--:-= :-=**=
*: :---=--+**#######%###*+++++=======+*#####%%#*+=++:-- -=. .-=+- .-++=
:--+*=-+*######%%%%%%##**++====++*#######%%#**++++**+=--=+=---=+*+. .-=-
.-+++=-+*###%%%%%@@@%%%#######%%%%##########**+++++===-==-===+***+. ...:=
-+***==+**####%%%%@@@@@@%%%%%%%@%############*+***####*****####**+. .. ....
.:=+=--+***###%%%@@@@@@@@@@@@@@%%####*######**+***##%%@@%%%%%%##*+: . .
.-=+***##%%%%%%%%%%@%%%%*********#######**+++*##%%%%%@@%%##*+. .
-=+++**######%######*+--=+########%@%%##*+**++*##%%%%%###*+=
-==++++****######*+=-:=++=++**###%%@%%%#*+**==+*########*+=.
:=======+++++++++=-:-+*##*=-:::-=**#***+-:::::-=+*******+=:
-=++===========-::=+***####**+-::::-::.....:-::-=+++===:.
.=++++========---:-=+**####%@@#*=-::::--====:-=:----::.. ..
:=+++++++++++==:::..:==---=++++***++====--::++++--::. .
.=++++++****+=+***+====*+---::::::::. .=####*+-:.
.-==+++++*****##**********+====--::::-=#####*+:. .
:====++***######++**##*******++====+####*+-. . .
:-===+**####**#*++++**+*****+=--+##**+=. ..
:--=+**######***+====-------=+***+=:
.:-=+*#######%%####*****++**#*=:
.:. ..-+*###%%%%%%%#####*****#*- .
...:=-:....-+*####%%%%%####*****=. ..
::::::-=++=:. .:=++*****+****++=-. .
.-=---::=++**=-. .............
:====-::=++***+-.
.=++++=:-=++****=:.
.++***=:-=++*****=-.. What the file actually is
- Source
- 900 × 1600JPEG, sRGB, 113 KB as delivered
- Served
- 56 KB720 px WebP, q80 — half the bytes, same frame
- Placeholder
- 231 B14 × 25 px blur-up, inlined so the frame never flashes empty
- Halftone
- 45°6 px cell, dot radius ∝ √(1 − luminance), 4× supersampled
- Dither
- 1 bppAtkinson error diffusion across 460 px
- Metadata
- Noneno EXIF survived the trip — camera, time and place were stripped before the file reached me
- Shadow
- —of the frame sits below 25% luminance
- Triangles
- 4,232in the low-poly plate, from a jittered 46 × 46 grid
- Accent
- #d53363the hair clip, lifted from L 0.19 to L 0.52
One image is enough to build a whole site from.
Give me a name, a few lines of bio and some links, and this becomes a portfolio instead of a study.
Back to the top