Skip to content
Sample of Pixel Sort (Glitch Art)

toxi_openframeworks · PixelSort

Pixel Sort (Glitch Art)

Per-row pixel sorting à la Kim Asendorf's `ASDFPixelSort` and Karsten Schmidt's own glitch-art Processing sketches. For every row, find contiguous runs of pixels whose metric (brightness, RGB channel, or hue) lies above (or below) a threshold; each qualifying run is sorted by the chosen channel. The source image is procedurally regenerated each step (gradient + sinusoidal bands + noise wash) so the artwork evolves over time rather than being a one-shot transformation.

Original: https://github.com/kimasendorf/ASDFPixelSort

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
toxi_openframeworks
Source
toxi · openFrameworks
Evolution
filter
Render
sorted_pixels
Complexity
low
Agents
0
Year
2010
Author
Kim Asendorf (ASDFPixelSort, 2010) / Karsten Schmidt (Processing glitch sketches)

Math essence

For each row y, mask = metric(img[y]) >= threshold (or <= for dark mode). Walk the row; when a run of length in [min_run, max_run] is found, np.argsort the run by the selected channel and write back. A fraction `pass_prob` of rows are skipped entirely to break up the pattern. Metric is BT.601 luminance (default), or any of {R, G, B}, or hue computed from RGB max-min.

Parameters

Name Type Default Range Description
dim int 256 96–800 Square canvas side length in pixels.
mode str bright — Which pixels qualify for sorting: bright (above threshold), dark (below), white (very high), black (very low).
sort_channel str value — Channel to sort each run by.
threshold float 0.55 0.05–0.95 Brightness/darkness threshold for inclusion.
min_run int 6 2–64 Minimum run length to qualify.
max_run int 96 16–512 Maximum run length to qualify.
pass_prob float 0.7 0–1 Probability that any given row is processed.
frame int 0 0–9999 Animation frame counter (changes the source gradient).
seed int null 0–999999 RNG seed.

Reference

First 60 lines of reference.py. Full source: library_external/toxi_openframeworks/PixelSort/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _build_source(dim: int, rng: np.random.Generator, frame: int) -> np.ndarray:
    yy, xx = np.mgrid[0:dim, 0:dim].astype(np.float32)
    t = frame * 0.02
    base_r = 0.5 + 0.5 * np.sin(xx / dim * 6.0 + t * 1.3)
    base_g = 0.5 + 0.5 * np.cos(yy / dim * 5.0 - t * 0.7 + 1.1)
    base_b = 0.5 + 0.5 * np.sin((xx + yy) / dim * 4.0 + t * 0.5 + 2.2)
    bands = 0.7 + 0.3 * np.sin(yy / dim * 18.0 + t * 0.4)
    perturb = rng.normal(0, 0.05, size=(dim, dim)).astype(np.float32)
    img = np.stack(
        [
            np.clip(base_r * bands + perturb * 0.5, 0, 1),
            np.clip(base_g * bands + perturb * 0.5, 0, 1),
            np.clip(base_b * bands + perturb * 0.5, 0, 1),
        ],
        axis=-1,
    )
    return (img * 255).astype(np.uint8)


class PixelSort:
    """Per-row pixel sorting (Kim Asendorf / Karsten Schmidt glitch art).

    A source image (here a procedurally-generated gradient + sinusoidal
    bands + noise wash) is processed row by row. In every row we scan
    for connected runs of pixels whose ``metric`` value lies above
    ``threshold`` (the *bright* mode); each run is sorted by the
    selected channel. The result is the streak-y, databend look that
    Kim Asendorf popularised in `ASDFPixelSort` (2010) and that
    Karsten Schmidt has used in his own glitch-art Processing sketches.

    Each ``step()`` regenerates the source with a new perturbation
    seed, producing an evolving glitch artwork rather than a single
    frame.
    """

    family: ClassVar[str] = "toxi_openframeworks"
    sketch: ClassVar[str] = "pixelsort"

    def __init__(
        self,
        dim: int = 256,
        mode: str = "bright",
        sort_channel: str = "value",
        threshold: float = 0.55,
        min_run: int = 6,
        max_run: int = 96,
        pass_prob: float = 0.7,
        frame: int = 0,
        seed: int | None = None,
    ) -> None:
        self.dim = dim
        self.mode = mode
        self.sort_channel = sort_channel

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/toxi_openframeworks/PixelSort/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from toxi · openFrameworks

Sample of Generative Type Letterforms

Generative Type Letterforms

toxi_openframeworks · GenerativeTypeLetterforms

Letterforms assembled from a 9×9 stroke grid alphabet (A–Z subset), then modulated by a parametric function (bar widths and stroke positions follow `a * sin(b*x + c)` style curves) and optionally recursively subdivided into smaller marks.

View →
Sample of Gray-Scott Reaction-Diffusion

Gray-Scott Reaction-Diffusion

toxi_openframeworks · ReactionDiffusionGS

The canonical two-species Gray-Scott reaction-diffusion model on a periodic square grid: dU/dt = Du*lap(U) - U*V^2 + F*(1-U), dV/dt = Dv*lap(V) + U*V^2 - (F+k)*V.

View →
Sample of Median-Cut Color Quantizer

Median-Cut Color Quantizer

toxi_openframeworks · ColorQuantizer

Heckbert's 1982 median-cut color quantization applied to an evolving procedural gradient + low-resolution noise wash.

View →
Sample of Sound-Reactive Particle Field (Synthetic Audio)

Sound-Reactive Particle Field (Synthetic Audio)

toxi_openframeworks · SoundReactiveField

Particles advected by a force field whose horizontal component is driven by a synthetic audio signal: a chain of N sinusoids at different frequencies/amplitudes (the 'audio'), with the audio's instantaneous value plus its time derivative ('beat onset') driving the field.

View →
Sample of Verlet Particle-Spring Network

Verlet Particle-Spring Network

toxi_openframeworks · ParticleSpring2D

A Verlet-integrated particle network connected to its k-nearest neighbours by Hooke's-law springs.

View →
Sample of Voronoi Tessellation with Lloyd Relaxation

Voronoi Tessellation with Lloyd Relaxation

toxi_openframeworks · VoronoiRelaxation

Lloyd's algorithm applied to a jittered point cloud: each seed is replaced with the centroid of its Voronoi cell, repeatedly, producing ever-more-uniform polygonal cells.

View →

See all toxi_openframeworks artworks →