Portrait No. 01
One photograph · 900 × 1600 · 2026

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.

Portrait of a young woman with long dark hair and a pink hair clip, smiling at the camera.
Plate 01 — source
Scroll
01 — Extraction

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.

02 — Light

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.

Red Green Blue Luminance Mean
—in shadow
—clipped
—mean luminance

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.

03 — Darkroom

Eight ways to develop the same frame

Each plate is a real render of the pixels, not a CSS trick laid over the original.

Source Hover to peek at the source

Cycling automatically — tap to take over
04 — Field

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.

—particles
—fps

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.

05 — Depth

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.

The depth proxy: bright is near, dark is far.

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.

06 — Text

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.

@@@%%%%%%%#*-.                               .....                 .....        .=%@@@@@@@@@@@@@
@@@%@%%##*=:                                  ..              .....:::....        :%@@@@@@@@@@@@
@@@@%%#*==:                                     .......:.::.::::--::..   .         :#@@@@@@@@@@@
@@@@%#*=+:                                  .....::----=---::---===-::.             :#@@@@@@@@@@
@@@%##*+:                               ...:---===++=+++++====++++++++=-:            .#@@@@@@@@@
@@%%#*+:                              .:---++****#######***************+=-:           :#@@@@@@@@
@%%##=:                           ...:-=+++**######%%%%######**#######**++=-:.         -%@@@@@@@
@@##=.                        ..::::-=+++**##%%%%%%%%%%%###############**+===:.         =%%%%@@@
%%*=.                       ..:----=+++*****##%%@@@@###################**++==-:.        .*%%%@@@
%%=.                       :--===++*****#####%%%%%@@%#################**++++==::.        =%%%%@@
%%=.:                     :=++++******######%%%%%%%%%%%%%#########*****++++++==-:        :*%%%@@
@%*:.                   .:=+++******#########%%%%%%%%%%%#########*****+++++++===-.       :+#%%%@
%%#-                   .-==+*********#######%%%%%%%%%%%##########*******++++++==-.       :+##@%@
%#*:                  :==+++*****#######%%%%%%@%%%%%#################*****++++===:       .=+*%%@
%%*=. .:.            -=++*******##******##%%%@@%%%%###################*****+++===:     . =+++#%%
@#=-:*+:            -++********+++++++====--=++***#####%##############*****+++==-.     ...=#**#%
-::::=:            .=+********++++******++==--==++***###########***++===--=====--       ::.:***#
--:::              :=+********+****##%%%%##*++===+++***####****++=-::::::::::--=:       .=+::=++
=-..        .      -++******+++++===--======++=====++*******+==----=++***++=-:-=.        :=*====
-:.. .            .-++**###**+==-:..:      :::-=---=+****++=-:-=+*###*****++=--=         :=++*+=
=:...         ...:--+***#######*+===+=:.  :+-::-==++*####*=--===-:.   .::::--:-=          :-=**=
*:           :---=--+**#######%###*+++++=======+*#####%%#*+=++:--     -=.  .-=+-           .-++=
             :--+*=-+*######%%%%%%##**++====++*#######%%#**++++**+=--=+=---=+*+.            .-=-
             .-+++=-+*###%%%%%@@@%%%#######%%%%##########**+++++===-==-===+***+.           ...:=
             -+***==+**####%%%%@@@@@@%%%%%%%@%############*+***####*****####**+.         .. ....
             .:=+=--+***###%%%@@@@@@@@@@@@@@%%####*######**+***##%%@@%%%%%%##*+:            .  .
                  .-=+***##%%%%%%%%%%@%%%%*********#######**+++*##%%%%%@@%%##*+.               .
                   -=+++**######%######*+--=+########%@%%##*+**++*##%%%%%###*+=                 
                   -==++++****######*+=-:=++=++**###%%@%%%#*+**==+*########*+=.                 
                   :=======+++++++++=-:-+*##*=-:::-=**#***+-:::::-=+*******+=:                  
                    -=++===========-::=+***####**+-::::-::.....:-::-=+++===:.                   
                    .=++++========---:-=+**####%@@#*=-::::--====:-=:----::..             ..     
                     :=+++++++++++==:::..:==---=++++***++====--::++++--::.                .     
                      .=++++++****+=+***+====*+---::::::::.   .=####*+-:.                       
                       .-==+++++*****##**********+====--::::-=#####*+:.                 .       
                         :====++***######++**##*******++====+####*+-.                   . .     
                           :-===+**####**#*++++**+*****+=--+##**+=.                      ..     
                             :--=+**######***+====-------=+***+=:                               
                               .:-=+*#######%%####*****++**#*=:                                 
                            .:.  ..-+*###%%%%%%%#####*****#*-                  .                
                          ...:=-:....-+*####%%%%%####*****=.                  ..                
                        ::::::-=++=:. .:=++*****+****++=-.          .                           
                       .-=---::=++**=-.  .............                                          
                        :====-::=++***+-.                                                       
                        .=++++=:-=++****=:.                                                     
                         .++***=:-=++*****=-..                                                  
07 — Plate data

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
08 — End plate

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