SSGOI: app-like page transitions that leave your router alone
animated page transition for major ssr frameworks and browsers, including Safari
At a glance
- What is it?
- SSGOI is a page transition library for mobile web apps, PWAs and WebView shells, and its central choice is to run on the Web Animations API rather than the View Transition API, which is what makes it work in Safari and Firefox at the same time. It ships a package per framework, including React, Vue, Svelte, Angular, Solid and Qwik, and it is MIT licensed.
- Who is it for?
- SSGOI fits a team building a mobile web app or PWA that wants the drill and sheet transitions of a native app and wants its own router to keep owning navigation, and it fits a team that cannot wait for the View Transition API to reach Safari. It does not fit a project that is a desktop-first marketing site, where the transitions are decoration rather than navigation feedback.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It is built for phones, and the two transitions are phone gestures
SSGOI is described as native app-like page transitions for mobile web apps, PWAs and WebView apps, and the two transitions it leads with are named after the mobile interactions they imitate.
The first is Drill, described as navigating through a mobile app with spatial depth. The second is Sheet, described as presenting focused tasks above the current page. Both come with animated demonstrations in the repository's documentation assets, and the framing is a page that moves forward into the next page the way a native app does, and a sheet that rises over the current one the way a compose screen does on a phone.
That focus explains the whole design. A transition library aimed at desktop sites would be about taste, about which easing curve looks best. A transition library aimed at mobile web apps is about whether the user believes they are in an app, and that is a functional question about spatial continuity, about the next screen arriving from the direction your thumb expected it.
The repository is a monorepo with an `apps/` directory, a `packages/` directory, `plugins/`, `templates/`, `research/` and `plans/`, and a `wrangler.jsonc` at the root. The `templates/` directory holds one template per framework, which is a good sign of how the library is meant to be evaluated, since each one is a working app with the transition wired in. The `research/` directory suggests the author keeps notes on the underlying browser behaviour.
The site is ssgoi.dev, with the live showcase there and the documentation at ssgoi.dev/docs, and the default branch is `latest` rather than `main`, which is an unusual choice that suggests the development line is the published one.
Web Animations API instead of View Transitions, and why that matters
The technical decision that distinguishes SSGOI from the View Transition API is stated in the compatibility section: SSGOI depends on the broadly available Web Animations API instead of requiring the View Transition API.
That single choice determines the browser support table. The runtime targets are Chrome 84 and later, Safari 13.1 and later, Firefox 75 and later and Edge 84 and later. Those are Web Animations API targets, and the Safari figure is the one that matters most, since Safari is where the View Transition API lagged.
The comparison table draws a line the library is careful about. It is described as beyond the View Transition API, building transitions that need live DOM, runtime layers and precise geometry, and the mechanism it names is optimized motion, with spring physics precomputed into Web Animations API keyframes.
That precomputation is the interesting technical claim. A spring animation is not a keyframe list, it is a simulation, and simulating it during the transition would cost frames on a phone, which is exactly where the frames are scarce. Computing the spring curve up front and handing the browser a static keyframe list moves the work out of the animation frame and into a one-off calculation, so the animation itself is a plain interpolation the compositor can run.
The blur types in Sheet and Zoom need one more capability. They also use `backdrop-filter`, which is Firefox 103 and later, and the documentation is precise about the degradation: earlier Firefox keeps the transition, the scale and the dimming but omits the backdrop blur. That is a well-behaved fallback, since the animation still reads as a sheet and the missing piece is only the frosted background.
The same build is also meant to run inside WebView shells, and the documentation names Capacitor, Ionic, Tauri and React Native WebView, as well as as an installed PWA, with no native plugin. And it says the iOS and Android back swipes are left to the operating system, which is the correct division of labour.
The integration is one provider and one route boundary
The React and Next.js setup is described as one config, one provider and one simple ready-made route boundary, and the files are short enough to read in full.
The install is one command:
npm install @ssgoi/reactThe provider holds the configuration:
// app/ssgoi-provider.tsx
"use client";
import { type ReactNode } from "react";
import { Ssgoi } from "@ssgoi/react";
import { drill } from "@ssgoi/react/view-transitions";
const config = {
transitions: [{ on: "/**", except: "/", transition: drill() }],
};
export function SsgoiProvider({ children }: { children: ReactNode }) {
return <Ssgoi config={config}>{children}</Ssgoi>;
}The transition configuration is a list of rules with a path pattern, an exception and a transition function. `on: "/**"` matches every route, `except: "/"` leaves the root alone, and `drill()` is the transition to use. So the model is declarative, and the same shape presumably expresses a sheet on a different path or a different transition on a nested route.
The route boundary reads the pathname and handles URL-hook Suspense:
import { SsgoiRouteBoundary } from "@ssgoi/react/nextjs";
<SsgoiRouteBoundary>{children}</SsgoiRouteBoundary>;And the two are composed in the root layout:
// app/layout.tsx
import { type ReactNode } from "react";
import { SsgoiProvider } from "./ssgoi-provider";
import { SsgoiRouteBoundary } from "@ssgoi/react/nextjs";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<main className="relative z-0 min-h-dvh overflow-x-clip">
<SsgoiProvider>
<SsgoiRouteBoundary>{children}</SsgoiRouteBoundary>
</SsgoiProvider>
</main>
</body>
</html>
);
}That Tailwind class string on the main element is doing real work and the documentation explains it: the class is Tailwind shorthand, and without Tailwind you apply `position: relative; z-index: 0; min-height: 100dvh; overflow-x: clip` to the shell yourself, using `100vh` only where `dvh` is unsupported. The `dvh` unit is the dynamic viewport height, which matters on mobile where the browser chrome collapses as you scroll, and `overflow-x: clip` prevents the outgoing page from creating a horizontal scrollbar during the transition.
That is the whole integration for Next.js, and the claim that you can add SSGOI by changing only two files is accurate for this framework.
Router agnostic means optional peer dependencies, and that has a cost
The router-agnostic claim is the feature that makes SSGOI usable in an existing codebase, and it is implemented in a specific way worth understanding.
The documentation says that router subpaths use optional peers, so importing `@ssgoi/react` does not install or load Next.js. Other frameworks use the same small boundary model with their own router state. And the library observes the DOM lifecycle your framework already owns, so routing and SSR stay with your existing stack.
The point of that is the framework table. The library lists Next.js, React Router, TanStack Router, SvelteKit and Nuxt, and the compatibility section in the README names Vue and Nuxt, Solid and SolidStart, Angular and Qwik as well. The setup instructions in the README are described as covering React and Next.js, Svelte and SvelteKit, Vue and Nuxt, Solid and SolidStart, Angular and Qwik.
The cost of router agnosticism is that the library has to detect navigation without owning it. The alternative design, where the router is a dependency and the transition is triggered by a router hook, is simpler and more reliable, and it is what most transition libraries do. Working around the framework means working around the fact that each router has its own idea of when a navigation starts and ends, and each framework has its own way of rendering a new page and discarding the old one.
That is also why the standalone component is not what you would expect. The library is built around a boundary model rather than a component you wrap around each route, and the route boundary reads the pathname itself. For a team migrating between routers, that is a genuine benefit. For a team with one router and one framework, it is an abstraction you are paying for and may not need.
The release history shows the work is recent and fast. v7.3.0 added continuous motion across interrupted navigations, v7.3.1 fixed hero and zoom shared-image flashes, and v7.4.0 added hero, zoom chrome and shared scroll. The last push was on 2026-10-12.
An llms.txt and an agent plugin, which is a new kind of distribution
The README offers a setup path that is not a package manager, and it is the most distinctive thing about the project.
The first option is to give a URL to Claude, Codex, Cursor or another coding agent:
https://ssgoi.dev/llms.txtIt contains the full setup for React and Next.js, Svelte and SvelteKit, Vue and Nuxt, Solid and SolidStart, Angular, and Qwik. So the canonical setup instructions are published as a machine-readable document, and the workflow is that you hand the URL to an agent and it applies the library to your project.
The second option is an agent plugin, where the same `mobile-web-app` skill works in Codex and Claude Code:
codex plugin marketplace add meursyphus/ssgoi
codex plugin add ssgoi@ssgoiclaude plugin marketplace add meursyphus/ssgoi
claude plugin install ssgoi@ssgoiThen you ask the agent to apply SSGOI to the current mobile web app. The skill reads the canonical `llms.txt`, selects the matching framework guide, and follows the app's existing router and layout structure.
There is a `context7` style pattern here that is worth naming even if you do not use agents. The `llms.txt` format, which this project uses for its setup, is a link index of the documentation, and the `.claude-plugin/`, `.claude/` and `.agents/` directories at the root of this repository are the agent-facing configuration.
The trade-off is real. An agent applying a transition library to your codebase without you reading every file it changes is a different workflow from reading the documentation yourself, and it is faster. But the integration surface of this library is exactly two files, and the layout change it makes, adding a wrapper `main` element with a stacking context and a clip on overflow, is the kind of change that affects the rest of your app's layout, because `overflow-x: clip` on the shell means anything that relied on horizontal overflow now behaves differently. That is worth reading yourself whatever route you take to install it.
Where SSGOI is the wrong choice
The first case is a desktop-first site. The transitions are designed as mobile navigation feedback, and the drill and sheet metaphors assume a thumb and a phone screen. On a wide desktop layout, a drill transition that moves the page forward is decorative rather than informative, and it costs frames on a page that was previously free. If your product is a documentation site or a dashboard, this library is solving a problem you do not have.
The second case is a project that has already committed to the View Transition API. If your target browsers all support it, the native mechanism is simpler, it is maintained by the browser, and it does not need a library at all. Using SSGOI there means running a JS animation layer for a feature the platform provides.
The third is a project that cannot accept the layout change. The recommended setup wraps your content in a `main` element with `position: relative; z-index: 0; min-height: 100dvh; overflow-x: clip`. The `z-index: 0` creates a stacking context, which changes how fixed and sticky elements inside your app composite, and the `overflow-x: clip` hides horizontal overflow. Both are correct for a mobile app shell and both can break an existing design that assumed the page root was unclipped and unpositioned. If your app has a sticky header, a horizontally scrollable table or a full-screen modal, that is where you will find the problem.
The fourth is a team that wants the transition to be part of the router's contract. Because SSGOI observes the DOM lifecycle rather than hooking the router, you cannot easily make a transition conditional on the navigation's intent, on a query parameter or on the direction of travel, except through the route pattern matching in the configuration. A library that owns the navigation hook gives you more say over when a transition runs.
One more caution about the version numbers. The npm packages are versioned independently per framework, the root package.json in the monorepo is a private workspace at version 2.0.0, and the published release line is at 7.x. The releases move quickly, with three releases in the last month, so the version you pin and the version the documentation describes may not be the same one.
Editorial conclusion
SSGOI fits a team building a mobile web app or PWA that wants the drill and sheet transitions of a native app and wants its own router to keep owning navigation, and it fits a team that cannot wait for the View Transition API to reach Safari. It does not fit a project that is a desktop-first marketing site, where the transitions are decoration rather than navigation feedback. Before you adopt it, read the install documentation at ssgoi.dev/docs/install rather than the two-file quick start, because the quick start leaves out persistent layouts, nested boundaries and the framework-specific setup, and check the two changed files in your diff carefully since the provider and the route boundary are the whole integration surface.
Frequently asked questions
What is SSGOI and what does it do?
SSGOI is a page transition library for mobile web apps, PWAs and WebView apps, providing app-like transitions such as the drill transition for spatial navigation and the sheet transition for presenting a task above the current page. It is router agnostic, SSR ready and MIT licensed.
Which browsers does SSGOI support?
Chrome 84 and later, Safari 13.1 and later, Firefox 75 and later and Edge 84 and later, because it depends on the Web Animations API rather than the View Transition API. The blur in the Sheet and Zoom transitions also uses backdrop-filter, which needs Firefox 103 and later, with earlier Firefox keeping the transition, scale and dimming but losing the blur.
How do I add SSGOI to a Next.js project?
Install `@ssgoi/react`, create a provider component that wraps your children in `Ssgoi` with a transitions config, and wrap your content in `SsgoiRouteBoundary` from `@ssgoi/react/nextjs` inside the root layout. The two files are the whole integration, though the documentation at ssgoi.dev/docs/install covers persistent layouts and nested boundaries as well.
Does SSGOI work with frameworks other than React?
Yes. There are dedicated packages for Vue, Svelte, Angular, Solid and Qwik alongside React, and the setup instructions cover React and Next.js, Svelte and SvelteKit, Vue and Nuxt, Solid and SolidStart, Angular and Qwik. The library keeps your existing router, so it works with Next.js, React Router, TanStack Router, SvelteKit and Nuxt.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/meursyphus-ssgoi)Was this useful?