@luisitoluis/viewfx 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luis Martínez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.es.md ADDED
@@ -0,0 +1,109 @@
1
+ <div align="center">
2
+
3
+ # ViewFX
4
+
5
+ [![en](https://img.shields.io/badge/lang-en-red.svg)](./README.md)
6
+ [![es](https://img.shields.io/badge/lang-es-yellow.svg)](./README.es.md)
7
+
8
+ ![GitHub stars](https://img.shields.io/github/stars/LuisitoLuis/viewfx)
9
+ ![GitHub Forks](https://img.shields.io/github/forks/LuisitoLuis/viewfx)
10
+ ![GitHub PRs](https://img.shields.io/github/issues-pr/LuisitoLuis/viewfx)
11
+ ![GitHub issues](https://img.shields.io/github/issues/LuisitoLuis/viewfx)
12
+ ![GitHub Contributors](https://img.shields.io/github/contributors/LuisitoLuis/viewfx)
13
+
14
+ ![Catálogo de ViewFX](./lib/imgs/web.png)
15
+
16
+ ![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-4-blue?style=for-the-badge&logo=tailwind-css)
17
+ ![npm](https://img.shields.io/npm/v/viewfx?style=for-the-badge)
18
+
19
+ Transiciones de tema con una sola clase de Tailwind en <code>&lt;html&gt;</code>.
20
+
21
+ Visita la [web](https://viewfx.luismc.dev) o el [playground](https://viewfx.luismc.dev/playground) para obtener más información.
22
+
23
+ </div>
24
+
25
+ ## Instalación :book:
26
+
27
+ #### Instalar el paquete
28
+
29
+ > Instala el paquete con tu gestor de paquetes favorito:
30
+
31
+ - npm
32
+
33
+ ```bash
34
+ npm install viewfx
35
+ ```
36
+
37
+ - pnpm
38
+
39
+ ```bash
40
+ pnpm add viewfx
41
+ ```
42
+
43
+ - yarn
44
+
45
+ ```bash
46
+ yarn add viewfx
47
+ ```
48
+
49
+ #### Implementación del plugin
50
+
51
+ > Úsalo en tu proyecto de Tailwind CSS:
52
+
53
+ ```css
54
+ /* globals.css (para Tailwind CSS 4.*) */
55
+ @import 'tailwindcss';
56
+ @import 'viewfx';
57
+ ```
58
+
59
+ > Tailwind CSS v3 — registra el plugin de JavaScript:
60
+
61
+ ```js
62
+ /** @type {import('tailwindcss').Config} */
63
+ module.exports = {
64
+ plugins: [
65
+ require('viewfx')
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## Uso :gear:
71
+
72
+ #### Ejemplo
73
+
74
+ > Pon una clase de efecto en `<html>` y envuelve el toggle de tema en `document.startViewTransition`:
75
+
76
+ ```html
77
+ <html class="dark circle">
78
+ ```
79
+
80
+ ```html
81
+ <html class="dark circle-duration-1000-delay-300">
82
+ ```
83
+
84
+ ```js
85
+ const switchTheme = () =>
86
+ document.documentElement.classList.toggle('dark')
87
+
88
+ document.startViewTransition
89
+ ? document.startViewTransition(switchTheme)
90
+ : switchTheme()
91
+ ```
92
+
93
+ El timing puede ir en la misma clase (`circle-duration-1000`, `circle-duration-1000-delay-300`) o en utilidades sueltas: `fx-duration-1000`, `fx-delay-300`, `fx-steps-modern`.
94
+
95
+ El tema se espera como clase `.dark` en `<html>` (el wipe `polygon` se invierte en oscuro).
96
+
97
+ `prefers-reduced-motion: reduce` se respeta: el tema cambia, el wipe no. Los navegadores sin View Transitions API cambian al instante.
98
+
99
+ ### Efectos
100
+
101
+ 30 utilidades. Pasa el ratón para previsualizar y haz clic para copiar en el [catálogo](https://viewfx.luismc.dev).
102
+
103
+ `circle`, `circle-blur`, `polygon`, `corner-tl`, `corner-tr`, `corner-bl`, `corner-br`, `iris`, `diamond`, `hexagon`, `square`, `soft`, `heart`, `expand`, `split`, `shutter`, `ink`, `spiral`, `wipe-h`, `wipe-left`, `wipe-v`, `slide-down`, `venetian`, `glitch`, `slide`, `lift`, `zoom`, `rotate`, `fade`, `dissolve`.
104
+
105
+ ## Contribuidores 👑
106
+
107
+ <a href="https://github.com/LuisitoLuis/viewfx/graphs/contributors">
108
+ <img src="https://contrib.rocks/image?repo=LuisitoLuis/viewfx" alt="Contribuidores de ViewFX" />
109
+ </a>
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ <div align="center">
2
+
3
+ # ViewFX
4
+
5
+ [![en](https://img.shields.io/badge/lang-en-red.svg)](./README.md)
6
+ [![es](https://img.shields.io/badge/lang-es-yellow.svg)](./README.es.md)
7
+
8
+ ![GitHub stars](https://img.shields.io/github/stars/LuisitoLuis/viewfx)
9
+ ![GitHub Forks](https://img.shields.io/github/forks/LuisitoLuis/viewfx)
10
+ ![GitHub PRs](https://img.shields.io/github/issues-pr/LuisitoLuis/viewfx)
11
+ ![GitHub issues](https://img.shields.io/github/issues/LuisitoLuis/viewfx)
12
+ ![GitHub Contributors](https://img.shields.io/github/contributors/LuisitoLuis/viewfx)
13
+
14
+ ![ViewFX catalogue](./lib/imgs/web.png)
15
+
16
+ ![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-4-blue?style=for-the-badge&logo=tailwind-css)
17
+ ![npm](https://img.shields.io/npm/v/viewfx?style=for-the-badge)
18
+
19
+ Theme transitions with one Tailwind class on <code>&lt;html&gt;</code>.
20
+
21
+ Visit the [website](https://viewfx.luismc.dev) or the [playground](https://viewfx.luismc.dev/playground) to get more information.
22
+
23
+ </div>
24
+
25
+ ## Installation :book:
26
+
27
+ #### Package install
28
+
29
+ > Install the package with your favorite package manager:
30
+
31
+ - npm
32
+
33
+ ```bash
34
+ npm install viewfx
35
+ ```
36
+
37
+ - pnpm
38
+
39
+ ```bash
40
+ pnpm add viewfx
41
+ ```
42
+
43
+ - yarn
44
+
45
+ ```bash
46
+ yarn add viewfx
47
+ ```
48
+
49
+ #### Plugin Implementation
50
+
51
+ > Use the plugin in your Tailwind CSS project:
52
+
53
+ ```css
54
+ /* globals.css (for Tailwind CSS 4.*) */
55
+ @import 'tailwindcss';
56
+ @import 'viewfx';
57
+ ```
58
+
59
+ > Tailwind CSS v3 — register the JavaScript plugin:
60
+
61
+ ```js
62
+ /** @type {import('tailwindcss').Config} */
63
+ module.exports = {
64
+ plugins: [
65
+ require('viewfx')
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## Usage :gear:
71
+
72
+ #### Example
73
+
74
+ > Put an effect class on `<html>`, then wrap your theme toggle in `document.startViewTransition`:
75
+
76
+ ```html
77
+ <html class="dark circle">
78
+ ```
79
+
80
+ ```html
81
+ <html class="dark circle-duration-1000-delay-300">
82
+ ```
83
+
84
+ ```js
85
+ const switchTheme = () =>
86
+ document.documentElement.classList.toggle('dark')
87
+
88
+ document.startViewTransition
89
+ ? document.startViewTransition(switchTheme)
90
+ : switchTheme()
91
+ ```
92
+
93
+ Timing can sit in the same class (`circle-duration-1000`, `circle-duration-1000-delay-300`) or as separate utilities: `fx-duration-1000`, `fx-delay-300`, `fx-steps-modern`.
94
+
95
+ Theme is expected as a `.dark` class on `<html>` (the `polygon` wipe reverses in dark).
96
+
97
+ `prefers-reduced-motion: reduce` is honoured: the theme still changes, without the wipe. Browsers without the View Transitions API skip the animation and toggle instantly.
98
+
99
+ ### Effects
100
+
101
+ 30 utilities. Hover to preview and click to copy on the [catalogue](https://viewfx.luismc.dev).
102
+
103
+ `circle`, `circle-blur`, `polygon`, `corner-tl`, `corner-tr`, `corner-bl`, `corner-br`, `iris`, `diamond`, `hexagon`, `square`, `soft`, `heart`, `expand`, `split`, `shutter`, `ink`, `spiral`, `wipe-h`, `wipe-left`, `wipe-v`, `slide-down`, `venetian`, `glitch`, `slide`, `lift`, `zoom`, `rotate`, `fade`, `dissolve`.
104
+
105
+ ## Contributors 👑
106
+
107
+ <a href="https://github.com/LuisitoLuis/viewfx/graphs/contributors">
108
+ <img src="https://contrib.rocks/image?repo=LuisitoLuis/viewfx" alt="ViewFX contributors" />
109
+ </a>
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@luisitoluis/viewfx",
3
+ "version": "0.0.3",
4
+ "description": "Tailwind CSS v3/v4 plugin for View Transitions theme effects",
5
+ "style": "./src/index.css",
6
+ "main": "./src/plugin.cjs",
7
+ "exports": {
8
+ ".": {
9
+ "style": "./src/index.css",
10
+ "require": "./src/plugin.cjs",
11
+ "import": "./src/plugin.js",
12
+ "default": "./src/plugin.cjs"
13
+ },
14
+ "./index.css": "./src/index.css",
15
+ "./plugin": {
16
+ "require": "./src/plugin.cjs",
17
+ "import": "./src/plugin.js",
18
+ "default": "./src/plugin.cjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "src"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/LuisitoLuis/viewfx.git"
27
+ },
28
+ "homepage": "https://viewfx.luismc.dev",
29
+ "type": "module",
30
+ "scripts": {
31
+ "emit:masks": "node scripts/emit-masks.mjs",
32
+ "test": "vitest",
33
+ "test:ci": "vitest run"
34
+ },
35
+ "keywords": [
36
+ "tailwind",
37
+ "css",
38
+ "view-transitions",
39
+ "theme",
40
+ "plugin"
41
+ ],
42
+ "license": "MIT",
43
+ "engines": {
44
+ "node": ">=22.12.0"
45
+ },
46
+ "peerDependencies": {
47
+ "tailwindcss": "^3.0.0 || ^4.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@csstools/postcss-minify": "3.0.0",
51
+ "@tailwindcss/postcss": "4.3.3",
52
+ "postcss": "8.5.25",
53
+ "tailwindcss": "4.3.3",
54
+ "tailwindcss-v3": "npm:tailwindcss@3.4.17",
55
+ "vitest": "5.0.0"
56
+ }
57
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Combined effect+timing utilities:
3
+ * circle-duration-1000
4
+ * circle-duration-1000-delay-300
5
+ *
6
+ * Tailwind v4 only allows one `*` in `@utility` names, so these are registered
7
+ * from JS (`@plugin` in v4, `require('viewfx')` in v3).
8
+ */
9
+ const plugin = require('tailwindcss/plugin')
10
+ const effects = require('./effects.cjs')
11
+ const { duration, delay } = require('./theme.json')
12
+
13
+ function registerCompound({ matchUtilities }) {
14
+ for (const [selector, tokens] of Object.entries(effects)) {
15
+ if (!selector.startsWith('.') || selector.includes('.dark')) continue
16
+
17
+ const name = selector.slice(1)
18
+
19
+ matchUtilities(
20
+ {
21
+ [`${name}-duration`]: (value) => ({
22
+ ...tokens,
23
+ '--fx-duration-override': value
24
+ })
25
+ },
26
+ { values: duration }
27
+ )
28
+
29
+ for (const [durationKey, durationValue] of Object.entries(duration)) {
30
+ matchUtilities(
31
+ {
32
+ [`${name}-duration-${durationKey}-delay`]: (value) => ({
33
+ ...tokens,
34
+ '--fx-duration-override': durationValue,
35
+ '--fx-delay': value
36
+ })
37
+ },
38
+ { values: delay }
39
+ )
40
+ }
41
+ }
42
+ }
43
+
44
+ const compoundPlugin = plugin(registerCompound)
45
+ compoundPlugin.registerCompound = registerCompound
46
+
47
+ module.exports = compoundPlugin
@@ -0,0 +1,212 @@
1
+ /** Effect utilities — keep in sync with `@utility` blocks in `src/index.css`. */
2
+
3
+ module.exports = {
4
+ '.circle': {
5
+ '--fx-anim': 'fx-mask-grow',
6
+ '--fx-anim-old': 'none',
7
+ '--fx-old-z': '-1',
8
+ '--fx-mask': 'var(--mask-circle)',
9
+ '--fx-mask-size': '200vmax',
10
+ '--fx-duration': '1s'
11
+ },
12
+ '.circle-blur': {
13
+ '--fx-anim': 'fx-mask-grow',
14
+ '--fx-anim-old': 'none',
15
+ '--fx-old-z': '-1',
16
+ '--fx-mask': 'var(--mask-circle-blur)',
17
+ '--fx-mask-size': '200vmax',
18
+ '--fx-duration': '1s'
19
+ },
20
+ '.corner-tl': {
21
+ '--fx-anim': 'fx-mask-grow',
22
+ '--fx-anim-old': 'none',
23
+ '--fx-old-z': '-1',
24
+ '--fx-mask': 'var(--mask-corner-tl)',
25
+ '--fx-mask-position': 'top left',
26
+ '--fx-mask-size': '350vmax',
27
+ '--fx-duration': '1s'
28
+ },
29
+ '.corner-tr': {
30
+ '--fx-anim': 'fx-mask-grow',
31
+ '--fx-anim-old': 'none',
32
+ '--fx-old-z': '-1',
33
+ '--fx-mask': 'var(--mask-corner-tr)',
34
+ '--fx-mask-position': 'top right',
35
+ '--fx-mask-size': '350vmax',
36
+ '--fx-duration': '1s'
37
+ },
38
+ '.corner-bl': {
39
+ '--fx-anim': 'fx-mask-grow',
40
+ '--fx-anim-old': 'none',
41
+ '--fx-old-z': '-1',
42
+ '--fx-mask': 'var(--mask-corner-bl)',
43
+ '--fx-mask-position': 'bottom left',
44
+ '--fx-mask-size': '350vmax',
45
+ '--fx-duration': '1s'
46
+ },
47
+ '.corner-br': {
48
+ '--fx-anim': 'fx-mask-grow',
49
+ '--fx-anim-old': 'none',
50
+ '--fx-old-z': '-1',
51
+ '--fx-mask': 'var(--mask-corner-br)',
52
+ '--fx-mask-position': 'bottom right',
53
+ '--fx-mask-size': '350vmax',
54
+ '--fx-duration': '1s'
55
+ },
56
+ '.iris': {
57
+ '--fx-anim': 'fx-mask-grow',
58
+ '--fx-anim-old': 'none',
59
+ '--fx-old-z': '-1',
60
+ '--fx-mask': 'var(--mask-star)',
61
+ '--fx-mask-size': '300vmax',
62
+ '--fx-duration': '0.9s'
63
+ },
64
+ '.diamond': {
65
+ '--fx-anim': 'fx-mask-grow',
66
+ '--fx-anim-old': 'none',
67
+ '--fx-old-z': '-1',
68
+ '--fx-mask': 'var(--mask-diamond)',
69
+ '--fx-mask-size': '280vmax',
70
+ '--fx-duration': '0.9s'
71
+ },
72
+ '.hexagon': {
73
+ '--fx-anim': 'fx-mask-grow',
74
+ '--fx-anim-old': 'none',
75
+ '--fx-old-z': '-1',
76
+ '--fx-mask': 'var(--mask-hexagon)',
77
+ '--fx-mask-size': '300vmax',
78
+ '--fx-duration': '1s'
79
+ },
80
+ '.square': {
81
+ '--fx-anim': 'fx-mask-grow',
82
+ '--fx-anim-old': 'none',
83
+ '--fx-old-z': '-1',
84
+ '--fx-mask': 'var(--mask-square)',
85
+ '--fx-mask-size': '240vmax',
86
+ '--fx-duration': '0.8s'
87
+ },
88
+ '.soft': {
89
+ '--fx-anim': 'fx-mask-grow',
90
+ '--fx-anim-old': 'none',
91
+ '--fx-old-z': '-1',
92
+ '--fx-mask': 'var(--mask-soft)',
93
+ '--fx-mask-size': '280vmax',
94
+ '--fx-duration': '1.1s'
95
+ },
96
+ '.heart': {
97
+ '--fx-anim': 'fx-mask-grow',
98
+ '--fx-anim-old': 'none',
99
+ '--fx-old-z': '-1',
100
+ '--fx-mask': 'var(--mask-heart)',
101
+ '--fx-mask-size': '280vmax',
102
+ '--fx-duration': '1s'
103
+ },
104
+ '.expand': {
105
+ '--fx-anim': 'fx-expand-in',
106
+ '--fx-anim-old': 'none',
107
+ '--fx-old-z': '-1',
108
+ '--fx-duration': '0.6s'
109
+ },
110
+ '.split': {
111
+ '--fx-anim': 'fx-split-in',
112
+ '--fx-anim-old': 'none',
113
+ '--fx-old-z': '-1',
114
+ '--fx-duration': '0.7s'
115
+ },
116
+ '.shutter': {
117
+ '--fx-anim': 'fx-shutter-in',
118
+ '--fx-anim-old': 'none',
119
+ '--fx-old-z': '-1',
120
+ '--fx-duration': '0.7s'
121
+ },
122
+ '.ink': {
123
+ '--fx-anim': 'fx-mask-grow',
124
+ '--fx-anim-old': 'none',
125
+ '--fx-old-z': '-1',
126
+ '--fx-mask': 'var(--mask-ink)',
127
+ '--fx-mask-size': '250vmax',
128
+ '--fx-duration': '1.2s'
129
+ },
130
+ '.spiral': {
131
+ '--fx-anim': 'fx-spiral',
132
+ '--fx-anim-old': 'none',
133
+ '--fx-old-z': '-1',
134
+ '--fx-mask': 'conic-gradient(from 0deg, #fff 0%, transparent 0%)',
135
+ '--fx-mask-size': '250vmax',
136
+ '--fx-duration': '1.2s'
137
+ },
138
+ '.polygon': {
139
+ '--fx-anim': 'fx-reveal-light',
140
+ '--fx-anim-old': 'none',
141
+ '--fx-old-z': '-1',
142
+ '--fx-duration': '0.7s'
143
+ },
144
+ '.dark.polygon': {
145
+ '--fx-anim': 'fx-reveal-dark'
146
+ },
147
+ '.dark[class*="polygon-duration"]': {
148
+ '--fx-anim': 'fx-reveal-dark'
149
+ },
150
+ '.wipe-h': {
151
+ '--fx-anim': 'fx-wipe-in-h',
152
+ '--fx-anim-old': 'fx-wipe-out-h',
153
+ '--fx-duration': '0.6s'
154
+ },
155
+ '.wipe-left': {
156
+ '--fx-anim': 'fx-wipe-in-left',
157
+ '--fx-anim-old': 'fx-wipe-out-left',
158
+ '--fx-duration': '0.6s'
159
+ },
160
+ '.wipe-v': {
161
+ '--fx-anim': 'fx-wipe-in-down',
162
+ '--fx-anim-old': 'fx-wipe-out-down',
163
+ '--fx-duration': '0.6s'
164
+ },
165
+ '.slide-down': {
166
+ '--fx-anim': 'fx-wipe-in-up',
167
+ '--fx-anim-old': 'fx-wipe-out-up',
168
+ '--fx-duration': '0.6s'
169
+ },
170
+ '.venetian': {
171
+ '--fx-anim': 'fx-wipe-in-up',
172
+ '--fx-anim-old': 'fx-venetian-out',
173
+ '--fx-duration': '0.8s'
174
+ },
175
+ '.glitch': {
176
+ '--fx-anim': 'fx-glitch-in',
177
+ '--fx-anim-old': 'fx-glitch-out',
178
+ '--fx-duration': '0.6s'
179
+ },
180
+ '.slide': {
181
+ '--fx-anim': 'fx-slide-in',
182
+ '--fx-anim-old': 'fx-slide-out',
183
+ '--fx-duration': '0.6s'
184
+ },
185
+ '.lift': {
186
+ '--fx-anim': 'fx-lift-in',
187
+ '--fx-anim-old': 'fx-lift-out',
188
+ '--fx-duration': '0.7s'
189
+ },
190
+ '.zoom': {
191
+ '--fx-anim': 'fx-zoom-in',
192
+ '--fx-anim-old': 'fx-zoom-out',
193
+ '--fx-duration': '0.7s'
194
+ },
195
+ '.rotate': {
196
+ '--fx-anim': 'fx-rotate-in',
197
+ '--fx-anim-old': 'fx-rotate-out',
198
+ '--fx-duration': '0.7s'
199
+ },
200
+ '.fade': {
201
+ '--fx-anim': 'fx-fade-in',
202
+ '--fx-anim-old': 'fx-fade-out',
203
+ '--fx-duration': '0.5s',
204
+ '--fx-ease': 'ease-in-out'
205
+ },
206
+ '.dissolve': {
207
+ '--fx-anim': 'fx-blur-in',
208
+ '--fx-anim-old': 'fx-blur-out',
209
+ '--fx-duration': '0.7s',
210
+ '--fx-ease': 'ease-in-out'
211
+ }
212
+ }
package/src/engine.cjs ADDED
@@ -0,0 +1,136 @@
1
+ const { maskVariables } = require('./masks.cjs')
2
+
3
+ const expoOut = `linear(0 0%,0.1684 2.66%,0.3165 5.49%,0.446 8.52%,0.5581 11.78%,0.6535 15.29%,0.7341 19.11%,0.8011 23.3%,0.8557 27.93%,0.8962 32.68%,0.9283 38.01%,0.9529 44.08%,0.9711 51.14%,0.9833 59.06%,0.9915 68.74%,1 100%)`
4
+ const expoIn = `linear(0 0%,0.0085 31.26%,0.0167 40.94%,0.0289 48.86%,0.0471 55.92%,0.0717 61.99%,0.1038 67.32%,0.1443 72.07%,0.1989 76.7%,0.2659 80.89%,0.3465 84.71%,0.4419 88.22%,0.554 91.48%,0.6835 94.51%,0.8316 97.34%,1 100%)`
5
+
6
+ const duration = 'var(--fx-duration-override, var(--fx-duration, 0.5s))'
7
+ const ease = 'var(--fx-ease-override, var(--fx-ease, var(--expo-out)))'
8
+ const delay = 'var(--fx-delay, 0s)'
9
+
10
+ function engineBase() {
11
+ return {
12
+ ':root': {
13
+ ...maskVariables(),
14
+ '--expo-out': expoOut,
15
+ '--expo-in': expoIn
16
+ },
17
+ ':root::view-transition-group(root)': {
18
+ animationDuration: duration,
19
+ animationTimingFunction: ease,
20
+ animationDelay: delay
21
+ },
22
+ ':root::view-transition-old(root)': {
23
+ animation: `var(--fx-anim-old, fx-fade-out) ${duration} ${ease} ${delay} both`,
24
+ zIndex: 'var(--fx-old-z, auto)',
25
+ mixBlendMode: 'normal'
26
+ },
27
+ ':root::view-transition-new(root)': {
28
+ mask: 'var(--fx-mask, none) var(--fx-mask-position, center) / 0 no-repeat',
29
+ maskOrigin: 'content-box',
30
+ animation: `var(--fx-anim, fx-fade-in) ${duration} ${ease} ${delay} both`,
31
+ mixBlendMode: 'normal'
32
+ },
33
+ '@media (prefers-reduced-motion: reduce)': {
34
+ '::view-transition-group(root), ::view-transition-old(root), ::view-transition-new(root)': {
35
+ animation: 'none !important'
36
+ }
37
+ },
38
+ '@keyframes fx-mask-grow': {
39
+ to: { maskSize: 'var(--fx-mask-size)' }
40
+ },
41
+ '@keyframes fx-spiral': {
42
+ to: {
43
+ maskSize: 'var(--fx-mask-size)',
44
+ maskImage: 'conic-gradient(from 0deg, #fff 0%, #fff 100%)'
45
+ }
46
+ },
47
+ '@keyframes fx-reveal-light': {
48
+ from: { clipPath: 'polygon(171% 50%, 50% 171%, 50% 171%, 171% 50%)' },
49
+ to: { clipPath: 'polygon(171% 50%, 50% 171%, -50% 71%, 50% -71%)' }
50
+ },
51
+ '@keyframes fx-reveal-dark': {
52
+ from: { clipPath: 'polygon(50% -71%, -50% 71%, -50% 71%, 50% -71%)' },
53
+ to: { clipPath: 'polygon(50% -71%, -50% 71%, 50% 171%, 171% 50%)' }
54
+ },
55
+ '@keyframes fx-wipe-in-h': {
56
+ from: { clipPath: 'inset(0 100% 0 0)' },
57
+ to: { clipPath: 'inset(0 0 0 0)' }
58
+ },
59
+ '@keyframes fx-wipe-out-h': {
60
+ from: { clipPath: 'inset(0 0 0 0)' },
61
+ to: { clipPath: 'inset(0 0 0 100%)' }
62
+ },
63
+ '@keyframes fx-wipe-in-down': {
64
+ from: { clipPath: 'inset(100% 0 0 0)' },
65
+ to: { clipPath: 'inset(0 0 0 0)' }
66
+ },
67
+ '@keyframes fx-wipe-out-down': {
68
+ from: { clipPath: 'inset(0 0 0 0)' },
69
+ to: { clipPath: 'inset(0 0 100% 0)' }
70
+ },
71
+ '@keyframes fx-wipe-in-up': {
72
+ from: { clipPath: 'inset(0 0 100% 0)' },
73
+ to: { clipPath: 'inset(0 0 0 0)' }
74
+ },
75
+ '@keyframes fx-wipe-out-up': {
76
+ from: { clipPath: 'inset(0 0 0 0)' },
77
+ to: { clipPath: 'inset(0 0 100% 0)' }
78
+ },
79
+ '@keyframes fx-venetian-out': {
80
+ from: { clipPath: 'inset(0 0 0 0)' },
81
+ to: { clipPath: 'inset(100% 0 0 0)' }
82
+ },
83
+ '@keyframes fx-expand-in': {
84
+ from: { clipPath: 'inset(50%)' },
85
+ to: { clipPath: 'inset(0)' }
86
+ },
87
+ '@keyframes fx-glitch-in': {
88
+ '0%': { clipPath: 'inset(0 0 100% 0)', opacity: '0' },
89
+ '20%': { clipPath: 'inset(40% 0 0 0)', opacity: '1' },
90
+ '40%': { clipPath: 'inset(0 0 60% 0)' },
91
+ '60%': { clipPath: 'inset(20% 0 20% 0)' },
92
+ '100%': { clipPath: 'inset(0 0 0 0)' }
93
+ },
94
+ '@keyframes fx-glitch-out': {
95
+ '0%': { clipPath: 'inset(0 0 0 0)', opacity: '1' },
96
+ '20%': { clipPath: 'inset(0 0 40% 0)' },
97
+ '40%': { clipPath: 'inset(60% 0 0 0)' },
98
+ '60%': { clipPath: 'inset(20% 0 20% 0)', opacity: '0.5' },
99
+ '100%': { clipPath: 'inset(0 0 100% 0)', opacity: '0' }
100
+ },
101
+ '@keyframes fx-slide-in': {
102
+ from: { transform: 'translateX(100%)' },
103
+ to: { transform: 'translateX(0)' }
104
+ },
105
+ '@keyframes fx-slide-out': {
106
+ from: { transform: 'translateX(0)', opacity: '1' },
107
+ to: { transform: 'translateX(-50%)', opacity: '0.3' }
108
+ },
109
+ '@keyframes fx-zoom-in': {
110
+ from: { opacity: '0', transform: 'scale(0.85)' },
111
+ to: { opacity: '1', transform: 'scale(1)' }
112
+ },
113
+ '@keyframes fx-zoom-out': {
114
+ from: { opacity: '1', transform: 'scale(1)' },
115
+ to: { opacity: '0', transform: 'scale(1.15)' }
116
+ },
117
+ '@keyframes fx-rotate-in': {
118
+ from: { opacity: '0', transform: 'rotate(-6deg) scale(0.9)' },
119
+ to: { opacity: '1', transform: 'rotate(0) scale(1)' }
120
+ },
121
+ '@keyframes fx-rotate-out': {
122
+ from: { opacity: '1', transform: 'rotate(0) scale(1)' },
123
+ to: { opacity: '0', transform: 'rotate(6deg) scale(0.9)' }
124
+ },
125
+ '@keyframes fx-fade-in': {
126
+ from: { opacity: '0' },
127
+ to: { opacity: '1' }
128
+ },
129
+ '@keyframes fx-fade-out': {
130
+ from: { opacity: '1' },
131
+ to: { opacity: '0' }
132
+ }
133
+ }
134
+ }
135
+
136
+ module.exports = { engineBase }