Skip to content

About

A generative art project for the 42 Lyon ArtCore

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

26 Commits

Folders and files

Repository files navigation

ft_artcore

ft_artcore

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.

Usage

Generate the image

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

Real-time inspector

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.

Requirements

  • Rust (stable, rustup.rs)
  • GPU drivers (Vulkan or OpenGL)
    • Ubuntu: sudo apt install libvulkan-dev
    • Arch: sudo pacman -S vulkan-icd-loader

Tech Stack

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)

How It Works

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.

Step 1: Noise field

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.

Step 2: Domain warping

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.

Step 3: Background (black and white marble)

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.

Step 4: Foreground (iridescent dithered veins)

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.

Step 5: Film grain

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.

Seed

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.

Project Structure

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

License

MIT

About

A generative art project for the 42 Lyon ArtCore

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages