@linear_non/stellar-libs 1.0.7 → 1.0.8
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/README.md +12 -12
- package/package.json +2 -2
- package/src/SpritePlayer/index.js +152 -0
- package/src/Sticky/index.js +1 -1
- package/src/index.js +2 -1
package/README.md
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# stellar-libs
|
|
2
2
|
|
|
3
|
-
A collection of lightweight, reusable frontend UI behavior modules — built to work seamlessly with [`stellar-kit`](https://www.npmjs.com/package/@linear_non/stellar-kit) and the [Stellar](https://github.com/nonlinearstudio/stellar) frontend system. Each library is self-contained, configurable, and designed to be dropped into modular websites.
|
|
3
|
+
A collection of lightweight, reusable frontend UI behavior modules — built to work seamlessly with [`stellar-kit`](https://www.npmjs.com/package/@linear_non/stellar-kit) and the [Stellar](https://github.com/nonlinearstudio/stellar) frontend system. Each library is self-contained, configurable, and designed to be dropped into modular websites. Also is a project that is constantly growing and we are adding new updates all the time.
|
|
4
4
|
|
|
5
|
-
## ✨
|
|
5
|
+
## ✨ Avalible Libs
|
|
6
6
|
|
|
7
|
+
- Designed for plug-and-play
|
|
7
8
|
- **Sticky**: Basic sticky logic for DOM elements
|
|
8
|
-
- **SplitOnScroll**: Text splitting + reveal synced to scroll
|
|
9
9
|
- **Smooth**: Smooth scroll instance using Virtual Scroll
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- **SplitOnScroll**: Text splitting + reveal synced to scroll
|
|
11
|
+
- **Noise**: Configurable canvas noise
|
|
12
|
+
- **SpritePlayer**: Canvas image sequence player
|
|
12
13
|
|
|
13
14
|
## 📦 Installation
|
|
14
15
|
|
|
@@ -16,7 +17,7 @@ A collection of lightweight, reusable frontend UI behavior modules — built to
|
|
|
16
17
|
npm install @linear_non/stellar-libs
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
> Note:
|
|
20
|
+
> Note: Most libraries rely on `stellar-kit` for shared events, scroll, or utilities. Be sure to install both:
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
npm install @linear_non/stellar-kit
|
|
@@ -31,6 +32,8 @@ stellar-libs/
|
|
|
31
32
|
│ ├── SplitOnScroll/ # Scroll-triggered text reveals
|
|
32
33
|
│ ├── Smooth/ # Smooth scrolling system
|
|
33
34
|
│ └── ScrollBar/ # Custom scrollbar component
|
|
35
|
+
│ └── Noise/ # Canvas noise
|
|
36
|
+
│ └── SpritePlayer/ # Image sprite player
|
|
34
37
|
├── dev/ # Dev playgrounds for each lib
|
|
35
38
|
├── index.js # Entry point for exports
|
|
36
39
|
└── vite.config.js # Vite config to run individual demos
|
|
@@ -48,12 +51,12 @@ npm run dev
|
|
|
48
51
|
## 🛠️ Usage Example
|
|
49
52
|
|
|
50
53
|
```js
|
|
51
|
-
import { Sticky } from "@linear_non/stellar-libs"
|
|
54
|
+
import { Sticky } from "@linear_non/stellar-libs"
|
|
52
55
|
|
|
53
56
|
const sticky = new Sticky({
|
|
54
57
|
el: qs(".sticky"),
|
|
55
58
|
sticky: qs(".sticky-content"),
|
|
56
|
-
})
|
|
59
|
+
})
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
> You can find usage examples in each library’s README file also an HTML markup example. You can see a live example inside the `dev/` folder.
|
|
@@ -62,10 +65,7 @@ const sticky = new Sticky({
|
|
|
62
65
|
|
|
63
66
|
### ✅ TODO
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
- [ ] Implement `Dropdown` module
|
|
67
|
-
- [ ] Implement `Lenis` scroll
|
|
68
|
-
- [ ] Update Readme files for each component
|
|
68
|
+
This is a projects that will continue growing and we have plan to add as many things that we feel can be helpful for us in the future.
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linear_non/stellar-libs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Reusable JavaScript libraries for Non-Linear Studio projects.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"author": "Non-Linear Studio",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@linear_non/stellar-kit": "^1.1.
|
|
28
|
+
"@linear_non/stellar-kit": "^1.1.7"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@linear_non/prettier-config": "^1.0.6",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// SpritePlayer.js
|
|
2
|
+
import { ImageLoader } from "@linear_non/stellar-kit/classes"
|
|
3
|
+
import { emitter, EVENTS } from "@linear_non/stellar-kit/events"
|
|
4
|
+
import { sniffer, bounds } from "@linear_non/stellar-kit/utils"
|
|
5
|
+
import { gsap } from "@linear_non/stellar-kit/gsap"
|
|
6
|
+
|
|
7
|
+
export default class SpritePlayer {
|
|
8
|
+
constructor({
|
|
9
|
+
canvas,
|
|
10
|
+
container,
|
|
11
|
+
mobile_path,
|
|
12
|
+
desktop_path,
|
|
13
|
+
fileName,
|
|
14
|
+
total = 0,
|
|
15
|
+
progress = 0,
|
|
16
|
+
fileExtension = "png",
|
|
17
|
+
cache = null, // optional Map for global cache
|
|
18
|
+
persistent = false, // true if using shared cache (don’t revoke)
|
|
19
|
+
}) {
|
|
20
|
+
const rect = bounds(container)
|
|
21
|
+
this.progress = progress
|
|
22
|
+
this.persistent = persistent
|
|
23
|
+
|
|
24
|
+
this.dom = { container, reference: container, images: [] }
|
|
25
|
+
this.canvas = {
|
|
26
|
+
el: canvas,
|
|
27
|
+
ctx: canvas.getContext("2d"),
|
|
28
|
+
width: rect.width,
|
|
29
|
+
height: rect.height,
|
|
30
|
+
rect,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.settings = {
|
|
34
|
+
mobile_path,
|
|
35
|
+
desktop_path,
|
|
36
|
+
file_name: fileName,
|
|
37
|
+
total,
|
|
38
|
+
file_extension: fileExtension,
|
|
39
|
+
cache,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.state = { loaded: false }
|
|
43
|
+
this.isVisible = true
|
|
44
|
+
this.init()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async loadImages() {
|
|
48
|
+
const { mobile_path, desktop_path, total, file_name, file_extension, cache } = this.settings
|
|
49
|
+
const origin = sniffer.isDesktop ? desktop_path : mobile_path
|
|
50
|
+
|
|
51
|
+
const loader = new ImageLoader({
|
|
52
|
+
origin,
|
|
53
|
+
fileName: file_name,
|
|
54
|
+
extension: file_extension,
|
|
55
|
+
total,
|
|
56
|
+
cache, // pass cache Map if you have one
|
|
57
|
+
useWorker: true,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// (optional) forward progress
|
|
61
|
+
const onProgress = e => emitter.emit("sprite:progress", { instance: this, ...e })
|
|
62
|
+
emitter.on(ImageLoader.events.PROGRESS, onProgress)
|
|
63
|
+
|
|
64
|
+
const images = await loader.load() // ✅ get images from promise
|
|
65
|
+
|
|
66
|
+
emitter.off?.(ImageLoader.events.PROGRESS, onProgress)
|
|
67
|
+
|
|
68
|
+
this.dom.images = images
|
|
69
|
+
this.frameCount = images.length
|
|
70
|
+
this.state.loaded = true
|
|
71
|
+
emitter.emit("sprite:loaded", this)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
configureCanvas() {
|
|
75
|
+
const { container, reference } = this.dom
|
|
76
|
+
const rect = bounds(container)
|
|
77
|
+
const area = bounds(reference)
|
|
78
|
+
const offset = area.top - rect.top
|
|
79
|
+
const dpr = window.devicePixelRatio || 1
|
|
80
|
+
|
|
81
|
+
const { el, ctx } = this.canvas
|
|
82
|
+
el.style.width = `${rect.width}px`
|
|
83
|
+
el.style.height = `${rect.height}px`
|
|
84
|
+
el.width = Math.floor(rect.width * dpr)
|
|
85
|
+
el.height = Math.floor(rect.height * dpr)
|
|
86
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0)
|
|
87
|
+
ctx.scale(dpr, dpr)
|
|
88
|
+
|
|
89
|
+
Object.assign(this.canvas, { width: rect.width, height: rect.height, rect, area, offset })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
drawImageCover(ctx, img, area, offset) {
|
|
93
|
+
const iw = img.naturalWidth,
|
|
94
|
+
ih = img.naturalHeight
|
|
95
|
+
const cw = area.width,
|
|
96
|
+
ch = area.height
|
|
97
|
+
const ir = iw / ih,
|
|
98
|
+
cr = cw / ch
|
|
99
|
+
let sw, sh, sx, sy
|
|
100
|
+
if (ir > cr) {
|
|
101
|
+
sh = ih
|
|
102
|
+
sw = ih * cr
|
|
103
|
+
sx = (iw - sw) / 2
|
|
104
|
+
sy = 0
|
|
105
|
+
} else {
|
|
106
|
+
sw = iw
|
|
107
|
+
sh = iw / cr
|
|
108
|
+
sx = 0
|
|
109
|
+
sy = (ih - sh) / 2
|
|
110
|
+
}
|
|
111
|
+
ctx.drawImage(img, sx, sy, sw, sh, 0, offset, cw, ch)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
tick = ({ current }) => {
|
|
115
|
+
if (!this.state.loaded || !this.isVisible) return
|
|
116
|
+
this.scroll = current
|
|
117
|
+
|
|
118
|
+
const { ctx, width, height, area, offset } = this.canvas
|
|
119
|
+
const { images } = this.dom
|
|
120
|
+
const total = this.frameCount || images.length || 1
|
|
121
|
+
const val = gsap.utils.clamp(0, total - 1, this.progress * total)
|
|
122
|
+
const index = Math.floor(val)
|
|
123
|
+
const img = images[index]
|
|
124
|
+
|
|
125
|
+
ctx.clearRect(0, 0, width, height)
|
|
126
|
+
if (img) this.drawImageCover(ctx, img, area, offset)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
resize = () => this.configureCanvas()
|
|
130
|
+
|
|
131
|
+
on() {
|
|
132
|
+
emitter.on(EVENTS.APP_TICK, this.tick)
|
|
133
|
+
emitter.on(EVENTS.APP_RESIZE, this.resize)
|
|
134
|
+
}
|
|
135
|
+
off() {
|
|
136
|
+
emitter.off(EVENTS.APP_TICK, this.tick)
|
|
137
|
+
emitter.off(EVENTS.APP_RESIZE, this.resize)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
destroy() {
|
|
141
|
+
this.off()
|
|
142
|
+
// Only revoke if not using shared cache
|
|
143
|
+
if (!this.persistent) this.dom.images.forEach(img => URL.revokeObjectURL(img?.src))
|
|
144
|
+
this.dom.images = []
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async init() {
|
|
148
|
+
await this.loadImages()
|
|
149
|
+
this.configureCanvas()
|
|
150
|
+
this.on()
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/Sticky/index.js
CHANGED
|
@@ -38,7 +38,7 @@ export default class Sticky {
|
|
|
38
38
|
scrub: true,
|
|
39
39
|
onEnter: () => this.toggleSticky(true),
|
|
40
40
|
onEnterBack: () => this.toggleSticky(true),
|
|
41
|
-
onLeave: () => this.toggleSticky(false, true),
|
|
41
|
+
onLeave: () => this.toggleSticky(false, true),
|
|
42
42
|
onLeaveBack: () => this.toggleSticky(false),
|
|
43
43
|
onUpdate: self => this.onUpdate(self),
|
|
44
44
|
})
|
package/src/index.js
CHANGED
|
@@ -2,5 +2,6 @@ import Sticky from "./Sticky"
|
|
|
2
2
|
import Smooth from "./Smooth"
|
|
3
3
|
import SplitonScroll from "./SplitOnScroll"
|
|
4
4
|
import Noise from "./Noise"
|
|
5
|
+
import SpritePlayer from "./SpritePlayer"
|
|
5
6
|
|
|
6
|
-
export { Sticky, Smooth, SplitonScroll, Noise }
|
|
7
|
+
export { Sticky, Smooth, SplitonScroll, Noise, SpritePlayer }
|