orber 0.3.0

Turn photos and videos into abstract orb mood images and short-form vertical videos
Documentation
# orber

Turn photos and videos into abstract **orb mood** output — colorful, blurry light spheres drifting slowly. Useful as video backgrounds, streaming wait screens, social story backgrounds, wallpapers, or just to obfuscate a personal photo into a vibe.

> **Status:** prototype. PNG output and vertical-format video (`mp4` via libx264, `webm` via libvpx-vp9) are implemented end-to-end. Vector / CSS outputs are still placeholders.

## Concept

```
Input image / video
  → Extract color clusters (this area is red, that area is blue, ...)
  → Convert each cluster into a light orb
  → Animate orbs drifting slowly with smooth color transitions
  → Output as still image, vertical video, or pure CSS/SVG
```

## Output formats (planned)

|              | Static                       | Animated                       |
| ------------ | ---------------------------- | ------------------------------ |
| **Raster**   | PNG / WebP                   | MP4 / WebM (vertical 9:16)     |
| **Style**    | CSS gradient                 | CSS gradient + `@keyframes`    |
| **Vector**   | SVG                          ||

## Usage

PNG output is implemented and produces a 1080×1920 vertical orb image:

```bash
orber --input photo.jpg --output orb.png
orber --input photo.jpg --output orb.png --blur 0.9 --orb-size 1.5 --saturation 1.4
orber --input photo.jpg --output orb.svg
```

Static PNG, vertical-format video (`mp4` via libx264, `webm` via libvpx-vp9), static SVG, and CSS background snippets are implemented. Only `webp` is accepted by the CLI but not yet rendered — it exits with `not yet implemented`. The output format is inferred from the extension. CLI flags cover orb size, blur, conveyor `--direction` and `--speed`, orb shape (circle / aquarelle bleed), saturation, and clip duration. See all flags via `orber --help`.

### Background color

The background color is **derived automatically from the input image**: the dominant (highest-weight) k-means cluster becomes the canvas color, and the remaining clusters become the orb pool. A nightscape gives a black canvas with bright points; a daytime sky gives a sky-blue canvas with floating points; a beige interior gives a beige canvas with small accents. There is no `--background` flag — to change colors, change the input image.

### Motion model

Animated outputs use a **one-way conveyor belt**: every orb in a clip drifts in the
same direction, exits one edge, and re-enters from the opposite edge. The seam happens
**fully off-screen** — each orb's wrap range is `[-r, 1+r]` (where `r` is its radius
normalized by the progress-axis length), so orbs are spawned and despawned beyond the
canvas edge instead of popping in or out at the edge. A single clip flows in exactly
one of `lr` (left→right), `rl`, `tb`, or `bt`. Pick the direction and pace with:

```bash
orber --input photo.jpg --output drift.mp4 --direction lr --speed slow
orber --input photo.jpg --output drift.mp4 --direction tb --speed very-slow --duration-ms 10000
```

`--speed` is the **global** cycle count (`very-slow` / `slow` = 1 / 2 screen-crosses
per clip for the slowest orbs). Each orb also gets a per-orb integer **speed
multiplier** (`1x` / `2x`) assigned deterministically from the seed, so individual
orbs visibly travel at different paces inside the same clip — effective traversal
counts spread over `{1, 2, 4}` per clip. All factors are integers, so the loop
closure at `t = 0 ≡ t = 1` stays pixel-exact. Combined with a long `--duration-ms`,
this gives the characteristic gentle, layered drift. Every orb also gets three
independent breathing pulses (radius ±10%, blur ±15%, opacity ±5%) applied
automatically — there is no opt-in flag for that.

> Note: the aquarelle shape uses the legacy `[0, 1]` wrap (its bleed / bloom / halo
> textures clip cleanly enough that the off-screen buffer would interfere with the
> rendered halo). The off-screen wrap buffer described above applies to the
> `circle` shape only.

### Orb count

Use `--count <N>` (1..=200, default 20) to control how many orbs are visible on screen
at once. The K colors picked from the input image (by k-means) are *expanded* into N
orbs by weight-proportional color sampling and per-orb scattering on the cross axis.
Higher counts produce a denser, more screen-filling composition; lower counts leave
more breathing room around each orb.

```bash
orber --input photo.jpg --output dense.png --count 40 --orb-size 2.5
orber --input photo.jpg --output sparse.png --count 8 --orb-size 4.5
```

`--count` is purely a deterministic renderer knob; randomization (e.g. picking a
random count in the GUI) is the caller's responsibility, not a CLI feature. Each orb
is also assigned one of two visual styles (rim or soft) deterministically from the
seed, so a single frame mixes the rim-emphasized look with plain soft gradients.

> Note: the aquarelle shape ignores `--count` (palette-only rendering). It always
> renders one orb per cluster from the k-means palette so the bleed / bloom / halo
> texture set stays coherent.

### Variation preset

To explore looks for a single input, batch out a curated set of 10 alternates:

```bash
orber --input photo.jpg --variations 10 --output-dir out/
```

The preset table varies conveyor direction, speed, orb count, orb size, and blur to
produce ten visibly distinct outputs (4 stills + 6 animations). Colors come straight
from the k-means palette of the input image — variations never recolor the photo.
Use `--variations-mode still` or `--variations-mode video` to filter the table.

## Build

```bash
cargo build
cargo test
cargo clippy -- -D warnings
cargo fmt --check
```

## Installation

```bash
cargo install orber
```

Or download a prebuilt binary from GitHub Releases once `v0.1.0+` tags are published.

## Release

`orber` is prepared as a Rust CLI crate with:
- `cargo install orber`
- GitHub Actions CI on pushes and pull requests
- a tag-driven GitHub Releases workflow for Linux, macOS, and Windows artifacts

The first public crate/release target is `v0.1.0`.

## License

MIT