feat: type-safe .riv schema system#292
Closed
mfazekas wants to merge 18 commits into
Closed
Conversation
Adds a codegen pipeline that extracts artboard/SM/ViewModel schemas from .riv files at build time and exposes them as TypeScript phantom types. RiveView, useRiveFile, useRiveNumber/String/Boolean/Color/Trigger, and useViewModelInstance all gain typed overloads so wrong artboard names, state machine names, or property paths are caught at compile time. Scripts: rive-extract-schema.ts (WASM-based extractor), rive-gen-types.ts (generates .riv.d.ts alongside assets), with bun tests for both. Type-level tests via tsd in src/__tests__/typed-rive.test-d.ts.
71c5e59 to
e932f41
Compare
…lInstance Adds __vmBrand to TypedViewModelInstance so TypeScript rejects passing a typed instance to untyped hook overloads, ensuring wrong property paths are caught at compile time. Also adds allowArbitraryExtensions to tsconfig for .riv imports.
There was a problem hiding this comment.
Pull request overview
Introduces a POC build-time codegen pipeline that extracts .riv schemas and surfaces them as TypeScript phantom types, enabling type-safe artboard/state machine/view model usage with no runtime overhead.
Changes:
- Adds
RiveAsset<T>,TypedRiveFile<T>, andTypedViewModelInstance<T, VMName>plus typed path utilities to constrain hook/component inputs. - Adds Bun-based schema extraction +
.riv.d.tsgenerator scripts, along with Bun tests for the scripts. - Adds
tsdtype-level tests and updates examples/config to support typed.rivimports.
Reviewed changes
Copilot reviewed 24 out of 56 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Adds lock entries for @rive-app/canvas and tsd dependencies. |
| tsconfig.json | Enables arbitrary extension imports and excludes type-test/script-test files from standard TS checking. |
| src/index.tsx | Re-exports new typed schema/instance utility types from the public entrypoint. |
| src/hooks/useViewModelInstance.ts | Adds a typed overload returning a TypedViewModelInstance when schema + literal VM name are provided. |
| src/hooks/useRiveTrigger.ts | Adds typed overload for trigger property paths based on schema. |
| src/hooks/useRiveString.ts | Adds typed overload for string property paths based on schema. |
| src/hooks/useRiveNumber.ts | Adds typed overload for number property paths based on schema. |
| src/hooks/useRiveFile.ts | Adds typed overload so importing a typed .riv asset yields a TypedRiveFile<T>. |
| src/hooks/useRiveEnum.ts | Adds typed overload for enum properties (typed enum values). |
| src/hooks/useRiveColor.ts | Adds typed overload for color property paths based on schema. |
| src/hooks/useRiveBoolean.ts | Adds typed overload for boolean property paths based on schema. |
| src/core/TypedViewModelInstance.ts | Introduces core type utilities for typed view model instances, paths, enums, lists, and branding. |
| src/core/TypedRiveFile.ts | Introduces schema + branded asset/file phantom types (RiveFileSchema, RiveAsset, TypedRiveFile, SchemaOf). |
| src/core/RiveView.tsx | Types RiveViewProps to constrain artboard/state machine names when a schema is present. |
| src/core/RiveFile.ts | Makes factory methods generic over schema types and attempts to type fromSource for branded assets. |
| src/tests/typed-rive.test-d.ts | Adds tsd type tests validating typed assets, RiveViewProps, typed instances, and typed hooks. |
| scripts/rive-gen-types.ts | Adds generator CLI to emit .riv.d.ts declarations (and optional standalone schema types). |
| scripts/rive-extract-schema.ts | Adds WASM-based schema extraction script using @rive-app/canvas. |
| scripts/tests/rive-gen-types.test.ts | Adds Bun tests verifying .riv.d.ts generation output. |
| scripts/tests/rive-extract-schema.test.ts | Adds Bun tests verifying extracted artboards/SMs/view models (including nested refs + enums). |
| package.json | Adds rive-gen-types, typetest (tsd), and script tests; adds deps for generator/testing; configures Jest ignore for .test-d.ts. |
| example/src/exercisers/RiveDataBindingExample.tsx | Updates example to use typed .riv import + typed view model instance/property paths. |
| example/src/exercisers/FileSwitcher.tsx | Adds exerciser to rapidly switch files/fits to stress dispose/render race conditions. |
| example/assets/rive/vm_value_change_test.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/viewmodelproperty.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/style_fallback_fonts.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/rewards.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/rating.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/quick_start.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/out_of_band.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/on_entry_test.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/nodefaultbouncing.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/movecircle.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/many_viewmodels.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/layouts_demo.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/layout_test.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/ios_android_layouts_demo_v01.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/inputglow.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/hello_world_text.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/GradientBorder.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/font_fallback.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/fallback_fonts.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/databinding.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/databinding_lists.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/databinding_images.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/counter.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/bouncing_ball.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/blinko.riv.d.ts | Adds generated schema typing for the asset. |
| example/assets/rive/artboard_db_test.riv.d.ts | Adds generated schema typing for the asset. |
| eslint.config.mjs | Excludes .test-d.ts files from ESLint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Codegen pipeline that extracts artboard/state machine/ViewModel schemas from
.rivfiles and surfaces them as TypeScript phantom types — no runtime overhead.How it works
Step 1 — generate
.riv.d.tsalongside each asset (committed to git):yarn rive-gen-types example/assets/rive/rewards.riv yarn rive-gen-types --all example/assets/rive/ # batchUses
@rive-app/canvasWASM to introspect the file and emits a declaration:Step 2 — use the typed asset:
What's included
scripts/rive-extract-schema.ts— WASM-based extractor; resolves nested VM refs and extracts enum valuesscripts/rive-gen-types.ts— generates.riv.d.ts, single file or--allbatchsrc/core/TypedRiveFile.ts—RiveAsset<T>,TypedRiveFile<T>,SchemaOf<T>src/core/TypedViewModelInstance.ts—TypedViewModelInstance<T,N>,TypedViewModelOf<T,N>,UntypedViewModelInstance,PathsOfKind,EnumValuesOfRiveView,useRiveFile,useViewModelInstance,useRiveNumber/String/Boolean/Color/Enum/Trigger__vmBrandphantom property onTypedViewModelInstance— prevents typed instances from silently matching untyped hook overloadssrc/__tests__/typed-rive.test-d.ts— tsd type-level tests against real.riv.d.tsfiles.riv.d.tsis out of dateNotes
.riv.d.tsfiles are committed (same as nitrogen-generated bindings); CI enforces they stay in syncallowArbitraryExtensions: truein tsconfig for.rivimports to resolve their.riv.d.tsschemaToJSON()in the C++ runtime would fix this cleanly