@tsogtoodev/shingen-metal 1.0.0
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 +21 -0
- package/README.md +164 -0
- package/dist/index.cjs.js +421 -0
- package/dist/index.d.ts +321 -0
- package/dist/index.es.js +1605 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jakub Antalik
|
|
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.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# shingen-metal
|
|
2
|
+
|
|
3
|
+
Animated WebGL "liquid metal" effect for Vue 3 — a port of [metal-fx](https://github.com/Jakubantalik/metal-fx) (React) by Jakub Antalik. Wrap a button, chip, or icon and it gets a real-time metal ring with optional proximity reflection on neighbouring elements.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install shingen-metal
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<script setup>
|
|
15
|
+
import { MetalFx } from 'shingen-metal';
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<MetalFx variant="button">
|
|
20
|
+
<button class="upgrade-pill">Upgrade to Pro</button>
|
|
21
|
+
</MetalFx>
|
|
22
|
+
</template>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The component wraps a single slotted host element, measures it, and paints an animated metal ring on top. The child stays fully interactive — overlays sit above it with `pointer-events: none`.
|
|
26
|
+
|
|
27
|
+
## Variants
|
|
28
|
+
|
|
29
|
+
```vue
|
|
30
|
+
<MetalFx variant="button"> <!-- Pill silhouette, 1 px ring, scale 1.6 -->
|
|
31
|
+
<button>Upgrade to Pro</button>
|
|
32
|
+
</MetalFx>
|
|
33
|
+
|
|
34
|
+
<MetalFx variant="circle"> <!-- Compact circle, 2 px ring, scale 1.3 -->
|
|
35
|
+
<button>↑</button>
|
|
36
|
+
</MetalFx>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Presets
|
|
40
|
+
|
|
41
|
+
Three bundled palettes, each with a tuned dark and light mode block:
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<MetalFx preset="chromatic" /> <!-- Iridescent rainbow (default) -->
|
|
45
|
+
<MetalFx preset="silver" /> <!-- Cool steel -->
|
|
46
|
+
<MetalFx preset="gold" /> <!-- Warm gold -->
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Theme
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<MetalFx theme="auto" /> <!-- Follows prefers-color-scheme (default) -->
|
|
53
|
+
<MetalFx theme="dark" /> <!-- Pin to dark backgrounds -->
|
|
54
|
+
<MetalFx theme="light" /> <!-- Pin to light backgrounds -->
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`auto` reads the OS / browser theme on mount and subscribes to live changes via `matchMedia('(prefers-color-scheme: dark)')`, so the metal frame switches over instantly when the user toggles their system theme. SSR-safe — the initial render falls back to `dark` and rehydrates to the resolved theme on the client.
|
|
58
|
+
|
|
59
|
+
If your app has its own theme toggle that doesn't follow the OS, drive `theme` from your app state instead:
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<MetalFx :theme="appTheme">...</MetalFx>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Strength
|
|
66
|
+
|
|
67
|
+
```vue
|
|
68
|
+
<MetalFx :strength="0.7"> <!-- 70% effect intensity -->
|
|
69
|
+
<button>Upgrade to Pro</button>
|
|
70
|
+
</MetalFx>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`strength` runs from `0` (invisible) to `1` (full, default). It scales the canvas and glow opacity without changing the underlying shader animation.
|
|
74
|
+
|
|
75
|
+
## Paused
|
|
76
|
+
|
|
77
|
+
```vue
|
|
78
|
+
<MetalFx paused>
|
|
79
|
+
<button>Upgrade to Pro</button>
|
|
80
|
+
</MetalFx>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Freezes the shader on its current frame. The metal silhouette stays visible.
|
|
84
|
+
|
|
85
|
+
## Proximity reflection (dark mode only)
|
|
86
|
+
|
|
87
|
+
Pass template refs to neighbouring elements and they receive a soft, mirrored reflection of the metal ring:
|
|
88
|
+
|
|
89
|
+
```vue
|
|
90
|
+
<script setup>
|
|
91
|
+
import { ref } from 'vue';
|
|
92
|
+
import { MetalFx } from 'shingen-metal';
|
|
93
|
+
|
|
94
|
+
const chipRef = ref(null);
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<template>
|
|
98
|
+
<button ref="chipRef">Tools</button>
|
|
99
|
+
<MetalFx variant="circle" :reflection-targets="[chipRef]">
|
|
100
|
+
<button aria-label="Send">↑</button>
|
|
101
|
+
</MetalFx>
|
|
102
|
+
</template>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Reflections are skipped automatically when the resolved theme is `light` — no DOM scanning, no per-frame work in light mode.
|
|
106
|
+
|
|
107
|
+
## Performance
|
|
108
|
+
|
|
109
|
+
- One shared WebGL context is reused across every mounted `<MetalFx>` on the page. The shader is compiled once.
|
|
110
|
+
- A single `requestAnimationFrame` loop drives every instance. Per-frame work for one mount: a `gl.drawArrays` plus N×`drawImage` copies (one per visible instance).
|
|
111
|
+
- `IntersectionObserver` pauses per-instance copies when the host scrolls offscreen. When every instance is offscreen the GL render is skipped too.
|
|
112
|
+
- `ResizeObserver` callbacks are debounced through RAF.
|
|
113
|
+
- The GL context, program, and buffer are released when the last `<MetalFx>` unmounts.
|
|
114
|
+
|
|
115
|
+
## Server-side rendering
|
|
116
|
+
|
|
117
|
+
The component renders a transparent placeholder during SSR and only mounts the WebGL pipeline after hydration on the client. No flash of broken effect, no SSR errors.
|
|
118
|
+
|
|
119
|
+
## Sizing
|
|
120
|
+
|
|
121
|
+
`MetalFx` does not force any dimensions onto the wrapped child — the wrapper sizes itself to whatever the child renders. Style your child the way you normally would (intrinsic content, CSS class, or inline style):
|
|
122
|
+
|
|
123
|
+
```vue
|
|
124
|
+
<!-- Pattern 1 (recommended): size the child. -->
|
|
125
|
+
<MetalFx variant="circle">
|
|
126
|
+
<button style="width: 36px; height: 36px" aria-label="Send">↑</button>
|
|
127
|
+
</MetalFx>
|
|
128
|
+
|
|
129
|
+
<MetalFx>
|
|
130
|
+
<button class="rounded-full px-6 h-10">Upgrade to Pro</button>
|
|
131
|
+
</MetalFx>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
If you want a metal frame larger than the child (e.g. padding around an icon), size the wrapper instead and explicitly stretch the child to fill:
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<!-- Pattern 2: size the wrapper, child fills. -->
|
|
138
|
+
<MetalFx style="width: 36px; height: 36px" variant="circle">
|
|
139
|
+
<button style="width: 100%; height: 100%" aria-label="Send">↑</button>
|
|
140
|
+
</MetalFx>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Both patterns work; pick whichever fits your layout. The wrapper is `display: inline-flex` so it lays out inline like a button.
|
|
144
|
+
|
|
145
|
+
## Custom border radius
|
|
146
|
+
|
|
147
|
+
By default `MetalFx` reads the computed `border-radius` of the wrapped child each resize. Pass an explicit override when needed:
|
|
148
|
+
|
|
149
|
+
```vue
|
|
150
|
+
<MetalFx :border-radius="20">
|
|
151
|
+
<button>Upgrade to Pro</button>
|
|
152
|
+
</MetalFx>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Demo
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npm install
|
|
159
|
+
npm run dev
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT — port of [metal-fx](https://github.com/Jakubantalik/metal-fx) © [Jakub Antalik](https://github.com/Jakubantalik). See [LICENSE](./LICENSE).
|