Deploy from Lumerel
This commit is contained in:
176
main.js
Normal file
176
main.js
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Lumerel — 3D Homepage
|
||||
* main.js
|
||||
*
|
||||
* Handles:
|
||||
* - Spline 3D scene loading & pointer-events toggle
|
||||
* - Navbar scroll behaviour (frosted glass on scroll)
|
||||
* - Video autoplay fallback (iOS / autoplay-blocked browsers)
|
||||
* - Waitlist button click handlers
|
||||
* - Global helpers exposed on window.Lumerel
|
||||
*/
|
||||
|
||||
/* ── Spline Integration ────────────────────────────────────────────────
|
||||
*
|
||||
* WHEN YOUR SPLINE SCENE IS READY:
|
||||
*
|
||||
* Option A — HTML (simplest):
|
||||
* Open index.html, find #spline-layer, delete .spline-placeholder,
|
||||
* and paste in:
|
||||
*
|
||||
* <spline-viewer
|
||||
* url="https://prod.spline.design/YOUR_SCENE_ID/scene.splinecode"
|
||||
* events-target="global"
|
||||
* ></spline-viewer>
|
||||
*
|
||||
* Option B — JavaScript:
|
||||
* Call window.Lumerel.loadSplineScene('https://prod.spline.design/…');
|
||||
* This removes the placeholder and injects <spline-viewer> for you.
|
||||
*
|
||||
* Option C — @splinetool/runtime (advanced):
|
||||
* import { Application } from '@splinetool/runtime';
|
||||
* const app = new Application(canvas);
|
||||
* app.load('https://prod.spline.design/YOUR_SCENE_ID/scene.splinecode');
|
||||
*
|
||||
* For interactive scenes (mouse/touch on the 3D layer), call:
|
||||
* window.Lumerel.enableSpline()
|
||||
*
|
||||
* ──────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
const splineLayer = document.getElementById('spline-layer');
|
||||
|
||||
/**
|
||||
* Enable pointer events on the 3D layer so Spline scenes
|
||||
* can receive mouse/touch input.
|
||||
* Call this AFTER your Spline scene has loaded.
|
||||
*/
|
||||
function enableSpline() {
|
||||
if (splineLayer) {
|
||||
splineLayer.style.pointerEvents = 'auto';
|
||||
console.log('[Lumerel] Spline pointer events ENABLED.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable pointer events on the 3D layer (default state).
|
||||
* Ensures all UI elements (buttons, links) remain fully clickable.
|
||||
*/
|
||||
function disableSpline() {
|
||||
if (splineLayer) {
|
||||
splineLayer.style.pointerEvents = 'none';
|
||||
console.log('[Lumerel] Spline pointer events DISABLED.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Programmatically load a Spline scene by URL.
|
||||
* Removes the placeholder orbs and injects a <spline-viewer>.
|
||||
* @param {string} sceneUrl - The Spline scene URL (.splinecode)
|
||||
* @param {boolean} [enableInteraction=false] - Auto-enable pointer events
|
||||
*/
|
||||
function loadSplineScene(sceneUrl, enableInteraction = false) {
|
||||
if (!splineLayer) return;
|
||||
|
||||
// Remove placeholder
|
||||
const placeholder = splineLayer.querySelector('.spline-placeholder');
|
||||
if (placeholder) placeholder.remove();
|
||||
|
||||
// Inject spline-viewer
|
||||
const viewer = document.createElement('spline-viewer');
|
||||
viewer.setAttribute('url', sceneUrl);
|
||||
viewer.setAttribute('events-target', 'global');
|
||||
viewer.style.width = '100%';
|
||||
viewer.style.height = '100%';
|
||||
viewer.style.display = 'block';
|
||||
|
||||
viewer.addEventListener('load', () => {
|
||||
console.log('[Lumerel] Spline scene loaded:', sceneUrl);
|
||||
if (enableInteraction) enableSpline();
|
||||
});
|
||||
|
||||
splineLayer.appendChild(viewer);
|
||||
console.log('[Lumerel] Spline scene injected:', sceneUrl);
|
||||
}
|
||||
|
||||
// Listen for spline-viewer ready event if already in HTML
|
||||
if (splineLayer) {
|
||||
const existingViewer = splineLayer.querySelector('spline-viewer');
|
||||
if (existingViewer) {
|
||||
existingViewer.addEventListener('load', () => {
|
||||
console.log('[Lumerel] Spline scene loaded.');
|
||||
// Uncomment to auto-enable 3D interactivity:
|
||||
// enableSpline();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Navbar Scroll Effect ──────────────────────────────────────────────
|
||||
Adds a frosted-glass background when the user scrolls past 24px.
|
||||
──────────────────────────────────────────────────────────────────────── */
|
||||
const navbar = document.getElementById('navbar');
|
||||
|
||||
function handleNavbarScroll() {
|
||||
if (!navbar) return;
|
||||
if (window.scrollY > 24) {
|
||||
navbar.style.background = 'rgba(0, 0, 0, 0.45)';
|
||||
navbar.style.backdropFilter = 'blur(16px)';
|
||||
navbar.style.webkitBackdropFilter = 'blur(16px)';
|
||||
} else {
|
||||
navbar.style.background = 'transparent';
|
||||
navbar.style.backdropFilter = 'none';
|
||||
navbar.style.webkitBackdropFilter = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handleNavbarScroll, { passive: true });
|
||||
handleNavbarScroll(); // run once on load
|
||||
|
||||
/* ── Video Autoplay Fallback ───────────────────────────────────────────
|
||||
Some browsers / iOS block autoplay. This attempts a manual play
|
||||
on the first user interaction as a fallback.
|
||||
──────────────────────────────────────────────────────────────────────── */
|
||||
const heroVideo = document.querySelector('.hero__video');
|
||||
|
||||
if (heroVideo) {
|
||||
heroVideo.play().catch(() => {
|
||||
// Autoplay blocked — wait for first interaction
|
||||
const resumeVideo = () => {
|
||||
heroVideo.play().catch(() => {});
|
||||
document.removeEventListener('pointerdown', resumeVideo);
|
||||
document.removeEventListener('keydown', resumeVideo);
|
||||
};
|
||||
document.addEventListener('pointerdown', resumeVideo, { once: true });
|
||||
document.addEventListener('keydown', resumeVideo, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
/* ── Waitlist Button Handlers ─────────────────────────────────────────
|
||||
Replace the console.log with your modal, form, or redirect logic.
|
||||
──────────────────────────────────────────────────────────────────────── */
|
||||
const navbarWaitlistBtn = document.getElementById('navbar-waitlist-btn');
|
||||
const heroWaitlistBtn = document.getElementById('hero-waitlist-btn');
|
||||
|
||||
function handleWaitlistClick(source) {
|
||||
console.log('[Lumerel] Join Waitlist clicked —', source);
|
||||
// TODO: open modal, redirect to /waitlist, or trigger form
|
||||
// Example: window.location.href = '/waitlist';
|
||||
}
|
||||
|
||||
if (navbarWaitlistBtn) {
|
||||
navbarWaitlistBtn.addEventListener('click', () => handleWaitlistClick('navbar'));
|
||||
}
|
||||
|
||||
if (heroWaitlistBtn) {
|
||||
heroWaitlistBtn.addEventListener('click', () => handleWaitlistClick('hero-cta'));
|
||||
}
|
||||
|
||||
/* ── Global API ────────────────────────────────────────────────────────
|
||||
Expose helpers on window.Lumerel for easy console/runtime access.
|
||||
──────────────────────────────────────────────────────────────────────── */
|
||||
window.Lumerel = {
|
||||
loadSplineScene,
|
||||
enableSpline,
|
||||
disableSpline,
|
||||
};
|
||||
|
||||
console.log('[Lumerel] Ready. Use window.Lumerel.loadSplineScene(url) to add a 3D scene.');
|
||||
Reference in New Issue
Block a user