192 lines
6.8 KiB
HTML
192 lines
6.8 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta
|
|
name="description"
|
|
content="HyperTwist is a native cube and hypercube training environment for recognition, replay, coaching, higher-dimensional runtime ownership, and desktop-first operator workflows."
|
|
/>
|
|
<meta property="og:site_name" content="HyperTwist" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:title" content="HyperTwist" />
|
|
<meta
|
|
property="og:description"
|
|
content="HyperTwist is a native cube and hypercube training environment for recognition, replay, coaching, higher-dimensional runtime ownership, and desktop-first operator workflows."
|
|
/>
|
|
<meta property="og:url" content="https://hypertwist.app/" />
|
|
<meta property="og:image" content="https://hypertwist.app/branding/hypertwist-3d-symbol.png" />
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content="HyperTwist" />
|
|
<meta
|
|
name="twitter:description"
|
|
content="HyperTwist is a native cube and hypercube training environment for recognition, replay, coaching, higher-dimensional runtime ownership, and desktop-first operator workflows."
|
|
/>
|
|
<meta name="twitter:image" content="https://hypertwist.app/branding/hypertwist-3d-symbol.png" />
|
|
<meta name="theme-color" content="#0b1020" />
|
|
<meta name="hypertwist-site-shell" content="first-party-website-v1" />
|
|
<link rel="canonical" href="https://hypertwist.app/" />
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;700&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<style>
|
|
:root {
|
|
color-scheme: dark;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
background:
|
|
radial-gradient(circle at top, rgba(84, 203, 255, 0.16), transparent 40%),
|
|
linear-gradient(180deg, #0b1020, #050814 68%);
|
|
color: #f4f6f8;
|
|
font-family: "IBM Plex Sans", system-ui, sans-serif;
|
|
}
|
|
|
|
.hypertwist-initial-shell {
|
|
min-height: 100vh;
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 2rem;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.hypertwist-initial-shell__frame {
|
|
width: min(30rem, 100%);
|
|
border: 1px solid rgba(84, 203, 255, 0.22);
|
|
border-radius: 1.75rem;
|
|
background: rgba(9, 14, 28, 0.9);
|
|
box-shadow: 0 30px 90px rgba(0, 0, 0, 0.4);
|
|
padding: 2rem 1.5rem;
|
|
display: grid;
|
|
justify-items: center;
|
|
gap: 0.9rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.hypertwist-initial-shell__brand {
|
|
width: 4.5rem;
|
|
height: 4.5rem;
|
|
object-fit: contain;
|
|
filter: drop-shadow(0 0 22px rgba(84, 203, 255, 0.25));
|
|
}
|
|
|
|
.hypertwist-initial-shell__eyebrow {
|
|
margin: 0;
|
|
color: #54cbff;
|
|
font-size: 0.82rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.16em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.hypertwist-initial-shell__spinner {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
border-radius: 999px;
|
|
border: 3px solid rgba(84, 203, 255, 0.18);
|
|
border-top-color: #54cbff;
|
|
border-right-color: #f7b267;
|
|
animation: hypertwist-initial-shell-spin 0.9s linear infinite;
|
|
}
|
|
|
|
.hypertwist-initial-shell__title {
|
|
margin: 0;
|
|
font-family: "Space Grotesk", "IBM Plex Sans", system-ui, sans-serif;
|
|
font-size: clamp(1.55rem, 3vw, 2rem);
|
|
font-weight: 700;
|
|
letter-spacing: -0.03em;
|
|
}
|
|
|
|
.hypertwist-initial-shell__body {
|
|
margin: 0;
|
|
max-width: 24rem;
|
|
color: rgba(212, 225, 245, 0.86);
|
|
font-size: 0.97rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
@keyframes hypertwist-initial-shell-spin {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|
|
<title>HyperTwist</title>
|
|
</head>
|
|
<body>
|
|
<div id="root">
|
|
<div class="hypertwist-initial-shell" role="status" aria-live="polite" aria-label="Loading HyperTwist">
|
|
<div class="hypertwist-initial-shell__frame">
|
|
<img
|
|
src="/branding/hypertwist-3d-symbol.png"
|
|
alt="HyperTwist"
|
|
class="hypertwist-initial-shell__brand"
|
|
/>
|
|
<p class="hypertwist-initial-shell__eyebrow">Booting HyperTwist</p>
|
|
<div class="hypertwist-initial-shell__spinner" aria-hidden="true"></div>
|
|
<p class="hypertwist-initial-shell__title">Loading HyperTwist...</p>
|
|
<p class="hypertwist-initial-shell__body">
|
|
Preparing the public product story, shared auth posture, and desktop-first release lane.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
const BACKDROP_ID = 'hypertwist-auth-shell-backdrop';
|
|
|
|
function isAuthRoute(pathname) {
|
|
return pathname === '/login'
|
|
|| pathname.startsWith('/login/')
|
|
|| pathname === '/register'
|
|
|| pathname.startsWith('/register/')
|
|
|| pathname.startsWith('/auth/');
|
|
}
|
|
|
|
function syncAuthChrome() {
|
|
const shouldRender = isAuthRoute(window.location.pathname);
|
|
const existingBackdrop = document.getElementById(BACKDROP_ID);
|
|
|
|
if (!shouldRender) {
|
|
if (existingBackdrop) existingBackdrop.remove();
|
|
return;
|
|
}
|
|
|
|
if (!existingBackdrop) {
|
|
const backdrop = document.createElement('div');
|
|
backdrop.id = BACKDROP_ID;
|
|
backdrop.setAttribute('data-testid', 'supertokens-auth-backdrop');
|
|
backdrop.setAttribute('aria-hidden', 'true');
|
|
backdrop.style.position = 'fixed';
|
|
backdrop.style.inset = '0';
|
|
backdrop.style.zIndex = '0';
|
|
backdrop.style.pointerEvents = 'none';
|
|
backdrop.style.background = 'radial-gradient(circle at top, rgba(216,203,175,0.12), transparent 40%), linear-gradient(180deg, rgba(18,20,24,0.97), rgba(10,12,17,0.99))';
|
|
document.body.appendChild(backdrop);
|
|
}
|
|
}
|
|
|
|
function startAuthChromeObserver() {
|
|
syncAuthChrome();
|
|
window.addEventListener('popstate', syncAuthChrome);
|
|
window.addEventListener('hashchange', syncAuthChrome);
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', startAuthChromeObserver, { once: true });
|
|
} else {
|
|
startAuthChromeObserver();
|
|
}
|
|
})();
|
|
</script>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|