@linear_non/stellar-kit 3.0.5 → 3.0.6
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/core/PageEngine.js +117 -39
- package/events/Raf.js +176 -6
- package/kitStore.js +6 -0
- package/package.json +2 -1
- package/plugins/Observer.js +2 -0
- package/styles/helpers/_ +0 -0
package/core/PageEngine.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Manager } from "../classes/index.js"
|
|
|
2
2
|
import { emitter, EVENTS } from "../events/index.js"
|
|
3
3
|
import { Debug, qsa } from "../utils/index.js"
|
|
4
4
|
import { kitStore } from "../kitStore.js"
|
|
5
|
+
import { ScrollTrigger } from "../libraries/gsap/index.js"
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @typedef {Object} EngineOwner
|
|
@@ -23,9 +24,16 @@ import { kitStore } from "../kitStore.js"
|
|
|
23
24
|
/**
|
|
24
25
|
* @typedef {Object} EngineSetupConfig
|
|
25
26
|
* @property {Array<any>} components - Array of component constructors/definitions.
|
|
26
|
-
* @property {
|
|
27
|
+
* @property {Object} [lenis] - Lenis instance. If provided, uses Lenis mode.
|
|
28
|
+
* @property {HTMLElement} [wrapper] - Scroll wrapper element (required if lenis is provided).
|
|
29
|
+
* @property {any} [smooth] - Legacy: Smooth instance for internal scroll mode.
|
|
27
30
|
*/
|
|
28
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Unified page engine that handles both internal scroll and Lenis modes.
|
|
34
|
+
* - Pass `lenis` + `wrapper` in setup() → Lenis mode (auto-configures ticker + ScrollTrigger)
|
|
35
|
+
* - Don't pass lenis → Internal scroll mode (uses APP_TICK from Raf.js)
|
|
36
|
+
*/
|
|
29
37
|
export default class PageEngine {
|
|
30
38
|
/**
|
|
31
39
|
* @param {{ owner: EngineOwner }} param0
|
|
@@ -52,11 +60,23 @@ export default class PageEngine {
|
|
|
52
60
|
this.manager = null
|
|
53
61
|
|
|
54
62
|
/**
|
|
55
|
-
* Smooth instance
|
|
63
|
+
* Smooth/Lenis instance
|
|
56
64
|
* @type {any | null}
|
|
57
65
|
*/
|
|
58
66
|
this.smooth = null
|
|
59
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Lenis instance (if using Lenis mode)
|
|
70
|
+
* @type {any | null}
|
|
71
|
+
*/
|
|
72
|
+
this.lenis = null
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Wrapper element for ScrollTrigger proxy
|
|
76
|
+
* @type {HTMLElement | null}
|
|
77
|
+
*/
|
|
78
|
+
this.wrapper = null
|
|
79
|
+
|
|
60
80
|
/**
|
|
61
81
|
* @type {EngineScrollState}
|
|
62
82
|
*/
|
|
@@ -81,16 +101,23 @@ export default class PageEngine {
|
|
|
81
101
|
}
|
|
82
102
|
|
|
83
103
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
104
|
+
* Setup the engine with components and optional scroll instance.
|
|
105
|
+
* Auto-detects Lenis mode if `lenis` is provided.
|
|
86
106
|
*
|
|
87
107
|
* @param {EngineSetupConfig} param0
|
|
88
108
|
*/
|
|
89
|
-
setup({ components, smooth }) {
|
|
90
|
-
Debug.log("ENGINE", "Setup", { components, smooth })
|
|
109
|
+
setup({ components, lenis, wrapper, smooth }) {
|
|
110
|
+
Debug.log("ENGINE", "Setup", { components, lenis, wrapper, smooth })
|
|
91
111
|
|
|
92
112
|
this.components = components || []
|
|
93
|
-
|
|
113
|
+
|
|
114
|
+
if (lenis && wrapper) {
|
|
115
|
+
// Lenis mode: auto-configure ticker and ScrollTrigger
|
|
116
|
+
this._setupLenis(lenis, wrapper)
|
|
117
|
+
} else if (smooth) {
|
|
118
|
+
// Legacy: smooth instance passed directly
|
|
119
|
+
this.smooth = smooth
|
|
120
|
+
}
|
|
94
121
|
|
|
95
122
|
this.manager = new Manager()
|
|
96
123
|
|
|
@@ -108,6 +135,54 @@ export default class PageEngine {
|
|
|
108
135
|
this.resize()
|
|
109
136
|
}
|
|
110
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Setup Lenis: register with global Raf and configure ScrollTrigger.
|
|
140
|
+
* Raf.js handles the lenis.raf() call on each tick.
|
|
141
|
+
* @param {Object} lenis - Lenis instance
|
|
142
|
+
* @param {HTMLElement} wrapper - Scroll wrapper element
|
|
143
|
+
* @private
|
|
144
|
+
*/
|
|
145
|
+
_setupLenis(lenis, wrapper) {
|
|
146
|
+
Debug.log("ENGINE", "Setting up Lenis mode")
|
|
147
|
+
|
|
148
|
+
this.lenis = lenis
|
|
149
|
+
this.wrapper = wrapper
|
|
150
|
+
this.smooth = lenis
|
|
151
|
+
|
|
152
|
+
// Store scroller globally so components can access it
|
|
153
|
+
kitStore.scroller = wrapper
|
|
154
|
+
|
|
155
|
+
// Register Lenis with global Raf - it will call lenis.raf() on each tick
|
|
156
|
+
if (kitStore.raf) {
|
|
157
|
+
kitStore.raf.setLenis(lenis)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Wire Lenis scroll events to ScrollTrigger
|
|
161
|
+
this.lenis.on("scroll", ScrollTrigger.update)
|
|
162
|
+
|
|
163
|
+
// Setup ScrollTrigger scroller proxy
|
|
164
|
+
ScrollTrigger.scrollerProxy(wrapper, {
|
|
165
|
+
scrollTop: (value) => {
|
|
166
|
+
if (value !== undefined) {
|
|
167
|
+
this.lenis.scrollTo(value, { immediate: true })
|
|
168
|
+
}
|
|
169
|
+
return this.lenis.scroll
|
|
170
|
+
},
|
|
171
|
+
getBoundingClientRect: () => ({
|
|
172
|
+
top: 0,
|
|
173
|
+
left: 0,
|
|
174
|
+
width: window.innerWidth,
|
|
175
|
+
height: window.innerHeight,
|
|
176
|
+
}),
|
|
177
|
+
pinType: wrapper.style.transform ? "transform" : "fixed",
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Set default scroller for all ScrollTrigger instances
|
|
181
|
+
ScrollTrigger.defaults({ scroller: wrapper })
|
|
182
|
+
|
|
183
|
+
Debug.log("ENGINE", "Lenis setup complete", { wrapper, scrollerSet: true })
|
|
184
|
+
}
|
|
185
|
+
|
|
111
186
|
/**
|
|
112
187
|
* Adds `.loaded` class to images when loaded.
|
|
113
188
|
* Looks for `.lazy` images.
|
|
@@ -134,42 +209,22 @@ export default class PageEngine {
|
|
|
134
209
|
|
|
135
210
|
/**
|
|
136
211
|
* Receives data from global Raf (APP_TICK).
|
|
137
|
-
*
|
|
138
|
-
* In external mode (Lenis), calls smooth.raf() and derives scroll.
|
|
212
|
+
* Raf already handles Lenis.raf() call and provides correct scroll values.
|
|
139
213
|
*
|
|
140
214
|
* @param {{ current: number, diff: number, mouse: EngineMouseState }} param0
|
|
141
215
|
*/
|
|
142
216
|
tick = ({ current, diff, mouse }) => {
|
|
143
|
-
const { isResizing, isLocked
|
|
217
|
+
const { isResizing, isLocked } = kitStore.flags
|
|
144
218
|
|
|
145
219
|
if (isResizing || isLocked) return
|
|
146
220
|
if (!this.manager) return
|
|
147
221
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (useExternalScroll && this.smooth?.raf) {
|
|
152
|
-
const t = performance.now()
|
|
153
|
-
this.smooth.raf(t)
|
|
154
|
-
|
|
155
|
-
if (typeof this.smooth.scroll === "number") {
|
|
156
|
-
nextScroll = this.smooth.scroll
|
|
157
|
-
} else if (typeof this.smooth.targetScroll === "number") {
|
|
158
|
-
nextScroll = this.smooth.targetScroll
|
|
159
|
-
} else {
|
|
160
|
-
nextScroll = window.scrollY || window.pageYOffset || 0
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
delta = nextScroll - this.scroll.current
|
|
164
|
-
}
|
|
222
|
+
this.scroll.current = current
|
|
223
|
+
this.scroll.direction = diff > 0 ? "down" : "up"
|
|
165
224
|
|
|
166
|
-
this.scroll.current = nextScroll
|
|
167
|
-
this.scroll.direction = delta > 0 ? "down" : "up"
|
|
168
|
-
|
|
169
225
|
this.mouse.x = mouse.x
|
|
170
226
|
this.mouse.y = mouse.y
|
|
171
|
-
|
|
172
|
-
// Debug.log("ENGINE", "Tick scroll:", this.scroll)
|
|
227
|
+
|
|
173
228
|
this.manager.tick?.({
|
|
174
229
|
mouse: this.mouse,
|
|
175
230
|
scroll: this.scroll,
|
|
@@ -178,15 +233,15 @@ export default class PageEngine {
|
|
|
178
233
|
|
|
179
234
|
/**
|
|
180
235
|
* Called during APP_RESIZE.
|
|
181
|
-
* Updates Smooth then calls Manager.resize().
|
|
236
|
+
* Updates Smooth/Lenis then calls Manager.resize().
|
|
182
237
|
*/
|
|
183
238
|
resize = () => {
|
|
184
239
|
Debug.log("ENGINE", "Resize")
|
|
185
240
|
|
|
241
|
+
// Lenis
|
|
242
|
+
this.lenis?.resize?.()
|
|
186
243
|
// Internal Smooth
|
|
187
244
|
this.smooth?.update?.()
|
|
188
|
-
// Lenis
|
|
189
|
-
this.smooth?.resize?.()
|
|
190
245
|
|
|
191
246
|
this.manager?.resize?.()
|
|
192
247
|
}
|
|
@@ -229,6 +284,25 @@ export default class PageEngine {
|
|
|
229
284
|
this.destroy()
|
|
230
285
|
}
|
|
231
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Cleanup Lenis if in Lenis mode.
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
_destroyLenis() {
|
|
292
|
+
// Unregister Lenis from global Raf
|
|
293
|
+
if (kitStore.raf) {
|
|
294
|
+
kitStore.raf.setLenis(null)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (this.lenis) {
|
|
298
|
+
this.lenis.destroy()
|
|
299
|
+
this.lenis = null
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
this.wrapper = null
|
|
303
|
+
kitStore.scroller = null
|
|
304
|
+
}
|
|
305
|
+
|
|
232
306
|
/**
|
|
233
307
|
* Cleanup Smooth + Manager.
|
|
234
308
|
* Called by Page.onLeaveCompleted().
|
|
@@ -237,9 +311,13 @@ export default class PageEngine {
|
|
|
237
311
|
this.manager?.destroy?.()
|
|
238
312
|
this.manager = null
|
|
239
313
|
|
|
240
|
-
if
|
|
241
|
-
|
|
242
|
-
|
|
314
|
+
// Cleanup Lenis if in Lenis mode
|
|
315
|
+
this._destroyLenis()
|
|
316
|
+
|
|
317
|
+
// Cleanup internal smooth
|
|
318
|
+
if (this.smooth?.destroy) {
|
|
319
|
+
this.smooth.destroy()
|
|
243
320
|
}
|
|
321
|
+
this.smooth = null
|
|
244
322
|
}
|
|
245
|
-
}
|
|
323
|
+
}
|
package/events/Raf.js
CHANGED
|
@@ -3,8 +3,54 @@ import emitter, { EVENTS } from "./Emitter"
|
|
|
3
3
|
import { Debug, lerp } from "../utils"
|
|
4
4
|
import { gsap, ScrollTrigger } from "../libraries/gsap"
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} RafScrollState
|
|
8
|
+
* @property {number} target - Target scroll position (used in internal scroll mode).
|
|
9
|
+
* @property {number} current - Current interpolated scroll position.
|
|
10
|
+
* @property {number} rounded - Rounded scroll position for rendering.
|
|
11
|
+
* @property {number} ease - Lerp easing factor for smooth interpolation.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} RafMouseState
|
|
16
|
+
* @property {number} x - Current mouse X position.
|
|
17
|
+
* @property {number} y - Current mouse Y position.
|
|
18
|
+
* @property {EventTarget|null} target - Current mouse event target element.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Object} RafTickPayload
|
|
23
|
+
* @property {number} target - Target scroll position.
|
|
24
|
+
* @property {number} current - Current scroll position.
|
|
25
|
+
* @property {RafMouseState} mouse - Current mouse state.
|
|
26
|
+
* @property {number} diff - Scroll delta/difference.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Global RAF (Request Animation Frame) manager.
|
|
31
|
+
*
|
|
32
|
+
* Handles the main animation loop and scroll state for the application.
|
|
33
|
+
* Supports two scroll modes:
|
|
34
|
+
*
|
|
35
|
+
* **Internal Scroll Mode** (`useExternalScroll: false`):
|
|
36
|
+
* - Receives scroll delta from VirtualScroll via APP_SCROLL events
|
|
37
|
+
* - Interpolates scroll position using lerp for smooth scrolling
|
|
38
|
+
* - Sets up ScrollTrigger scroller proxy on pageContent
|
|
39
|
+
*
|
|
40
|
+
* **Lenis Mode** (`useExternalScroll: true`):
|
|
41
|
+
* - Lenis instance is registered via `setLenis()`
|
|
42
|
+
* - Calls `lenis.raf()` on each tick
|
|
43
|
+
* - Reads scroll position directly from Lenis
|
|
44
|
+
* - PageEngine handles ScrollTrigger proxy setup
|
|
45
|
+
*
|
|
46
|
+
* Emits `APP_TICK` event on each frame with scroll and mouse data.
|
|
47
|
+
*/
|
|
6
48
|
export default class Raf {
|
|
7
49
|
constructor() {
|
|
50
|
+
/**
|
|
51
|
+
* Scroll state for internal scroll mode.
|
|
52
|
+
* @type {RafScrollState}
|
|
53
|
+
*/
|
|
8
54
|
this.scroll = {
|
|
9
55
|
target: 0,
|
|
10
56
|
current: 0,
|
|
@@ -12,14 +58,28 @@ export default class Raf {
|
|
|
12
58
|
ease: 0.115,
|
|
13
59
|
}
|
|
14
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Current mouse position state.
|
|
63
|
+
* @type {RafMouseState}
|
|
64
|
+
*/
|
|
15
65
|
this.mouse = {
|
|
16
66
|
x: 0,
|
|
17
67
|
y: 0,
|
|
18
68
|
target: null,
|
|
19
69
|
}
|
|
20
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Scroll delta between frames.
|
|
73
|
+
* @type {number}
|
|
74
|
+
*/
|
|
21
75
|
this.diff = 0
|
|
22
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Lenis instance when using external scroll mode.
|
|
79
|
+
* @type {Object|null}
|
|
80
|
+
*/
|
|
81
|
+
this.lenis = null
|
|
82
|
+
|
|
23
83
|
this.tick = this.tick.bind(this)
|
|
24
84
|
this.onScroll = this.onScroll.bind(this)
|
|
25
85
|
this.onMouseMove = this.onMouseMove.bind(this)
|
|
@@ -29,10 +89,29 @@ export default class Raf {
|
|
|
29
89
|
this.onPageShow = this.resume.bind(this)
|
|
30
90
|
}
|
|
31
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Register Lenis instance for external scroll mode.
|
|
94
|
+
* When set, tick() will call lenis.raf() and read scroll position from Lenis.
|
|
95
|
+
* @param {Object|null} lenis - Lenis instance, or null to unregister.
|
|
96
|
+
*/
|
|
97
|
+
setLenis(lenis) {
|
|
98
|
+
this.lenis = lenis
|
|
99
|
+
if (lenis) {
|
|
100
|
+
gsap.ticker.lagSmoothing(0)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Initialize the RAF system.
|
|
106
|
+
* Sets up ScrollTrigger scroller proxy for internal scroll mode.
|
|
107
|
+
*/
|
|
32
108
|
init() {
|
|
33
109
|
this.setScrollTrigger()
|
|
34
110
|
}
|
|
35
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Activate all event listeners and start the animation loop.
|
|
114
|
+
*/
|
|
36
115
|
on() {
|
|
37
116
|
gsap.ticker.add(this.tick)
|
|
38
117
|
|
|
@@ -44,6 +123,9 @@ export default class Raf {
|
|
|
44
123
|
window.addEventListener("pageshow", this.onPageShow)
|
|
45
124
|
}
|
|
46
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Deactivate all event listeners and stop the animation loop.
|
|
128
|
+
*/
|
|
47
129
|
off() {
|
|
48
130
|
gsap.ticker.remove(this.tick)
|
|
49
131
|
|
|
@@ -55,10 +137,18 @@ export default class Raf {
|
|
|
55
137
|
window.removeEventListener("pageshow", this.onPageShow)
|
|
56
138
|
}
|
|
57
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Cleanup and destroy the RAF system.
|
|
142
|
+
*/
|
|
58
143
|
destroy() {
|
|
59
144
|
this.off()
|
|
60
145
|
}
|
|
61
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Handle smooth resize events.
|
|
149
|
+
* Clamps scroll values to valid range and updates ScrollTrigger.
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
62
152
|
onAppResize() {
|
|
63
153
|
const { fh } = kitStore.sizes
|
|
64
154
|
|
|
@@ -69,17 +159,39 @@ export default class Raf {
|
|
|
69
159
|
ScrollTrigger.update()
|
|
70
160
|
}
|
|
71
161
|
|
|
72
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Main animation loop tick.
|
|
164
|
+
* Called on each frame via GSAP ticker.
|
|
165
|
+
*
|
|
166
|
+
* - In Lenis mode: calls lenis.raf() and reads scroll from Lenis
|
|
167
|
+
* - In internal mode: interpolates scroll using lerp
|
|
168
|
+
*
|
|
169
|
+
* Emits APP_TICK event with current scroll and mouse state.
|
|
170
|
+
*
|
|
171
|
+
* @param {number} time - Current time from GSAP ticker (in seconds).
|
|
172
|
+
*/
|
|
173
|
+
tick(time) {
|
|
73
174
|
if (kitStore.flags.isResizing) return
|
|
74
175
|
|
|
75
|
-
|
|
176
|
+
// Lenis mode: update Lenis first, then read scroll from it
|
|
177
|
+
if (this.lenis) {
|
|
178
|
+
this.lenis.raf(time * 1000)
|
|
179
|
+
|
|
180
|
+
const lenisScroll = this.lenis.scroll ?? 0
|
|
181
|
+
this.diff = lenisScroll - this.scroll.current
|
|
182
|
+
this.scroll.current = lenisScroll
|
|
183
|
+
this.scroll.rounded = lenisScroll
|
|
184
|
+
} else {
|
|
185
|
+
// Internal scroll mode
|
|
186
|
+
const { target, current, ease } = this.scroll
|
|
76
187
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
188
|
+
this.scroll.current = lerp(current, target, ease)
|
|
189
|
+
this.scroll.rounded = Math.round(this.scroll.current * 100) / 100
|
|
190
|
+
this.diff = (target - this.scroll.current) * 0.005
|
|
191
|
+
}
|
|
80
192
|
|
|
81
193
|
emitter.emit(EVENTS.APP_TICK, {
|
|
82
|
-
target,
|
|
194
|
+
target: this.lenis ? this.scroll.current : this.scroll.target,
|
|
83
195
|
current: this.getScroll(),
|
|
84
196
|
mouse: this.mouse,
|
|
85
197
|
diff: this.diff,
|
|
@@ -88,29 +200,61 @@ export default class Raf {
|
|
|
88
200
|
ScrollTrigger.update()
|
|
89
201
|
}
|
|
90
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Get the current scroll position.
|
|
205
|
+
* - In Lenis mode: returns the rounded Lenis scroll value.
|
|
206
|
+
* - In internal smooth mode: returns the interpolated scroll value.
|
|
207
|
+
* - In native mode: returns the container's scrollTop.
|
|
208
|
+
* @returns {number} Current scroll position.
|
|
209
|
+
*/
|
|
91
210
|
getScroll() {
|
|
211
|
+
// Lenis mode: return Lenis scroll position
|
|
212
|
+
if (this.lenis) {
|
|
213
|
+
return this.scroll.rounded
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Internal mode
|
|
92
217
|
const { pageContent, flags } = kitStore
|
|
93
218
|
const container = pageContent ? pageContent.parentNode : document.body
|
|
94
219
|
return flags.isSmooth ? this.scroll.rounded : container.scrollTop
|
|
95
220
|
}
|
|
96
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Clamp scroll target to valid range (0 to full height).
|
|
224
|
+
* @private
|
|
225
|
+
*/
|
|
97
226
|
clamp() {
|
|
98
227
|
const { fh } = kitStore.sizes
|
|
99
228
|
this.scroll.target = Math.min(Math.max(this.scroll.target, 0), fh)
|
|
100
229
|
}
|
|
101
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Handle scroll events from VirtualScroll (internal scroll mode).
|
|
233
|
+
* Adds delta to target and clamps to valid range.
|
|
234
|
+
* @param {{ y: number }} param0 - Scroll delta.
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
102
237
|
onScroll({ y }) {
|
|
103
238
|
if (kitStore.flags.isLocked) return
|
|
104
239
|
this.scroll.target += y
|
|
105
240
|
this.clamp()
|
|
106
241
|
}
|
|
107
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Handle mouse move events.
|
|
245
|
+
* @param {{ x: number, y: number, target: EventTarget }} param0 - Mouse position and target.
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
108
248
|
onMouseMove({ x, y, target }) {
|
|
109
249
|
this.mouse.x = x
|
|
110
250
|
this.mouse.y = y
|
|
111
251
|
this.mouse.target = target
|
|
112
252
|
}
|
|
113
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Smoothly scroll to a target offset.
|
|
256
|
+
* @param {number} offset - Target scroll position in pixels.
|
|
257
|
+
*/
|
|
114
258
|
scrollTo(offset) {
|
|
115
259
|
if (kitStore.flags.isSmooth) {
|
|
116
260
|
gsap.to(this.scroll, {
|
|
@@ -123,6 +267,10 @@ export default class Raf {
|
|
|
123
267
|
}
|
|
124
268
|
}
|
|
125
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Immediately set scroll position (no animation).
|
|
272
|
+
* @param {number} offset - Target scroll position in pixels.
|
|
273
|
+
*/
|
|
126
274
|
setScroll(offset) {
|
|
127
275
|
if (kitStore.flags.isSmooth) {
|
|
128
276
|
gsap.set(this.scroll, {
|
|
@@ -135,10 +283,25 @@ export default class Raf {
|
|
|
135
283
|
}
|
|
136
284
|
}
|
|
137
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Configure ScrollTrigger for internal scroll mode.
|
|
288
|
+
* Sets up scroller proxy and defaults.
|
|
289
|
+
* Skipped when useExternalScroll is true (PageEngine handles it).
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
138
292
|
setScrollTrigger() {
|
|
293
|
+
// Skip if useExternalScroll flag is set - PageEngine will handle ScrollTrigger setup
|
|
294
|
+
if (kitStore.flags.useExternalScroll) {
|
|
295
|
+
Debug.log("RAF", "Skipping ScrollTrigger setup (external scroll mode)")
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
139
299
|
const { pageContent } = kitStore
|
|
140
300
|
const scroller = pageContent || document.body
|
|
141
301
|
|
|
302
|
+
// Store scroller globally so components can access it
|
|
303
|
+
kitStore.scroller = scroller
|
|
304
|
+
|
|
142
305
|
Debug.log(
|
|
143
306
|
"RAF",
|
|
144
307
|
"Setting ScrollTrigger scroller to:",
|
|
@@ -159,10 +322,17 @@ export default class Raf {
|
|
|
159
322
|
})
|
|
160
323
|
}
|
|
161
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Pause the animation loop (e.g., when page is hidden).
|
|
327
|
+
*/
|
|
162
328
|
stop() {
|
|
163
329
|
gsap.ticker.remove(this.tick)
|
|
164
330
|
}
|
|
165
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Resume the animation loop (e.g., when page becomes visible).
|
|
334
|
+
* Syncs current scroll to target to prevent jumps.
|
|
335
|
+
*/
|
|
166
336
|
resume() {
|
|
167
337
|
this.scroll.current = this.scroll.target
|
|
168
338
|
this.scroll.rounded = this.scroll.target
|
package/kitStore.js
CHANGED
|
@@ -42,4 +42,10 @@ export const kitStore = {
|
|
|
42
42
|
flags,
|
|
43
43
|
pageContent: null,
|
|
44
44
|
assets,
|
|
45
|
+
/**
|
|
46
|
+
* Scroll scroller element (wrapper for Lenis, pageContent for internal scroll).
|
|
47
|
+
* Used by ScrollTrigger components to get the correct scroller.
|
|
48
|
+
* @type {HTMLElement | null}
|
|
49
|
+
*/
|
|
50
|
+
scroller: null,
|
|
45
51
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linear_non/stellar-kit",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
4
4
|
"description": "Stellar frontend core for Non-Linear Studio projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "/core/index.js",
|
|
7
7
|
"sass": "./styles/index.scss",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./kitStore.js",
|
|
10
|
+
"./kitStore": "./kitStore.js",
|
|
10
11
|
"./utils": "./utils/index.js",
|
|
11
12
|
"./core": "./core/index.js",
|
|
12
13
|
"./classes": "./classes/index.js",
|
package/plugins/Observer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Emitter } from "../events"
|
|
2
2
|
import { ScrollTrigger } from "../libraries/gsap"
|
|
3
|
+
import { kitStore } from "../kitStore"
|
|
3
4
|
|
|
4
5
|
const DEFAULTS = {
|
|
5
6
|
trigger: null,
|
|
@@ -33,6 +34,7 @@ export default class Observer extends Emitter {
|
|
|
33
34
|
scrub,
|
|
34
35
|
once,
|
|
35
36
|
markers,
|
|
37
|
+
scroller: kitStore.scroller || undefined,
|
|
36
38
|
onEnter: forward("enter"),
|
|
37
39
|
onLeave: forward("leave"),
|
|
38
40
|
onEnterBack: forward("enterBack"),
|
package/styles/helpers/_
DELETED
|
File without changes
|