No project description provided
Project description
Invariant GFX
A deterministic, functional graphics pipeline built on Invariant. Invariant GFX allows developers to build complex visual assets (icons, badges, dynamic UI components, Stream Deck buttons, data visualizations) by plugging together reusable "pipeline parts" in a DAG-based system.
Note: This project builds on Invariant, a deterministic execution engine for DAGs. For information about Invariant's core concepts (DAG execution, caching, execution model, parameter markers, etc.), see the upstream README and Invariant documentation.
Features
- Smart Layout: Ops can inspect upstream artifact dimensions to calculate positions dynamically
- Anchor-Based Composition: Position layers relative to previously-placed named layers using
absolute()andrelative()builder functions - Content-Sized Layout: Flow-based arrangement (row/column) with automatic sizing
Relationship to Invariant
Invariant GFX is a child project of Invariant:
- Invariant (Parent): Provides the DAG execution engine, caching infrastructure, and core protocols. Invariant has NO image awareness—it is domain-agnostic.
- Invariant GFX (Child): Provides graphics-specific Ops (
gfx:render_text,gfx:composite,gfx:render_svg, etc.) and Artifacts (ImageArtifact,BlobArtifact). All image/Pillow concerns live here.
Invariant GFX uses Invariant's Executor and store infrastructure directly—no wrapper class is needed.
Op Standard Library
Invariant GFX provides a standard library of graphics operations, registered under the gfx: namespace:
Group A: Sources (Data Ingestion)
gfx:resolve_resource: Resolves bundled resources (icons, images) via JustMyResource (e.g.,"lucide:thermometer")gfx:create_solid: Generates solid color canvases (RGBA)
Group B: Transformers (Rendering)
gfx:render_svg: Converts SVG blobs into raster artifacts using cairosvggfx:render_text: Creates tight-fitting "Text Pill" artifacts (supports string font names via JustMyType and directBlobArtifactfont injection)gfx:resize: Scales anImageArtifactto target dimensions (LANCZOS resampling)
Group C: Composition (Combiners)
gfx:composite: Fixed-size composition engine with anchor-based positioning (absolute(),relative())gfx:layout: Content-sized arrangement engine (row/column flow)
Group D: Type Conversion (Casting)
gfx:blob_to_image: Parses raw binary data (PNG, JPEG, WEBP) intoImageArtifact
For detailed Op specifications, see docs/architecture.md.
Installation
# Clone the repository
git clone <repository-url>
cd invariant-gfx
# Install dependencies
uv sync
Note: This project depends on a local development version of Invariant. The dependency is configured in pyproject.toml as a file path reference.
Quick Start
This example demonstrates graphics-specific operations. For details on Invariant's execution model, parameter markers (ref(), cel(), ${...}), and context injection, see the upstream README.
from invariant import Executor, Node, ref
from invariant.registry import OpRegistry
from invariant.store.memory import MemoryStore
from invariant_gfx import register_core_ops
from invariant_gfx.anchors import absolute, relative
# Register graphics ops
registry = OpRegistry()
register_core_ops(registry) # Registers gfx:* ops
# Define the graph template (designed at 72px reference size)
graph = {
# Render text with proportional sizing
"text": Node(
op_name="gfx:render_text",
params={
"text": "Hello",
"font": "Geneva",
"size": "${decimal(root.width) * decimal('14') / decimal('72')}", # 14pt at 72px, scales proportionally
"color": (255, 255, 255, 255), # White RGBA
},
deps=["root"],
),
# Create background (size from context)
"background": Node(
op_name="gfx:create_solid",
params={
"size": ("${root.width}", "${root.height}"),
"color": (40, 40, 40, 255), # Dark gray RGBA
},
deps=["root"],
),
# Composite: center text on background
"final": Node(
op_name="gfx:composite",
params={
"layers": [
{
"image": ref("background"),
"id": "background",
},
{
"image": ref("text"),
"anchor": relative("background", "c@c"),
"id": "text",
},
],
},
deps=["background", "text"],
),
}
# Execute the graph
store = MemoryStore()
executor = Executor(registry=registry, store=store)
# Render at 72x72 (text at 14pt)
results = executor.execute(graph, context={"root": {"width": 72, "height": 72}})
results["final"].image.save("output_72.png", format="PNG")
# Render at 144x144 (text scales to 28pt automatically)
results = executor.execute(graph, context={"root": {"width": 144, "height": 144}})
results["final"].image.save("output_144.png", format="PNG")
For more complete examples, see:
examples/thermometer_button.py— Icon + text + layout + composite pipelineexamples/text_badge.py— Dynamic SVG resizing driven by text dimensionsexamples/color_dashboard.py— Multi-cell dashboard with nested layouts
For the full Thermometer pipeline and template + context pattern, see docs/architecture.md.
Status
Architecture: Complete and documented
Implementation: V1 op library complete
- Artifact types (
ImageArtifact,BlobArtifact): ✅ Implemented - Anchor functions (
absolute(),relative()): ✅ Implemented - Op standard library (8 ops): ✅ Implemented
register_core_ops()registration: ✅ Implemented- Integration with JustMyType/JustMyResource: ✅ Implemented
- Unit tests (94 tests): ✅ All passing
- E2E tests (Use Cases 1 & 2): ✅ Passing
- E2E context injection (Use Case 3): ⏳ Placeholder
See docs/status.md for detailed implementation status.
Architecture
Invariant GFX uses Invariant's execution model. For details on the two-phase execution model (Context Resolution and Action Execution), see the upstream documentation.
For Invariant GFX-specific architecture documentation, see docs/architecture.md.
For AI agents working with this codebase, see AGENTS.md.
Development
# Run tests
uv run pytest
# Run linting
uv run ruff check src/ tests/
# Format code
uv run ruff format src/ tests/
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file invariant_gfx-0.1.0.tar.gz.
File metadata
- Download URL: invariant_gfx-0.1.0.tar.gz
- Upload date:
- Size: 106.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ba6d92c1394931ea95947d491ae5c8cfeca6c8547538cfb4de5375658481bae
|
|
| MD5 |
717f624544e8fe301fce07961766ad53
|
|
| BLAKE2b-256 |
0ae0f102350eb2b013b47849296a317811987ec43c8062ab756ff52b5c0269e8
|
File details
Details for the file invariant_gfx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: invariant_gfx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c16e4b782fdf59685c2168ecf6b6cb6549564caf5a98dafa69521adfd4f8e072
|
|
| MD5 |
7766011a835324caf526a3b29984a070
|
|
| BLAKE2b-256 |
9db581f94faa338bb0cb925ffcce7c8bc5575792ec998a1249e01aa7f441cfae
|