A generative art project for the 42 Lyon ArtCore contest — producing a 5120x2880 PNG image where every pixel is computed by code. No images are loaded, no textures are sampled. The entire visual is generated from mathematical noise functions running on the GPU.
For details on the inspector's internal architecture, see docs/inspector-architecture.md.
make
This compiles the project and produces ft_artcore.png (5120x2880) in the project root. A seed can be passed to get different variations:
make run SEED=12345
make inspector
Opens a window with live parameter sliders. Change noise scale, warp strength, thresholds, colors, grain — and see the result instantly. Scroll to zoom, click-drag to pan. Press Tab to hide the panel, R to randomize the seed, Esc to quit. The Export PNG button renders the full 5120x2880 image with current parameters.
- Rust (stable, rustup.rs)
- GPU drivers (Vulkan or OpenGL)
- Ubuntu:
sudo apt install libvulkan-dev - Arch:
sudo pacman -S vulkan-icd-loader
- Ubuntu:
| Component | Technology |
|---|---|
| Language | Rust (edition 2024) |
| GPU API | wgpu 24 (Vulkan / GL backend) |
| Shaders | WGSL (WebGPU Shading Language) |
| Image export | image crate (PNG) |
| Inspector UI | winit + egui (optional, feature-gated) |
The image is generated in a single GPU pass. A fragment shader runs once per pixel — at 5120x2880 that's ~15 million pixels, each computed independently in parallel.
Every pixel starts as a coordinate. That coordinate is fed into a hash function — a mathematical operation that turns a 2D position into a pseudo-random number between 0 and 1. Unlike sin()-based hashes (which produce diagonal artifacts on some GPUs), this project uses bit-mixing: integer xor-shift operations that scramble the bits of the coordinate directly. This is fast, deterministic, and artifact-free.
The hash is used to build value noise — a smooth, continuous field where neighboring pixels get similar values. Six layers of this noise are stacked at increasing frequencies and decreasing amplitudes, a technique called Fractal Brownian Motion (FBM). The result looks like rolling clouds or topographic terrain.
Instead of sampling the noise field at the pixel's actual position, the position is displaced by a second noise field. This means the noise samples itself at warped coordinates, creating flowing, liquid-like distortions. The amount of displacement (warp strength) controls how twisted the patterns become.
A variant called ridged FBM is used for the main field. Instead of smooth hills, it produces sharp ridges and valleys — like lightning bolts or vein patterns.
The ridged noise field is converted to black and white using a threshold: values above 0.48 become white, below become black, with a thin gray transition band (0.06 wide). This creates a marble-like pattern of black veins on a white background.
In the brightest white areas (above 0.58), a vein mask activates. These areas get colored using a cosine palette — a mathematical formula that produces smooth iridescent color gradients (like oil on water).
The foreground is not filled solid. Instead, it uses Bayer 4x4 ordered dithering — a technique that places colored dots in a structured grid pattern. The dots vary in size (2-8 pixels) based on the mask intensity, and their density follows an inverted formula: sparse in the center of veins, denser at the edges. Each dot gets its own color from the palette, creating a gradient within each dither cell.
As a final step, each pixel gets a small amount of random colored noise mixed in (like film grain on old photographs). The grain is a blend between the pixel's color and a random color, at 1.88% opacity. This adds texture and prevents banding in smooth gradients.
A seed number is mixed into every hash call. Changing the seed produces a completely different image with the same aesthetic — same patterns, same colors, different layout.
ft_artcore/
├── src/
│ ├── main.rs # Image generator entry point
│ ├── inspector_main.rs # Inspector entry point
│ ├── render.rs # wgpu headless render pipeline
│ ├── inspector.rs # Real-time inspector (winit + egui)
│ ├── shader_params.rs # Uniform parameter struct
│ ├── config.rs # Output configuration constants
│ └── export.rs # PNG export
├── shaders/
│ ├── noise.wgsl # Hash, noise, FBM, palette, Bayer functions
│ └── main.wgsl # Fragment shader: background, foreground, grain
├── docs/
│ └── inspector-architecture.md
├── Makefile
└── Cargo.toml
MIT
