SKIP THE DEBT. / MASTER THE TRADE.
The Front Door is a Trap.
So we built a better door.
The institution wants you crawling through a broken window of debt just to learn a trade.
Senda Trades is the WebXR flight simulator
that puts the entire apprenticeship in your pocket.
// EARLY BETA ACCESS — LIMITED SPOTS
Enter your email to secure early Beta access and get in first.
We got you!
THE GATEKEEPER TAX / WHAT YOU’RE ACTUALLY PAYING FOR
We Cut the Bloat.
We Kept the Grit.
Built by actual electricians that are actively in the field. We know exactly what you need on a job site, because we are on the job site and we know what the trade schools are stealing from you. When you pay $20,000 to $40,000 for a traditional trade school, you are paying for their bloat.
// WHAT $40,000 ACTUALLY BUYS
01 — The Concrete Anchor.
You are paying the mortgage and electric bill for their 50,000 sq. ft. warehouse.
02 — The Consumable Burn.
You are paying for every foot of copper wire the first-years destroy. In Senda, our materials are pixels. We hit reset for $0.00.
03 — The Bureaucratic Bloat.
You pay the salaries of Deans and desk jockeys who haven’t touched a tool in 15 years.
04 — The Seat-Time Scam.
They stretch the curriculum to 4 years just to maximize profit, teaching theory you’ll never use. It is a staggering disrespect of your time.
THE UPGRADE / WHAT YOU GET INSTEAD
A Permanent Upgrade
to Your Income.
Merit-Based Speed.
Clear the entire map in under a year. You get what you earn by putting time in the app.
Zero Collateral Costs.
No textbooks. No commutes. The entire curriculum is in your pocket 24/7.
The Price of a Hammer.
Under $39.99 a month. Period.
EARLY BETA / LIMITED SPOTS
The Gatekeepers
Are Obsolete.
We are giving you the practical skills you will actually use.
// SECURE YOUR POSITION
Enter your email to lock in your spot before the Beta goes live.
We got you!
/* ── ANIMATION 1 (CARRD ORIGINAL): Generate the 100-dot animated SVG ──
Exact technique from Carrd: 10×10 grid of circles, each with an
SVG
// Pre-compute sine-wave keyframe values (16 steps, same as Carrd) const STEPS = 16; const keyTimes = Array.from({ length: STEPS }, (_, i) => (i / (STEPS - 1)).toFixed(4)).join(';');
function sineValues(cy, amp) { return Array.from({ length: STEPS }, (_, i) => { const t = i / (STEPS - 1); return (cy + amp * Math.sin(2 * Math.PI * t)).toFixed(4); }).join(';'); }
let svgContent = `
`;
let dotIndex = 0;
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const cx = col * CELL + CELL / 2;
const cy = row * CELL + CELL / 2;
const vals = sineValues(cy, AMPLITUDE);
const staggerMs = dotIndex * STAGGER;
// First dot anchors the chain; rest reference a0
const beginAttr = dotIndex === 0
? `id="a0" begin="-${DUR}ms;0ms;a0.begin+${DUR}ms"`
: `begin="a0.begin+${staggerMs}ms"`;
svgContent += `
svgContent += '';
const encoded = 'data:image/svg+xml;charset=utf8,' + encodeURIComponent(svgContent); document.documentElement.style.setProperty('--particle-bg', `url("${encoded}")`); })();
/* ── ANIMATION 4 (CARRD ORIGINAL): Card entry on load ───────────────── Remove .is-loading after a short delay to trigger the CSS transition. Then add .is-ready to trigger staggered reveal of card children. ─────────────────────────────────────────────────────────────────────── */ window.addEventListener('DOMContentLoaded', () => { // Small delay mirrors Carrd's loader behaviour setTimeout(() => { document.body.classList.remove('is-loading'); // Trigger staggered reveal setTimeout(() => { document.body.classList.add('is-ready'); }, 100); }, 80); });
/* ── ANIMATION 14 (BRUTALIST EXTRA): Custom volt cursor ─────────────── A small volt dot + ring follow the mouse with a lag. ─────────────────────────────────────────────────────────────────────── */ (function initCursor() { const dot = document.getElementById('cursorDot'); const ring = document.getElementById('cursorRing'); let mouseX = 0, mouseY = 0; let ringX = 0, ringY = 0; let active = false;
document.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; if (!active) { active = true; document.body.classList.add('cursor-active'); } // Dot follows instantly dot.style.left = mouseX + 'px'; dot.style.top = mouseY + 'px'; });
document.addEventListener('mouseleave', () => { document.body.classList.remove('cursor-active'); active = false; });
// Ring lags behind with lerp (function animateRing() { ringX += (mouseX - ringX) * 0.12; ringY += (mouseY - ringY) * 0.12; ring.style.left = ringX + 'px'; ring.style.top = ringY + 'px'; requestAnimationFrame(animateRing); })();
// Expand ring on interactive elements document.querySelectorAll('a, button, input').forEach(el => { el.addEventListener('mouseenter', () => { ring.style.width = '44px'; ring.style.height = '44px'; ring.style.borderColor = 'var(--volt)'; }); el.addEventListener('mouseleave', () => { ring.style.width = '28px'; ring.style.height = '28px'; ring.style.borderColor = 'rgba(245,230,66,0.4)'; }); }); })();
// ───────────────────────────────────────────────────────────────────── // INSERT FIREBASE CONFIG HERE // ───────────────────────────────────────────────────────────────────── // 1. Go to Firebase Console → Project Settings → Your Apps → Web App // 2. Copy the firebaseConfig object and paste it below, replacing this block // // const firebaseConfig = { // apiKey: "YOUR_API_KEY", // authDomain: "YOUR_PROJECT_ID.firebaseapp.com", // projectId: "YOUR_PROJECT_ID", // storageBucket: "YOUR_PROJECT_ID.appspot.com", // messagingSenderId: "YOUR_MESSAGING_SENDER_ID", // appId: "YOUR_APP_ID", // }; // ─────────────────────────────────────────────────────────────────────
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.2/firebase-app.js'; import { getFirestore, collection, addDoc, serverTimestamp } from 'https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js';
const firebaseConfig = { apiKey: "REPLACE_WITH_YOUR_API_KEY", authDomain: "REPLACE_WITH_YOUR_AUTH_DOMAIN", projectId: "REPLACE_WITH_YOUR_PROJECT_ID", storageBucket: "REPLACE_WITH_YOUR_STORAGE_BUCKET", messagingSenderId: "REPLACE_WITH_YOUR_MESSAGING_SENDER_ID", appId: "REPLACE_WITH_YOUR_APP_ID", };
const app = initializeApp(firebaseConfig); const db = getFirestore(app);
// DOM refs const form = document.getElementById('emailForm'); const emailInput = document.getElementById('emailInput'); const submitBtn = document.getElementById('submitBtn'); const btnText = document.getElementById('btnText'); const btnSpinner = document.getElementById('btnSpinner'); const btnIcon = document.getElementById('btnIcon'); const successMsg = document.getElementById('successMsg'); const errorMsg = document.getElementById('emailError');
function isValidEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim()); }
function setLoading(on) { submitBtn.disabled = on; btnText.textContent = on ? 'Sending...' : 'Get Early Access'; btnSpinner.style.display = on ? 'inline-block' : 'none'; btnIcon.style.display = on ? 'none' : 'block'; }
function showError(msg) { errorMsg.textContent = msg; errorMsg.classList.add('visible'); emailInput.setAttribute('aria-invalid', 'true'); }
function clearError() { errorMsg.textContent = ''; errorMsg.classList.remove('visible'); emailInput.removeAttribute('aria-invalid'); }
function showSuccess() { form.style.display = 'none'; successMsg.classList.add('visible'); }
form.addEventListener('submit', async (e) => { e.preventDefault(); clearError();
const email = emailInput.value.trim();
if (!email) { showError('// Enter your email address.'); emailInput.focus(); return; } if (!isValidEmail(email)) { showError("// That doesn't look like a valid email."); emailInput.focus(); return; }
setLoading(true);
try { // Write to Firestore — collection: early_access_emails await addDoc(collection(db, 'early_access_emails'), { email: email, createdAt: serverTimestamp(), source: 'senda_trades_landing', });
emailInput.value = ''; showSuccess();
} catch (err) { console.error('[Senda Trades] Firestore write failed:', err); showError('// Connection failed. Try again in a moment.'); setLoading(false); } });
emailInput.addEventListener('input', () => { if (errorMsg.classList.contains('visible')) clearError(); });
// ── BOTTOM FORM — identical logic, separate DOM refs ──────────────────── const formB = document.getElementById('emailFormBottom'); const emailInputB = document.getElementById('emailInputBottom'); const submitBtnB = document.getElementById('submitBtnBottom'); const btnTextB = document.getElementById('btnTextBottom'); const btnSpinnerB = document.getElementById('btnSpinnerBottom'); const btnIconB = document.getElementById('btnIconBottom'); const successMsgB = document.getElementById('successMsgBottom'); const errorMsgB = document.getElementById('emailErrorBottom');
function setLoadingB(on) { submitBtnB.disabled = on; btnTextB.textContent = on ? 'Sending...' : 'Secure Your Spot'; btnSpinnerB.style.display = on ? 'inline-block' : 'none'; btnIconB.style.display = on ? 'none' : 'block'; }
function showErrorB(msg) { errorMsgB.textContent = msg; errorMsgB.classList.add('visible'); emailInputB.setAttribute('aria-invalid', 'true'); }
function clearErrorB() { errorMsgB.textContent = ''; errorMsgB.classList.remove('visible'); emailInputB.removeAttribute('aria-invalid'); }
formB.addEventListener('submit', async (e) => { e.preventDefault(); clearErrorB();
const email = emailInputB.value.trim();
if (!email) { showErrorB('// Enter your email address.'); emailInputB.focus(); return; } if (!isValidEmail(email)) { showErrorB("// That doesn't look like a valid email."); emailInputB.focus(); return; }
setLoadingB(true);
try { await addDoc(collection(db, 'early_access_emails'), { email: email, createdAt: serverTimestamp(), source: 'senda_trades_landing', });
emailInputB.value = ''; formB.style.display = 'none'; successMsgB.classList.add('visible');
} catch (err) { console.error('[Senda Trades] Firestore write failed (bottom form):', err); showErrorB('// Connection failed. Try again in a moment.'); setLoadingB(false); } });
emailInputB.addEventListener('input', () => { if (errorMsgB.classList.contains('visible')) clearErrorB(); });