Add diagonal view-transition wipe between pages

Hooks SvelteKit's onNavigate into the View Transitions API and styles the
old/new root pseudos with a scaled fade-out and a clip-path diagonal reveal
trimmed by a green drop-shadow accent. Honors prefers-reduced-motion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
David Beccue
2026-05-16 07:49:33 +05:00
parent 8817b5bc07
commit def8f1d78f
2 changed files with 45 additions and 2 deletions

9
package-lock.json generated
View File

@ -13,7 +13,6 @@
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-node": "^5.2.0", "@sveltejs/adapter-node": "^5.2.0",
"@sveltejs/kit": "^2.5.0", "@sveltejs/kit": "^2.5.0",
"@sveltejs/vite-plugin-svelte": "^3.1.0",
"svelte": "^4.2.0", "svelte": "^4.2.0",
"vite": "^5.2.0" "vite": "^5.2.0"
} }
@ -996,6 +995,7 @@
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4", "debug": "^4.3.4",
@ -1019,6 +1019,7 @@
"integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
@ -1227,6 +1228,7 @@
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
}, },
@ -1585,7 +1587,8 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.12", "version": "3.3.12",
@ -2033,6 +2036,7 @@
"integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"peer": true,
"engines": { "engines": {
"node": "^12.20 || ^14.13.1 || >= 16" "node": "^12.20 || ^14.13.1 || >= 16"
}, },
@ -2182,6 +2186,7 @@
"integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0" "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
}, },

View File

@ -1,5 +1,16 @@
<script> <script>
import { onNavigate } from '$app/navigation';
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
onNavigate((navigation) => {
if (!document.startViewTransition) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
</script> </script>
<Header /> <Header />
@ -105,4 +116,31 @@
margin: 0 auto; margin: 0 auto;
padding: 1.5rem 1.25rem 3rem; padding: 1.5rem 1.25rem 3rem;
} }
@keyframes -global-va-fade-out {
from { opacity: 1; transform: scale(1); filter: blur(0); }
to { opacity: 0; transform: scale(0.97); filter: blur(2px); }
}
@keyframes -global-va-wipe-in {
from { clip-path: polygon(0% 0%, 0% 0%, 0% 0%); }
to { clip-path: polygon(0% 0%, 220% 0%, 0% 220%); }
}
:global(::view-transition-old(root)) {
animation: va-fade-out 500ms cubic-bezier(0.4, 0, 1, 1) both;
transform-origin: 50% 40%;
}
:global(::view-transition-new(root)) {
animation: va-wipe-in 700ms cubic-bezier(0.76, 0, 0.24, 1) both;
filter:
drop-shadow(2px 2px 0 #006a4e)
drop-shadow(10px 8px 26px rgba(0, 106, 78, 0.22));
}
@media (prefers-reduced-motion: reduce) {
:global(::view-transition-old(root)),
:global(::view-transition-new(root)) {
animation: none;
filter: none;
clip-path: none;
}
}
</style> </style>