Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"imaging",
"imaging_conformance",
"imaging_examples",
"imaging_skia",
"imaging_snapshot_tests",
"imaging_tiny_skia",
Expand Down
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# imaging

`imaging` is a small Rust command stream for 2D drawing. It is for code that wants to describe
drawing without choosing the final renderer too early.

You can stream commands directly into a backend, or record them into a retained scene for
validation, replay, snapshots, and tests.

This is not a finished graphics stack. It is the shared drawing vocabulary and recording layer used
by the backends in this workspace.

## How To Read It

- Use `Painter` to author drawing commands.
- Implement or use a `PaintSink` to receive those commands.
- Use `record::Scene` when you want an owned recording.
- Add a backend crate when you want pixels or renderer integration.

If you are new to the project, start with the examples crate:

```sh
cargo run -p imaging_examples --example hello_scene
```

To render a PNG through the Vello CPU backend:

```sh
cargo run -p imaging_examples --example render_png_vello_cpu -- out.png
```

The longer path through the concepts is in the `imaging::guide` rustdoc pages:

```sh
cargo doc -p imaging --open
```

## Where It Fits

`imaging` is useful when application or toolkit code wants to describe drawing once and send it to
different targets: a retained scene, a CPU renderer, a GPU renderer, snapshot tests, diagnostics, or
adapter code for another vector format.

It is especially relevant to people working on UI/toolkit rendering, SVG or Velato integration,
backend conformance, and Vello experiments.

## Crates

- `imaging`: `no_std` core `Painter`, `PaintSink`, `record::Scene`, validation, diagnostics,
and replay.
- `imaging_conformance`: shared backend conformance checks.
- `imaging_examples`: small examples for learning the core model.
- `imaging_skia`: Skia backend.
- `imaging_snapshot_tests`: image snapshot cases shared across backends.
- `imaging_tiny_skia`: CPU renderer based on `tiny-skia`.
- `imaging_vello`: Vello backend.
- `imaging_vello_cpu`: Vello CPU backend; start here if you want pixels quickly.
- `imaging_vello_hybrid`: Vello sparse/hybrid backend using `wgpu`.
- `imaging_wgpu`: shared texture-renderer traits and `wgpu` target glue.
- `imaging_wind_tunnel`: benchmark and measurement crate.
- `svg_imaging`: SVG lowering into `imaging`.
- `velato_imaging`: Velato lowering into `imaging`.

## Current Shape

The core crate is intentionally small and still experimental. The names and crate boundaries may
change while the project settles.

What is useful today:

- recording command streams with `record::Scene`
- validating and diagnosing recorded scenes
- replaying scenes into another sink
- rendering through backend crates for tests and experiments
- using snapshot tests to compare backend behavior

What is still rough:

- backend feature coverage differs
- GPU backends need platform/device setup
- this is not a full tutorial book or stable application API yet
3 changes: 3 additions & 0 deletions imaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Backend-agnostic 2D imaging recording + streaming API.

This crate is `no_std` by default (uses `alloc`); enable the `std` feature when needed.

If you are reading this on docs.rs, start with the `guide` module for the project-level learning
path, backend map, and mental model.

## API shape

`imaging` has two primary public layers:
Expand Down
77 changes: 77 additions & 0 deletions imaging/src/guide/backends.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Backend Map

Start with `imaging_vello_cpu` if you are learning the crate and want pixels. It is CPU-based, has
fewer setup steps than the GPU paths, and still exercises the Vello-side rendering work.

```sh
cargo run -p imaging_examples --example render_png_vello_cpu -- out.png
```

This page is a map, not a feature matrix. Backend coverage is still moving.

## Core And Tools

`imaging`

The core command stream and retained scene crate. Use this for [`crate::Painter`],
[`crate::PaintSink`], [`crate::record::Scene`], validation, diagnostics, and replay.

`imaging_examples`

Runnable examples for learning the crate. These live outside the core crate so examples can pull in
renderer and image-writing dependencies without changing the core dependency surface.

`imaging_conformance`

Contract tests for backend behavior at the command-stream level.

`imaging_snapshot_tests`

Shared visual cases and backend snapshot tests.

`imaging_wind_tunnel`

Benchmark and measurement crate.

## Renderers

`imaging_vello_cpu`

Vello CPU backend. This is the first backend to try for examples, tests, and local image output.

`imaging_vello`

Vello backend. Use this when working with the Vello renderer path.

`imaging_vello_hybrid`

Vello sparse/hybrid backend using `wgpu`. This needs a working GPU/device setup and is more
experimental than the CPU example path.

`imaging_wgpu`

Shared traits and target types for rendering into application-owned `wgpu` textures.

`imaging_skia`

Skia backend. Useful when you need Skia integration or want to compare behavior with a mature 2D
renderer.

`imaging_tiny_skia`

CPU renderer using `tiny-skia`. Useful for local rendering and backend comparisons.

## Importers

`svg_imaging`

Adapter from SVG documents into `imaging` commands.

`velato_imaging`

Adapter from Velato/Lottie-style content into `imaging` commands.

## Practical Rule

Use [`crate::record::Scene`] while you are learning the model. Add a backend when you want pixels,
texture integration, or backend-specific behavior.
85 changes: 85 additions & 0 deletions imaging/src/guide/learning_path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Learning Path

This is the short path through `imaging`: run one example, understand where commands go, then look
at a renderer. It is not meant to be a book or a full API reference.

The examples live in the workspace `imaging_examples` crate so the core crate does not need extra
example-only dependencies.

## Draw Something Into A Scene

Run:

```sh
cargo run -p imaging_examples --example hello_scene
```

This creates a [`crate::record::Scene`], wraps it in a [`crate::Painter`], draws a rectangle,
validates the scene, and prints a few facts about the recording.

The useful part is the shape of the code. Most callers should author drawing through
[`crate::Painter`]. The target can be a retained scene, a backend, a validator, or a small tool that
just observes commands.

## Look At `PaintSink`

Run:

```sh
cargo run -p imaging_examples --example counting_sink
```

This example implements a small [`crate::PaintSink`] that counts commands instead of rendering
pixels.

That is the core split in the crate: [`crate::Painter`] emits commands, and [`crate::PaintSink`]
receives them. A renderer can be a sink, but a sink does not have to be a renderer.

## Keep A Recording

Read:

```text
imaging_examples/examples/hello_scene.rs
```

[`crate::record::Scene`] is just one sink. It stores commands so they can be validated, diagnosed,
replayed, compared in tests, or rendered later.

That retained scene is backend-agnostic data. It is deliberately not a renderer.

## Replay A Scene

Run:

```sh
cargo run -p imaging_examples --example replay_scene
```

This records one scene, validates it, replays it into another scene, and checks that the recordings
match.

Replay is the bridge from retained data back into a sink. Once you can replay a scene, the same
recording can feed another retained scene, a backend, diagnostics, or a test harness.

## Render A PNG

Run:

```sh
cargo run -p imaging_examples --example render_png_vello_cpu -- out.png
```

This renders a retained scene through `imaging_vello_cpu` and writes a PNG.

Use this example when you want the quickest visible result. It keeps the rendering path CPU-based
while still exercising the Vello-side backend work.

## Where To Go Next

For visual comparison work, look at the `imaging_snapshot_tests` crate. It holds shared visual cases
and backend-specific snapshot tests.

For source labels and diagnostic context, search the crate docs for [`crate::Painter::with_context`]
and [`crate::with_context!`]. Context is useful when a retained scene needs to explain where a
command came from in application code.
71 changes: 71 additions & 0 deletions imaging/src/guide/mental_model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Mental Model

`imaging` is a command stream for 2D drawing. The core crate gives names to the commands and defines
how they move through the system; backend crates decide how those commands become pixels or renderer
state.

```text
Application code
|
v
Painter
|
v
PaintSink trait
|
+--> record::Scene
+--> Vello CPU backend
+--> Vello backend
+--> validation / diagnostics
```

[`crate::Painter`] is the authoring helper. It is the API most drawing code should use.

[`crate::PaintSink`] is the receiving side. It accepts borrowed drawing commands.

[`crate::record::Scene`] is an owned sink. It stores commands so they can be kept, checked,
replayed, or rendered later.

Backends either receive commands as sinks or consume scenes through rendering traits. The exact
shape depends on the backend crate.

## Streaming And Retained Paths

The streaming path is:

```text
Painter -> PaintSink
```

Use this when the caller can draw directly into the target. A sink might count commands, build a
backend-native scene, validate the stream, or render.

The retained path is:

```text
Painter -> record::Scene -> validate / diagnose / replay / render
```

Use this when the caller needs owned drawing data. That is useful for caching, tests, snapshots,
debugging, and backend-independent storage.

## Terms

- [`crate::Painter`]: helper for emitting drawing commands.
- [`crate::PaintSink`]: trait that receives borrowed drawing commands.
- [`crate::record::Scene`]: owned retained command stream.
- Validation: structural checks for balanced clips, groups, contexts, and referenced data.
- Diagnostics: warnings about suspicious but valid drawing.
- Replay: sending a retained scene into another sink.

## A Few Edges To Know

Backend support is uneven. A scene can be valid and still use a feature a particular backend does
not support yet.

[`crate::record::Scene::validate`] checks structure, not whether the result is visually what you
intended.

Diagnostics are advisory. They are meant to catch likely mistakes without rejecting valid scenes.

The core crate is pre-1.0 and intentionally small, so names and boundaries may still change.
Loading
Loading