Skip to content

feat!: v2 — Skia engine, 9 transitions, new API - #23

Merged
marioprieta merged 8 commits into
mainfrom
feat/v2-skia-rewrite
Apr 22, 2026
Merged

feat!: v2 — Skia engine, 9 transitions, new API#23
marioprieta merged 8 commits into
mainfrom
feat/v2-skia-rewrite

Conversation

@marioprieta

@marioprieta marioprieta commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

v2 is a major rewrite. The engine moved from react-native-view-shot to @shopify/react-native-skia, the hook return shape was flattened, and 8 new transition styles were added on top of v1's single fade.

Highlights

  • 9 transition stylesfade, circularReveal, heart, star, wipe, slide, split, pixelize, dissolve. Discriminated union on transition so TS only accepts the extra fields valid per variant.
  • Reshaped hook{ theme, preference, setTheme, isTransitioning }. theme.name is always concrete, preference carries the raw pick (including 'system') and updates synchronously so pickers drop optimistic state.
  • Strict runtime validation — invalid numeric options throw immediately at the setTheme call site instead of producing broken animations.
  • Expo Go on SDK 54+ — Skia 2.0 and Reanimated 4 are both bundled in modern Go clients. No prebuild required.

Breaking changes (abridged)

  • react-native-view-shot is no longer a peer dep; install @shopify/react-native-skia >= 2.0.0 instead.
  • Peer deps raised: react >= 19.0.0, react-native >= 0.78.0.
  • useTheme return shape changed. colors and name moved under theme. selected/select removed in favour of preference/setTheme.
  • setTheme returns 'accepted' | 'ignored' (was boolean).
  • Config fields removed: reduceMotion, duration (moved to per-call options), backgroundColor (paint your own root View background).
  • Renamed fields: axismode (split), grainSizenoiseSize (dissolve), invertedCircularReveal{ transition: 'circularReveal', inverted: true }.

Full migration guide in .changeset/v2-skia-rewrite.md and at react-native-theme-transition.vercel.app/docs/recipes/migration.

Test plan

  • `npm run lint` — biome clean
  • `npx tsc --noEmit` — clean
  • `npm test` — 99/99 pass
  • `npm run build` — dist/ emitted
  • Manual: v19 launch promo video renders correctly on iOS (new architecture)
  • CI workflow completes green
  • `changesets/action@v1` opens the "Version Packages" PR after merge to main, bumping 1.0.7 → 2.0.0 and publishing to npm with OIDC provenance

Notes

  • README + README.npm.md rewritten for v2 with hero gif (user-attachments CDN), Snack playground link, and agentic-skill install.
  • Docs site (docs/) rewritten end-to-end for v2.
  • Companion skill at skills.sh/marioprieta/skills/react-native-theme-transition restructured to mirror docs tree (23 topic-focused files).

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
@vercel

vercel Bot commented Apr 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-native-theme-transition Ready Ready Preview, Comment Apr 22, 2026 10:46am

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-shot capture pipeline with @shopify/react-native-skia (makeImageFromView) and introduces new transition metadata/types.
  • Reshapes useTheme API 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.

Comment thread src/overlay/resolveOrigin.ts
Comment thread src/transitionMeta.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/overlay/resolveOrigin.ts
Comment thread src/createThemeTransition.ts
Comment thread jest.setup.js Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@marioprieta
marioprieta merged commit 6860bb8 into main Apr 22, 2026
14 checks passed
@marioprieta
marioprieta deleted the feat/v2-skia-rewrite branch April 22, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants