feat!: v2 — Skia engine, 9 transitions, new API - #23
Conversation
Rewrite the engine on top of `@shopify/react-native-skia`. The provider now keeps a permanently-mounted Skia Canvas and snapshots the inner tree into a SkImage on every transition, replacing the v1 view-shot → RN `<Image>` decode pipeline. A single 0 → 1 shared value drives nine animation styles through a shader, a shape clip, or a simple cross-fade. New transitions: fade, circularReveal, wipe, slide, split, heart, star, pixelize, dissolve. Every reveal and shape transition accepts `inverted`; strip transitions accept `direction` / `axis`; shaders accept `blockSize` / `grainSize`. `SetThemeOptions` is now a discriminated union so TypeScript only allows combinations valid for the picked transition. New config: `backgroundColor: (colors) => string` picks the root background color from the current theme so the Skia snapshot path can't leak the Activity's default window color through transparent regions on Android. `animated` is a new global opt-out for instant-switching apps. New runtime exports: `useReducedMotion()` hook, `TRANSITION_TYPES` array, `TRANSITION_META` table — use them to drive transition pickers that adapt their options to the selected style without hardcoding a list. Behavior: `select()` no longer reverts `selected` on rejection — the optimistic selection stays in place and the mid-tap flicker back to the previous pill is gone. `useTheme` is now a single signature that always returns the full shape (v1's overloaded form and `ThemeSelectionResult` are removed). Per-kind duration defaults: 350ms fade/reveal/strip, 800ms shape, 750ms shader. BREAKING: peer dep `react-native-view-shot` replaced with `@shopify/react-native-skia` (>= 2.0.0). No consumer code changes are required when the default `transition` (`'fade'`) is used.
…ia install Update every page to match the v2 engine and API. Clean sweep of stale v1 references (view-shot as primary, opacity-only fade) and the removed `diamond` transition. - Install commands in getting-started include `@shopify/react-native-skia` - api/create-theme-transition: document the new `backgroundColor` config option with example and Android ScrollView gotcha callout - types.mdx: add `backgroundColor` row to the config table, drop `diamond` from `TransitionType` and `SetThemeOptions` - guides/callbacks: rewrite the animated-transition sequence to match the real v2 flow (Skia snapshot, two-commit, settle pattern) - guides/troubleshooting: fix two stale view-shot attributions and drop `diamond` from the hardcoded-picker entry - recipes/migration: expand "New in 2.0" to cover all 8 new transitions plus `inverted`, `useReducedMotion`, `TRANSITION_TYPES`, `backgroundColor` - index / quick-start: refresh the opening blurbs so they describe Skia snapshot + shader/shape/fade instead of "capture and animate away"
- Rewrite the transition engine on @shopify/react-native-skia 2.0 - 9 transition styles via discriminated SetThemeOptions union - Split useTheme into theme (painted) + preference (user pick) - setTheme returns 'accepted' | 'ignored', throws on out-of-range numerics - Strict darkThemes validation, mountedRef StrictMode fix - stripInternal in tsconfig, no internal symbols leak to .d.ts - Full docs site, JSDoc, and examples aligned with v2 API - npm ci in CI workflows
Engine no longer paints a root background behind the inner tree. Users set backgroundColor on their own root View like any standard RN app. Drops the `backgroundColor` config option, the internal `rootWrapperStyle` memo, and the `resolveBackground` helper. Flagged as breaking in the v2 changeset with migration notes. Also corrects stale identifiers in the changeset (`settleBeforeCapture` → `SETTLE.beforeCapture`, `settleTreeRepaint` → `SETTLE.treeRepaint`) and the `setTimeout` cleanup description — the engine deliberately uses `setTimeout(duration)` because Reanimated 4's worklet completion callback doesn't reliably fire for the nested-async closures the engine creates.
Unified tagline across every dev-facing surface (landing, npm, docs overview, README.npm.md): "Animated theme transitions for React Native. Nine styles built on Skia, all running in Expo Go." Docs quality pass: - Normalized example paths to the Expo Router default (`lib/theme.ts` with `@/*` → `./*`, dropping the `src/` prefix) - Link provider.mdx from createThemeTransition + quick-start so the page stops being an orphan - Fix theme-button CYCLE cast with findIndex; jest mock in testing recipe uses requireActual spread; zustand recipe documents why getState() is intentional; migration guide renames its local useReducedMotion helper to avoid shadowing the removed v1 export; React Navigation notification slot uses theme.colors.notification to match the canonical theme shape - Drop AI-smell: rule-of-three cleanup in how-it-works intro, "100% JS" / "powered by Reanimated" stale markers purged
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Major v2 rewrite of react-native-theme-transition: migrates the transition engine to Skia, expands transitions to 9 styles, and reshapes the public API/docs accordingly.
Changes:
- Replaces
react-native-view-shotcapture pipeline with@shopify/react-native-skia(makeImageFromView) and introduces new transition metadata/types. - Reshapes
useThemeAPI to{ theme, preference, setTheme, isTransitioning }, adds strict per-call option validation, and updates exports. - Updates docs/recipes/examples, peer deps, CI install strategy (
npm ci), and adds unit/type-level tests for v2 behavior.
Reviewed changes
Copilot reviewed 58 out of 64 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Enables stripInternal to keep internal JSDoc-marked declarations out of emitted types. |
| src/validateSetThemeOptions.ts | Adds runtime validation for numeric setTheme options (duration/blockSize/noiseSize/origin coords). |
| src/transitionMeta.ts | Introduces transition registry (TRANSITION_META, TRANSITION_TYPES) and derived unions. |
| src/setThemeDecision.ts | Extracts pure decision logic for setTheme guard behavior. |
| src/overlay/types.ts | Centralizes overlay params + default constants for shader/strip modes. |
| src/overlay/resolveOrigin.ts | Adds origin resolution + radius calculation helpers for point-based transitions. |
| src/overlay/captureView.ts | Implements Skia-based view capture (makeImageFromView) with CPU image conversion. |
| src/index.ts | Updates package-level exports to new API surface + transition registry exports. |
| src/hooks/useTheme.ts | Removes v1 selection-tracking hook factory (API simplification). |
| src/createThemeTransition.ts | Updates factory validation, adds transition validation, switches hook impl to React 19 use(Context). |
| src/constants.ts | Adds reusable layout style constants for provider/overlays. |
| package.json | Updates description/keywords and swaps peer dep from view-shot → Skia; raises React/RN minimums. |
| package-lock.json | Reflects dependency swap to Skia and removal of view-shot subtree. |
| jest.setup.js | Updates Jest mocks for Skia capture + adds missing RN/Reanimated stubs used by the engine. |
| docs/src/app/layout.tsx | Updates site metadata description for v2 positioning. |
| docs/src/app/(home)/page.tsx | Updates homepage copy + install command to include Skia. |
| docs/next-env.d.ts | Adjusts route-types import path. |
| docs/content/docs/types.mdx | Rewrites exported-type reference for v2 and documents transition registry exports. |
| docs/content/docs/recipes/zustand.mdx | Updates persistence integration to v2 preference/setTheme model. |
| docs/content/docs/recipes/testing.mdx | Adds Jest mocking recipe for Skia/Reanimated/Worklets. |
| docs/content/docs/recipes/persistence.mdx | Updates AsyncStorage persistence recipe around preference. |
| docs/content/docs/recipes/multiple-scopes.mdx | Adds recipe for multiple independent theme scopes. |
| docs/content/docs/recipes/migration.mdx | Adds v1→v2 upgrade guide and broader migration content. |
| docs/content/docs/recipes/meta.json | Adds new recipe entries (multiple-scopes/testing). |
| docs/content/docs/recipes/haptic-feedback.mdx | Updates lifecycle callback guidance + examples for v2 API. |
| docs/content/docs/recipes/expo-router.mdx | Updates Expo Router integration (ThemeProvider + memoized nav theme). |
| docs/content/docs/quick-start.mdx | Rewrites quick start around v2 API shape and new install requirements. |
| docs/content/docs/index.mdx | Updates docs landing overview for Skia engine + 9 transitions. |
| docs/content/docs/guides/troubleshooting.mdx | Refreshes troubleshooting entries for v2 semantics and common pitfalls. |
| docs/content/docs/guides/how-it-works.mdx | Updates engine explanation/sequence around Skia snapshot pipeline + settle frames. |
| docs/content/docs/guides/callbacks.mdx | Updates callback ordering semantics and edge-case behavior for v2. |
| docs/content/docs/getting-started.mdx | Updates installation steps and adds new-architecture notes and tested versions table. |
| docs/content/docs/examples/theme-toggle.mdx | Updates example to v2 fields and discourages native Switch for snapshot correctness. |
| docs/content/docs/examples/theme-picker.mdx | Updates segmented picker to highlight via preference. |
| docs/content/docs/examples/theme-button.mdx | Updates simple button example to v2 API. |
| docs/content/docs/examples/system-theme.mdx | Updates system-mode behavior description to v2 theme/preference split. |
| docs/content/docs/examples/react-navigation.mdx | Updates React Navigation theme bridging to v2 theme.scheme and memoization. |
| docs/content/docs/examples/checkmark-list.mdx | Updates list picker to preference-driven checkmark. |
| docs/content/docs/api/use-theme.mdx | Rewrites API reference for v2 return shape, behavior rules, and runtime validation errors. |
| docs/content/docs/api/provider.mdx | Minor doc fixes + adds “See Also” section. |
| docs/content/docs/api/create-theme-transition.mdx | Rewrites factory reference and config validation docs for v2. |
| tests/validateSetThemeOptions.test.ts | Adds unit tests for runtime options validator. |
| tests/v2ApiShape.test.ts | Adds compile-time API shape guards for v2 types. |
| tests/transitionMeta.test.ts | Adds tests ensuring registry keys/types are aligned and stable. |
| tests/transitionConfig.test.ts | Adds tests for config-level transition validation. |
| tests/setThemeDecision.test.ts | Adds tests for extracted setTheme guard logic. |
| tests/resolveOrigin.test.ts | Adds tests for origin resolution + max-radius calculation. |
| tests/exports.test.ts | Updates export tests and adds guard against reintroducing removed v2 symbols. |
| tests/createThemeTransition.test.ts | Updates config validation tests (removes v1 duration checks, adds darkThemes validation). |
| tests/configEdgeCases.test.ts | Updates edge-case validation (empty darkThemes now throws). |
| tests/captureView.test.ts | Adds tests for Skia capture wrapper behavior. |
| README.npm.md | Rewrites npm README for v2 (Skia requirements, new API, updated install). |
| README.md | Rewrites GitHub README for v2 (Skia requirements, new API, updated install). |
| CONTRIBUTING.md | Minor wording/formatting adjustments. |
| .gitignore | Ignores additional build caches and internal planning folders. |
| .github/workflows/release.yml | Switches install step to npm ci for reproducible builds. |
| .github/workflows/ci.yml | Switches install step to npm ci across jobs. |
| .gitattributes | Adds LF normalization and binary file patterns. |
| .changeset/v2-skia-rewrite.md | Adds major changeset + migration notes for v2 release. |
Files not reviewed (1)
- docs/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 58 out of 64 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- docs/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 58 out of 64 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- docs/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
v2 is a major rewrite. The engine moved from
react-native-view-shotto@shopify/react-native-skia, the hook return shape was flattened, and 8 new transition styles were added on top of v1's singlefade.Highlights
fade,circularReveal,heart,star,wipe,slide,split,pixelize,dissolve. Discriminated union ontransitionso TS only accepts the extra fields valid per variant.{ theme, preference, setTheme, isTransitioning }.theme.nameis always concrete,preferencecarries the raw pick (including'system') and updates synchronously so pickers drop optimistic state.setThemecall site instead of producing broken animations.Breaking changes (abridged)
react-native-view-shotis no longer a peer dep; install@shopify/react-native-skia >= 2.0.0instead.react >= 19.0.0,react-native >= 0.78.0.useThemereturn shape changed.colorsandnamemoved undertheme.selected/selectremoved in favour ofpreference/setTheme.setThemereturns'accepted' | 'ignored'(wasboolean).reduceMotion,duration(moved to per-call options),backgroundColor(paint your own rootViewbackground).axis→mode(split),grainSize→noiseSize(dissolve),invertedCircularReveal→{ transition: 'circularReveal', inverted: true }.Full migration guide in
.changeset/v2-skia-rewrite.mdand at react-native-theme-transition.vercel.app/docs/recipes/migration.Test plan
dist/emittedmain, bumping1.0.7 → 2.0.0and publishing to npm with OIDC provenanceNotes
docs/) rewritten end-to-end for v2.