@linear_non/stellar-libs 1.0.7 → 1.0.9

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 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
- ## ✨ Features
5
+ ## ✨ Available 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
- - Designed for plug-and-play usage inside Stellar Template
11
- - Works with `kitStore`, `Resize`, `Scroll`, `Raf`, and GSAP if needed
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: Some libraries rely on `stellar-kit` for shared events, scroll, or utilities. Be sure to install both if needed:
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
- - [ ] Implement `Marquee` module
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.7",
3
+ "version": "1.0.9",
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.0"
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,196 @@
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,
18
+ persistent = false,
19
+ // alpha options
20
+ alpha_path = null, // { mobile: "...", desktop: "..." }
21
+ fileAlpha = null, // e.g. "sprite_mask_"
22
+ useAlpha = false,
23
+ }) {
24
+ const rect = bounds(container)
25
+
26
+ this.progress = gsap.utils.clamp(0, 1, progress)
27
+ this.persistent = persistent
28
+ this.isAlpha = !!useAlpha
29
+
30
+ this.dom = { container, reference: container, images: [], alphaImages: [] }
31
+ this.canvas = {
32
+ el: canvas,
33
+ ctx: canvas.getContext("2d"),
34
+ width: rect.width,
35
+ height: rect.height,
36
+ rect,
37
+ }
38
+
39
+ this.settings = {
40
+ mobile_path,
41
+ desktop_path,
42
+ file_name: fileName,
43
+ total,
44
+ file_extension: fileExtension,
45
+ cache,
46
+ alpha_path,
47
+ fileAlpha,
48
+ }
49
+
50
+ this.state = { loaded: false }
51
+ this.isVisible = true
52
+ this.init()
53
+ }
54
+
55
+ async loadImages() {
56
+ const { mobile_path, desktop_path, alpha_path, file_name, fileAlpha, total, file_extension, cache } =
57
+ this.settings
58
+
59
+ const originBase = sniffer.isDesktop ? desktop_path : mobile_path
60
+ const originAlpha = alpha_path ? (sniffer.isDesktop ? alpha_path.desktop : alpha_path.mobile) : null
61
+
62
+ const make = (origin, name) =>
63
+ new ImageLoader({
64
+ origin,
65
+ fileName: name,
66
+ extension: file_extension,
67
+ total,
68
+ cache,
69
+ useWorker: true,
70
+ }).load()
71
+
72
+ const onProgress = e => emitter.emit("sprite:progress", { instance: this, ...e })
73
+ emitter.on(ImageLoader.events.PROGRESS, onProgress)
74
+
75
+ const [images, alphaImages] = await Promise.all([
76
+ make(originBase, file_name),
77
+ originAlpha && fileAlpha ? make(originAlpha, fileAlpha) : Promise.resolve([]),
78
+ ])
79
+
80
+ emitter.off?.(ImageLoader.events.PROGRESS, onProgress)
81
+
82
+ this.dom.images = images
83
+ this.dom.alphaImages = alphaImages
84
+ this.frameCount = images.length
85
+ this.state.loaded = true
86
+ emitter.emit("sprite:loaded", this)
87
+ }
88
+
89
+ configureCanvas() {
90
+ const { container, reference } = this.dom
91
+ const rect = bounds(container)
92
+ const area = bounds(reference)
93
+ const offset = area.top - rect.top
94
+ const dpr = window.devicePixelRatio || 1
95
+
96
+ const { el, ctx } = this.canvas
97
+ el.style.width = `${rect.width}px`
98
+ el.style.height = `${rect.height}px`
99
+ el.width = Math.floor(rect.width * dpr)
100
+ el.height = Math.floor(rect.height * dpr)
101
+ ctx.setTransform(1, 0, 0, 1, 0, 0)
102
+ ctx.scale(dpr, dpr)
103
+
104
+ Object.assign(this.canvas, { width: rect.width, height: rect.height, rect, area, offset })
105
+ }
106
+
107
+ drawImageCover(ctx, img, area, offset) {
108
+ const iw = img.naturalWidth,
109
+ ih = img.naturalHeight
110
+ const cw = area.width,
111
+ ch = area.height
112
+ const ir = iw / ih,
113
+ cr = cw / ch
114
+ let sw, sh, sx, sy
115
+ if (ir > cr) {
116
+ sh = ih
117
+ sw = ih * cr
118
+ sx = (iw - sw) / 2
119
+ sy = 0
120
+ } else {
121
+ sw = iw
122
+ sh = iw / cr
123
+ sx = 0
124
+ sy = (ih - sh) / 2
125
+ }
126
+ ctx.drawImage(img, sx, sy, sw, sh, 0, offset, cw, ch)
127
+ }
128
+
129
+ tick = ({ current }) => {
130
+ if (!this.state.loaded || !this.isVisible) return
131
+ this.scroll = current
132
+
133
+ const { ctx, width, height, area, offset } = this.canvas
134
+ const { images, alphaImages } = this.dom
135
+ const total = this.frameCount || images.length || 1
136
+ const index = Math.min(total - 1, Math.round(this.progress * (total - 1)))
137
+ const base = images[index]
138
+ const mask = this.isAlpha ? alphaImages[index] : null
139
+
140
+ ctx.clearRect(0, 0, width, height)
141
+ if (!base) return
142
+
143
+ this.drawImageCover(ctx, base, area, offset)
144
+
145
+ if (mask) {
146
+ ctx.globalCompositeOperation = "destination-in"
147
+ this.drawImageCover(ctx, mask, area, offset)
148
+ ctx.globalCompositeOperation = "source-over"
149
+ }
150
+ }
151
+
152
+ resize = () => this.configureCanvas()
153
+
154
+ on() {
155
+ emitter.on(EVENTS.APP_TICK, this.tick)
156
+ emitter.on(EVENTS.APP_RESIZE, this.resize)
157
+ }
158
+ off() {
159
+ emitter.off(EVENTS.APP_TICK, this.tick)
160
+ emitter.off(EVENTS.APP_RESIZE, this.resize)
161
+ }
162
+
163
+ setProgress(p) {
164
+ this.progress = gsap.utils.clamp(0, 1, p)
165
+ }
166
+
167
+ show() {
168
+ this.isVisible = true
169
+ }
170
+ hide() {
171
+ this.isVisible = false
172
+ const { ctx, width, height } = this.canvas
173
+ ctx.clearRect(0, 0, width, height)
174
+ }
175
+
176
+ enableAlpha(v = true) {
177
+ this.isAlpha = !!v
178
+ }
179
+
180
+ destroy() {
181
+ this.off()
182
+ if (!this.persistent) {
183
+ const revoke = img => img?.src?.startsWith("blob:") && URL.revokeObjectURL(img.src)
184
+ this.dom.images.forEach(revoke)
185
+ this.dom.alphaImages.forEach(revoke)
186
+ }
187
+ this.dom.images = []
188
+ this.dom.alphaImages = []
189
+ }
190
+
191
+ async init() {
192
+ await this.loadImages()
193
+ this.configureCanvas()
194
+ this.on()
195
+ }
196
+ }
@@ -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), // ✅ Ensure totalHeight is passed
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 }