@linear_non/stellar-libs 1.0.8 → 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
@@ -2,7 +2,7 @@
2
2
 
3
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
- ## ✨ Avalible Libs
5
+ ## ✨ Available Libs
6
6
 
7
7
  - Designed for plug-and-play
8
8
  - **Sticky**: Basic sticky logic for DOM elements
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linear_non/stellar-libs",
3
- "version": "1.0.8",
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",
@@ -14,14 +14,20 @@ export default class SpritePlayer {
14
14
  total = 0,
15
15
  progress = 0,
16
16
  fileExtension = "png",
17
- cache = null, // optional Map for global cache
18
- persistent = false, // true if using shared cache (don’t revoke)
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,
19
23
  }) {
20
24
  const rect = bounds(container)
21
- this.progress = progress
25
+
26
+ this.progress = gsap.utils.clamp(0, 1, progress)
22
27
  this.persistent = persistent
28
+ this.isAlpha = !!useAlpha
23
29
 
24
- this.dom = { container, reference: container, images: [] }
30
+ this.dom = { container, reference: container, images: [], alphaImages: [] }
25
31
  this.canvas = {
26
32
  el: canvas,
27
33
  ctx: canvas.getContext("2d"),
@@ -37,6 +43,8 @@ export default class SpritePlayer {
37
43
  total,
38
44
  file_extension: fileExtension,
39
45
  cache,
46
+ alpha_path,
47
+ fileAlpha,
40
48
  }
41
49
 
42
50
  this.state = { loaded: false }
@@ -45,27 +53,34 @@ export default class SpritePlayer {
45
53
  }
46
54
 
47
55
  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
- })
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()
59
71
 
60
- // (optional) forward progress
61
72
  const onProgress = e => emitter.emit("sprite:progress", { instance: this, ...e })
62
73
  emitter.on(ImageLoader.events.PROGRESS, onProgress)
63
74
 
64
- const images = await loader.load() // ✅ get images from promise
75
+ const [images, alphaImages] = await Promise.all([
76
+ make(originBase, file_name),
77
+ originAlpha && fileAlpha ? make(originAlpha, fileAlpha) : Promise.resolve([]),
78
+ ])
65
79
 
66
80
  emitter.off?.(ImageLoader.events.PROGRESS, onProgress)
67
81
 
68
82
  this.dom.images = images
83
+ this.dom.alphaImages = alphaImages
69
84
  this.frameCount = images.length
70
85
  this.state.loaded = true
71
86
  emitter.emit("sprite:loaded", this)
@@ -116,14 +131,22 @@ export default class SpritePlayer {
116
131
  this.scroll = current
117
132
 
118
133
  const { ctx, width, height, area, offset } = this.canvas
119
- const { images } = this.dom
134
+ const { images, alphaImages } = this.dom
120
135
  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]
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
124
139
 
125
140
  ctx.clearRect(0, 0, width, height)
126
- if (img) this.drawImageCover(ctx, img, area, offset)
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
+ }
127
150
  }
128
151
 
129
152
  resize = () => this.configureCanvas()
@@ -137,11 +160,32 @@ export default class SpritePlayer {
137
160
  emitter.off(EVENTS.APP_RESIZE, this.resize)
138
161
  }
139
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
+
140
180
  destroy() {
141
181
  this.off()
142
- // Only revoke if not using shared cache
143
- if (!this.persistent) this.dom.images.forEach(img => URL.revokeObjectURL(img?.src))
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
+ }
144
187
  this.dom.images = []
188
+ this.dom.alphaImages = []
145
189
  }
146
190
 
147
191
  async init() {