Skip to main content

Crate aquarelle

Crate aquarelle 

Source
Expand description

aquarelle — watercolor-style soft-bleed orb rendering on a tiny_skia::Pixmap.

Originally written as the cel-anime night-scene texture set for the orber abstract-mood-image generator, the engine is independent of orber and only depends on tiny-skia + palette + rand + rand_chacha. It takes a center, radius, RGB color, and a u64 seed, and draws four compositable elements onto a pixel buffer you already own.

§The four elements

  1. bleed — small same-color radial gradients scattered around the orb to fake a film grain / paper-bleed feel.
  2. bloom — a near-white core inside the inner ~30 % of the radius so the orb reads as a light source rather than a flat dot.
  3. offset — the gradient center is decoupled from the geometric center by up to 25 % of the radius. A perfectly concentric light source looks artificial; a slightly off-center one feels natural. The direction is seed-derived so calls are deterministic.
  4. halo — saturation of the outer falloff is boosted so the bleed reads as a film halation instead of a flat alpha fade.

Each is tunable in 0.0..=1.0 and they compose with source-over.

§Renderer-agnostic on purpose

aquarelle does not know what background is on the pixmap, what the rest of your scene looks like, or how you intend to encode the result. It just composites four watercolor layers onto the buffer you hand it. The caller decides the background fill, layout, and output format (PNG / WebP / SVG / animation frames / WebCodecs).

§Example

use aquarelle::{render_aquarelle_orb, AquarelleParams};
use tiny_skia::{Color, Pixmap};

let mut pix = Pixmap::new(128, 128).unwrap();
pix.fill(Color::from_rgba8(0, 0, 0, 255));

render_aquarelle_orb(
    &mut pix,
    (64.0, 64.0),       // center
    40.0,               // radius
    [200, 100, 50],     // sRGB color
    42,                 // seed (determinism)
    AquarelleParams::default(),
);

§Determinism

Identical (center, radius, color, seed, params) produce byte-identical pixels. RNG state is seeded per call via ChaCha8Rng::seed_from_u64(seed) and never touches thread_rng.

§Bleed pass (v0.2)

For callers that already have a rasterized image (e.g. ink lines on a white background from blueprinter) and want to bleed the existing pixels themselves, render_aquarelle_bleed_pass applies a Gaussian-approximating box blur (3 passes) to the whole pixmap with a halo saturation boost and a faint seed-derived paper-grain noise. The original picture is then re-composited on top, so the bleed reads as a halo underneath the existing strokes.

Structs§

AquarelleBleedParams
Knobs for render_aquarelle_bleed_pass. All values are interpreted in their natural range and clamped internally; callers can pass raw slider values without pre-validation.
AquarelleParams
Intensities of the four aquarelle elements. Each value is interpreted in 0.0..=1.0; out-of-range inputs are clamped internally so the caller can pass raw slider values without pre-validation.

Functions§

render_aquarelle_bleed_pass
Apply a watercolor bleed pass to an entire pixmap.
render_aquarelle_orb
Composite one aquarelle orb onto pixmap with source-over blending.