XENXOS / assets /js /boot.js
JSWAI's picture
Create assets/js/boot.js
8e65c9b verified
Raw History Blame Contribute Delete
6.37 kB
/**
* ============================================================
* XENEX GLASS OS
* Boot Controller
* ============================================================
*
* Responsibilities:
* - Control boot animation timing
* - Update boot status
* - Respect reduced-motion preferences
* - Transition cleanly to the login application
*
* This module does NOT:
* - authenticate users
* - contain passwords
* - contain API secrets
* - access Neon
* - access S3
* - make privileged backend decisions
*
* Backend authority begins when the login module is loaded.
*/
"use strict";
/* ============================================================
CONFIGURATION
============================================================ */
const BOOT_CONFIG = Object.freeze({
/*
* Short enough to feel responsive, but long enough for
* the visual identity to register.
*/
minimumDuration: 3000,
/*
* Small transition period after the Xenex wordmark appears.
*/
transitionDuration: 900,
/*
* Destination module.
*
* This file will be created next.
*/
loginModule: "./login.html"
});
/* ============================================================
BOOT STATE
============================================================ */
const BootState = Object.freeze({
STARTING: "starting",
READY: "ready",
TRANSITIONING: "transitioning",
COMPLETE: "complete"
});
let currentState = BootState.STARTING;
/* ============================================================
DOM REFERENCES
============================================================ */
const bootRoot =
document.getElementById("xenex-boot");
const bootStatus =
document.getElementById("boot-status");
const transitionLayer =
document.getElementById("boot-transition");
/* ============================================================
VALIDATION
============================================================ */
function validateBootDOM() {
if (!bootRoot) {
throw new Error(
"Xenex Boot: boot root was not found."
);
}
if (!bootStatus) {
throw new Error(
"Xenex Boot: status element was not found."
);
}
if (!transitionLayer) {
throw new Error(
"Xenex Boot: transition layer was not found."
);
}
}
/* ============================================================
STATUS
============================================================ */
function setBootStatus(message) {
if (!bootStatus) {
return;
}
bootStatus.textContent = message;
}
/* ============================================================
STATE
============================================================ */
function setState(nextState) {
currentState = nextState;
}
/* ============================================================
REDUCED MOTION
============================================================ */
function prefersReducedMotion() {
return window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
}
/* ============================================================
TRANSITION
============================================================ */
function beginTransition() {
if (currentState !== BootState.STARTING) {
return;
}
setState(BootState.TRANSITIONING);
setBootStatus(
"Preparing your workspace"
);
transitionLayer.classList.add(
"is-active"
);
/*
* Allow the transition layer to cover the boot screen
* before navigating to the login document.
*/
window.setTimeout(() => {
setState(BootState.COMPLETE);
window.location.replace(
BOOT_CONFIG.loginModule
);
}, BOOT_CONFIG.transitionDuration);
}
/* ============================================================
NORMAL BOOT
============================================================ */
function startNormalBoot() {
const startedAt = performance.now();
setBootStatus(
"Starting Xenex Glass OS"
);
/*
* We intentionally don't use a fixed "fake loading"
* percentage.
*
* This is simply the visual boot stage.
*
* Later, real frontend initialization can register
* readiness tasks here.
*/
window.setTimeout(() => {
const elapsed =
performance.now() - startedAt;
const remaining =
Math.max(
0,
BOOT_CONFIG.minimumDuration - elapsed
);
window.setTimeout(() => {
setBootStatus(
"Xenex Glass OS ready"
);
beginTransition();
}, remaining);
}, 100);
}
/* ============================================================
ACCESSIBILITY BOOT
============================================================ */
function startReducedMotionBoot() {
setBootStatus(
"Xenex Glass OS ready"
);
/*
* No unnecessary animation delay for users who have
* requested reduced motion.
*/
window.setTimeout(
beginTransition,
500
);
}
/* ============================================================
INITIALIZATION
============================================================ */
function initializeBoot() {
try {
validateBootDOM();
setState(BootState.STARTING);
if (prefersReducedMotion()) {
startReducedMotionBoot();
} else {
startNormalBoot();
}
} catch (error) {
/*
* Do not silently fail.
*
* This remains a frontend boot error and does not
* expose any backend information.
*/
console.error(
"Xenex Glass OS boot error:",
error
);
setBootStatus(
"Unable to start Xenex OS"
);
}
}
/* ============================================================
START
============================================================ */
if (
document.readyState === "loading"
) {
document.addEventListener(
"DOMContentLoaded",
initializeBoot,
{
once: true
}
);
} else {
initializeBoot();
}