Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
02c354a
feat(cg): viewport culling at draw time
softmarshmallow Mar 10, 2026
605e06f
feat(cg): headless GPU rendering module
softmarshmallow Mar 10, 2026
e1a1798
perf(cg): replace HashSet<NodeId> with Vec<bool> bitset for visibilit…
softmarshmallow Mar 10, 2026
fc8ee1e
perf(cg): remove unnecessary sort of R-tree indices in frame plan
softmarshmallow Mar 10, 2026
0ff7abf
fix: update environment variable for local WASM serving
softmarshmallow Mar 10, 2026
b11fedc
revert(cg): remove viewport culling from painter and scene
softmarshmallow Mar 10, 2026
1a28d62
Merge branch 'main' of https://github.com/gridaco/grida into canary
softmarshmallow Mar 10, 2026
ef0f7f7
Merge branch 'main' of https://github.com/gridaco/grida into canary
softmarshmallow Mar 10, 2026
4897f17
format save GRID magic bits
softmarshmallow Mar 10, 2026
0576867
Update schema version to 0.91.0-beta+20260311 across multiple files
softmarshmallow Mar 11, 2026
2ae7562
Enhance image source handling in editor and query modules
softmarshmallow Mar 12, 2026
6203778
Add CHANGELOG.md and update grida.fbs for NodeSlot wrapper
softmarshmallow Mar 12, 2026
bb8d105
Update FlatBuffers integration and add freshness check workflow
softmarshmallow Mar 12, 2026
36cd8ab
Add scene navigation and .grida file support
softmarshmallow Mar 12, 2026
710240e
add FlatBuffers test fixtures
softmarshmallow Mar 12, 2026
58b6068
Implement OPFS data quarantine mechanism
softmarshmallow Mar 12, 2026
5de1b46
Update text decoration terminology and enhance documentation
softmarshmallow Mar 13, 2026
7681e80
mv
softmarshmallow Mar 13, 2026
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
62 changes: 62 additions & 0 deletions .github/workflows/check-generated-fbs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# -----------------------------------------------------------------
# Freshness check for committed FlatBuffers bindings
# -----------------------------------------------------------------
#
# Why this exists
# ---------------
# The Rust FlatBuffers bindings (`crates/grida-canvas/src/io/generated/grida.rs`)
# are committed to git so that `cargo build` works from a clean checkout without
# requiring `flatc`. However, because the file is generated from `format/grida.fbs`,
# it can become stale if someone edits the schema but forgets to regenerate.
#
# This workflow re-runs codegen and asserts that the committed file is identical
# to what `flatc` would produce. If it differs, the check fails with a clear
# error message telling the contributor how to fix it.
#
# When does it run
# ----------------
# Only on PRs / pushes that touch the schema, the generated output, the codegen
# tooling, or the TS format package (which shares the same schema source).
#
# How to fix a failure
# --------------------
# pnpm --filter @crates/grida-canvas generate
# git add crates/grida-canvas/src/io/generated/grida.rs
# git commit
# -----------------------------------------------------------------

name: check generated flatbuffers

on:
push:
branches:
- main
pull_request:
paths:
- "format/grida.fbs"
- "crates/grida-canvas/src/io/generated/**"
- "packages/grida-format/src/**"
- "bin/activate-flatc"

jobs:
rust-bindings:
name: rust fbs freshness
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Regenerate Rust FlatBuffers bindings
run: |
python3 bin/activate-flatc -- --rust \
-o crates/grida-canvas/src/io/generated \
format/grida.fbs
mv crates/grida-canvas/src/io/generated/grida_generated.rs \
crates/grida-canvas/src/io/generated/grida.rs

- name: Check for uncommitted changes
run: |
if ! git diff --exit-code crates/grida-canvas/src/io/generated/grida.rs; then
echo "::error::Generated Rust FlatBuffers bindings are stale. Run 'pnpm --filter @crates/grida-canvas generate' and commit the result."
exit 1
fi
50 changes: 48 additions & 2 deletions Cargo.lock

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

7 changes: 4 additions & 3 deletions bin/activate-flatc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ Grida: FlatBuffers compiler (flatc) bootstrapper

Why this exists
---------------
We intentionally do NOT commit generated FlatBuffers bindings to git (see
`packages/grida-format/.gitignore`). The package build step runs `flatc` (see
`packages/grida-format/package.json`), so CI and Vercel builds must have a
Generated FlatBuffers bindings are committed for the Rust crate
(`crates/grida-canvas/src/io/generated/grida.rs`) so that `cargo build` works
from a clean checkout. The TypeScript package (`packages/grida-format`)
regenerates at build time. In both cases CI and Vercel builds need a
deterministic way to obtain `flatc`.

FlatBuffers does not ship `flatc` via npm, so this script installs a prebuilt
Expand Down
2 changes: 1 addition & 1 deletion crates/grida-canvas-wasm/example/demo.grida1
Original file line number Diff line number Diff line change
Expand Up @@ -9889,5 +9889,5 @@
"main"
]
},
"version": "0.90.0-beta+20260108"
"version": "0.91.0-beta+20260311"
}
2 changes: 1 addition & 1 deletion crates/grida-canvas-wasm/example/gradient.grida1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.90.0-beta+20260108",
"version": "0.91.0-beta+20260311",
"document": {
"nodes": {
"gradient-rect": {
Expand Down
2 changes: 1 addition & 1 deletion crates/grida-canvas-wasm/example/rectangle.grida1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.90.0-beta+20260108",
"version": "0.91.0-beta+20260311",
"document": {
"nodes": {
"rectangle": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe("raster export (node)", () => {
const imageBytes = new Uint8Array(readFileSync(imagePath));

const doc = {
version: "0.90.0-beta+20260108",
version: "0.91.0-beta+20260311",
document: {
nodes: {
"image-rect": {
Expand Down
3 changes: 1 addition & 2 deletions crates/grida-canvas/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,5 @@ See [examples/tool_io_grida.rs](./examples/tool_io_grida.rs) for full documentat
## Package Docs

```sh
# skia-safe
cargo doc --package skia-safe --open --no-deps
cargo doc --package cg --open --no-deps
```
1 change: 1 addition & 0 deletions crates/grida-canvas/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ gl = "0.14.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
json-patch = "4.1.0"
flatbuffers = "25.12.19"

# text editing
grida-text-edit = { path = "../grida-text-edit" }
Expand Down
134 changes: 99 additions & 35 deletions crates/grida-canvas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,116 @@

<img src="./cover.png" alt="Grida Canvas Rendering Backend Example" width="100%" />

Grida Canvas core graphics implements High-level Node & Property based Graphics API that supports mordern design techniques.
Grida Canvas is a **safe, high-performance 2D real-time rendering engine** for the Grida design tool. It provides a node- and property-based graphics API with support for modern design techniques.

## Rendering
- **Rendering**: [`skia-safe`](https://rust-skia.github.io/doc/skia_safe/) for painting
- **Geometry & math**: [`math2`](../math2/README.md) for transforms, rects, and common operations

**2D Nodes**
## Capabilities

- [ ] TextSpan
- [ ] Text (Text with mixed styles)
- [ ] Image
- [ ] Bitmap (for bitmap drawing)
- [ ] Group
- [ ] Container (Frame)
- [ ] Rectangle
- [ ] Ellipse
- [ ] Polygon
- [ ] RegularPolygon
- [ ] RegularStarPolygon
- [ ] Path (SVG Path)
- [ ] Vector (Vector Network)
- [ ] Line
### 2D nodes

**Meta**
| Node | Status |
| ------------------------------------------- | ------ |
| Container (Frame) | ✅ |
| Group | ✅ |
| Rectangle | ✅ |
| Ellipse (incl. arc, ring, sector) | ✅ |
| Polygon, RegularPolygon, RegularStarPolygon | ✅ |
| Line | ✅ |
| Path (SVG path) | ✅ |
| Vector (vector network) | ✅ |
| BooleanOperation | ✅ |
| TextSpan | ✅ |
| Image | ✅ |
| InitialContainer, Error | ✅ |

- [ ] Mask
- [ ] Clip
### Paints & effects

**Styles & Effects**
- **Fills**: Solid, LinearGradient, RadialGradient, SweepGradient, Image (with fit and image filters)
- **Strokes**: Stroke width (uniform/variable), dash array, caps/joins, stroke alignment, rect-specific stroke widths, markers
- **Effects**: Layer blur, backdrop blur, drop/inner shadow, liquid glass, noise
- **Blend modes** on layers and paints

- [ ] SolidPaint
- [ ] LinearGradientPaint
- [ ] RadialGradientPaint
- [ ] DropShadow
- [ ] BoxShadow
- [ ] BlendMode
### Layout

## API
- **Taffy**-based layout: flex (direction, alignment, gap, padding), positioning (inset, width/height), transform

**Camera**
### Meta

- [ ] 2D Camera
- **Masks** (layer and vector masks)

**Pipeline & API**
### Pipeline & runtime

- [ ] load font
- [ ] load image
- **Camera**: 2D camera (pan, zoom, viewport)
- **Resources**: Font loading (`FontRepository`), image loading (`ImageRepository`), embedded fonts (e.g. Geist, Geist Mono)
- **Export**: PNG, JPEG, WEBP, BMP, PDF, SVG

## Interactivity
### Interactivity

- [ ] Hit testing
- **Hit testing**: `HitTester` for point-in-node and hit-test queries

## I/O

| Module | Description |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `io::io_grida_fbs` | Encode/decode `.grida` FlatBuffers binaries. Bindings are generated from `format/grida.fbs` via `flatc --rust` (see repo root and `format/README.md`). |
| `io::io_grida` | Decode Grida JSON documents into a `Scene`. |
| `io::io_grida_patch` | Apply JSON Patch to a decoded scene. |
| `io::io_figma` | Decode Figma API JSON into a `Scene` (feature-gated: `--features figma`). |
| `io::io_svg`, `io::io_css`, `io::io_markdown` | Additional import/parsing helpers. |

### Test fixtures

Raw FlatBuffers test fixtures live in [`fixtures/test-grida/`](../../fixtures/test-grida/) at the repo root. In-memory round-trip tests are in `cargo test --package cg --test fbs_roundtrip`. See the fixtures directory README for format and version details.

## NodeID system

The canvas uses a dual-ID system:

- **NodeId** (`u64`): Internal counter-based IDs for high-performance operations. Ephemeral and not serialized.
- **UserNodeId** (`String`): External user-provided IDs for public APIs. Stable and serialized in `.grida` files.

See [AGENTS.md](./AGENTS.md#nodeid-system) for details and migration notes.

## Testing & development

```sh
# run tests
cargo test

# run fmt
cargo fmt

# run check
cargo check
cargo check --all-targets --all-features

# run clippy (no deps — skips re-checking skia etc.)
cargo clippy --no-deps --all-targets --all-features

# run build
cargo build

# run examples (many require window/GPU; headless_gpu requires native-gl-context)
cargo run --example <example-name>
cargo run --example headless_gpu --features native-gl-context
```

## Tools

### `tool_io_grida` — Grida file validator

CLI for validating `.grida` files and debugging parsing.

```sh
cargo run --example tool_io_grida <path-to-grida-file>
```

Validates file structure, reports node counts and types, and surfaces decode errors. See [examples/tool_io_grida.rs](./examples/tool_io_grida.rs) for full documentation.

## Package docs

```sh
cargo doc --package cg --open --no-deps
```
Loading
Loading