Elgtnl's picture
TerraForm Design
815dffe verified
// Oracle Engine Front-end Logic
// UTILITIES
const $ = (sel, root = document) => root.querySelector(sel);
const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel));
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const rand = (min, max) => Math.random() * (max - min) + min;
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
// INIT FEATHERS, YEAR, COUNTER
document.addEventListener('DOMContentLoaded', () => {
if (window.feather) feather.replace();
$('#year').textContent = new Date().getFullYear();
initCounters();
initTheme();
initNav();
initOrbits();
initConceptEngine();
initSignupModal();
initNewsletter();
});
// THEME TOGGLE
function initTheme() {
const btn = $('#themeToggle');
// Default to dark mode; ensure class exists
document.documentElement.classList.add('dark');
btn?.addEventListener('click', () => {
const isDark = document.documentElement.classList.toggle('dark');
btn.innerHTML = isDark ? '<i data-feather="moon" class="w-4 h-4"></i>' : '<i data-feather="sun" class="w-4 h-4"></i>';
feather.replace();
});
}
// MOBILE NAV
function initNav() {
const btn = $('#menuBtn');
const panel = $('#mobileNav');
btn?.addEventListener('click', () => {
panel.classList.toggle('hidden');
});
// Close on navigation
$$('#mobileNav a').forEach(a => a.addEventListener('click', () => panel.classList.add('hidden')));
}
// ORBIT CANVAS BACKGROUND
function initOrbits() {
const canvas = $('#orbits');
const ctx = canvas.getContext('2d');
let width, height, dpr;
let particles = [];
let mouse = { x: 0, y: 0 };
function resize() {
dpr = Math.min(2, window.devicePixelRatio || 1);
width = canvas.width = Math.floor(window.innerWidth * dpr);
height = canvas.height = Math.floor(window.innerHeight * dpr);
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
particles = createParticles(Math.floor((width * height) / (18000 * dpr)));
}
function createParticles(count) {
const arr = [];
for (let i = 0; i < count; i++) {
arr.push({
x: rand(0, width),
y: rand(0, height),
r: rand(0.6, 2.2) * dpr,
dx: rand(-0.15, 0.15) * dpr,
dy: rand(-0.15, 0.15) * dpr,
hue: rand(190, 280),
alpha: rand(0.25, 0.75),
});
}
return arr;
}
function step() {
ctx.clearRect(0, 0, width, height);
// subtle space glow
const grd = ctx.createRadialGradient(width * 0.5, height * 0.4, 0, width * 0.5, height * 0.4, Math.max(width, height) * 0.8);
grd.addColorStop(0, 'rgba(99,102,241,0.05)');
grd.addColorStop(1, 'rgba(6,182,212,0.02)');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, width, height);
// connections
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
p.x += p.dx;
p.y += p.dy;
if (p.x < 0 || p.x > width) p.dx *= -1;
if (p.y < 0 || p.y > height) p.dy *= -1;
// mouse interaction
const mx = mouse.x * dpr, my = mouse.y * dpr;
const dxm = p.x - mx, dym = p.y - my;
const distm = Math.sqrt(dxm * dxm + dym * dym);
const influence = clamp(140 * dpr - distm, 0, 140 * dpr) / (140 * dpr);
p.x += (dxm / (distm || 1)) * influence * 0.4;
p.y += (dym / (distm || 1)) * influence * 0.4;
// draw particle
ctx.beginPath();
ctx.fillStyle = `hsla(${p.hue}, 90%, 65%, ${p.alpha})`;
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fill();
// connections
for (let j = i + 1; j < particles.length; j++) {
const q = particles[j];
const dx = p.x - q.x;
const dy = p.y - q.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 120 * dpr) {
ctx.beginPath();
const a = clamp((120 * dpr - dist) / (120 * dpr), 0, 1) * 0.2;
ctx.strokeStyle = `hsla(${p.hue}, 90%, 65%, ${a})`;
ctx.lineWidth = 0.6 * dpr;
ctx.moveTo(p.x, p.y);
ctx.lineTo(q.x, q.y);
ctx.stroke();
}
}
}
requestAnimationFrame(step);
}
window.addEventListener('resize', resize);
window.addEventListener('mousemove', (e) => { mouse.x = e.clientX; mouse.y = e.clientY; });
resize();
step();
}
// COUNTER ANIMATION
function initCounters() {
const el = $('#conceptCounter');
if (!el) return;
const target = 24813;
const duration = 1200;
const start = performance.now();
function tick(t) {
const p = clamp((t - start) / duration, 0, 1);
const ease = 1 - Math.pow(1 - p, 3);
el.textContent = Math.floor(target * ease).toLocaleString();
if (p < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
// CONCEPT ENGINE DATA
const CONCEPT_BANK = [
{
title: 'Bio‑Responsive Hydration Platform',
domains: ['Biotech', 'Wellness', 'Materials'],
summary: 'A vessel and platform that modulates mineralization, pH, and micro‑dosage based on real‑time biomarkers and contextual signals.',
bullets: [
'Algae‑infused bio‑reactor keeps water oxygenated',
'Mineral composite equilibrates pH and electrolytes',
'DNA‑tagged capsules for personalized supplementation'
],
timing: '2028–2032',
readiness: 'Tech‑Adjacencies Converging',
viability: 92,
tags: ['Biotech', 'Sustainability', 'AI/ML']
},
{
title: 'Neural‑Loom Adaptive Textiles',
domains: ['Textiles', 'Haptics', 'Biometrics'],
summary: 'Fabrics that sense physiology and environment to tune thermal, moisture, and tension—displaying biofeedback via chromic fibers.',
bullets: [
'Piezo‑fiber mesh for haptic comfort mapping',
'Biofeedback dyes shift with stress metrics',
'On‑thread compute for low‑latency responses'
],
timing: '2027–2031',
readiness: 'Advanced Prototypes',
viability: 88,
tags: ['Wellness', 'Haptics', 'Materials']
},
{
title: 'Carbon‑Sequestering Architecture Blocks',
domains: ['Construction', 'Climate Tech', 'Materials'],
summary: 'Building blocks that sequester CO₂ over their lifecycle via mineral carbonation and self‑healing mycelium matrices.',
bullets: [
'Mycelium + mineral composite with self‑heal',
'On‑site carbon capture during curing',
'Modular units for rapid retrofitting'
],
timing: '2029–2034',
readiness: 'Pilots Active',
viability: 85,
tags: ['Climate', 'Construction', 'Circularity']
},
{
title: 'Ambient Compute Orchestrator',
domains: ['Edge AI', 'Spatial UX'],
summary: 'An ambient layer that senses room intent, orchestrates devices, and suggests interventions across spaces.',
bullets: [
'Edge transformers for multi‑modal context',
'Acoustic + visual sensing fusion',
'Privacy‑first on‑device inference'
],
timing: '2026–2030',
readiness: 'Production Readiness',
viability: 90,
tags: ['AI/ML', 'Edge', 'UX']
},
{
title: 'Oceanic Biomaterial Foundry',
domains: ['Blue Tech', 'Biomimicry'],
summary: 'Marine algae and bacteria cultivated to produce high‑performance biopolymers with tunable properties.',
bullets: [
'Programmable tensile strength and transparency',
'Fully biodegradable at end‑of‑life',
'Offshore cultivation reduces land use'
],
timing: '2030–2036',
readiness: 'Research Phase',
viability: 78,
tags: ['Biomaterials', 'Sustainability']
},
{
title: 'Micro‑Mobility Swarm Interfaces',
domains: ['Urban Systems', 'Mobility'],
summary: 'City‑level orchestration for micro‑vehicles with real‑time lane optimization and safety predictions.',
bullets: [
'Dynamic curb allocation',
'Predictive conflict avoidance',
'Open API for city and operator apps'
],
timing: '2027–2032',
readiness: 'Early Pilots',
viability: 83,
tags: ['Mobility', 'Cities', 'AI/ML']
},
{
title: 'TerraForm Design',
domains: ['Industrial Design', 'Sustainability', 'Circular Economy'],
summary: 'An industrial design service specializing in circular economy products, focusing on modularity, repairability, and using sustainable/recycled materials.',
bullets: [
'Modular product architecture for easy repair and upgrades',
'Lifecycle Optimization AI analyzes supply chain and end-of-life logistics',
'Recycled materials sourcing with carbon footprint tracking'
],
timing: '2025–2029',
readiness: 'Production Readiness',
viability: 94,
tags: ['Sustainability', 'Circular Economy', 'Industrial Design']
}
];
// CONCEPT ENGINE UI
function initConceptEngine() {
const grid = $('#conceptGrid');
const generateBtn = $('#generateBtn');
const generateBtnMobile = $('#generateBtnMobile');
function renderCard(item) {
const el = document.createElement('article');
el.className = 'rounded-2xl border border-white/10 bg-white/5 p-6 card-hover';
el.innerHTML = `
<div class="flex items-center justify-between">
<div class="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-2 py-1 text-xs text-slate-300">
<span class="w-2 h-2 rounded-full bg-accent-500 animate-pulse"></span>
${item.timing}
</div>
<div class="text-xs text-slate-400">${item.readiness}</div>
</div>
<h3 class="mt-4 font-display text-xl">${item.title}</h3>
<p class="mt-2 text-sm text-slate-300">${item.summary}</p>
<div class="mt-3 flex flex-wrap gap-2">
${item.tags.map(t => `<span class="rounded-lg bg-white/5 border border-white/10 px-2 py-1 text-[11px] text-slate-300">${t}</span>`).join('')}
</div>
<ul class="mt-4 grid gap-1.5 text-sm text-slate-300">
${item.bullets.map(b => `<li class="flex items-start gap-2"><i data-feather="chevron-right" class="w-4 h-4 text-accent-400 mt-0.5"></i><span>${b}</span></li>`).join('')}
</ul>
<div class="mt-5">
<div class="flex items-center justify-between text-xs text-slate-400">
<span>Viability Index</span>
<span>${item.viability}%</span>
</div>
<div class="h-1.5 rounded bg-white/10 overflow-hidden mt-1">
<div class="h-full bg-gradient-to-r from-accent-500 to-concept-cyan" style="width:${item.viability}%"></div>
</div>
</div>
`;
grid.appendChild(el);
feather.replace();
}
function renderAll() {
grid.innerHTML = '';
const shuffled = [...CONCEPT_BANK].sort(() => Math.random() - 0.5).slice(0, 6);
shuffled.forEach(renderCard);
animateCountUp();
}
function generateNew() {
grid.classList.add('opacity-60', 'scale-[0.99]');
setTimeout(() => {
renderAll();
grid.classList.remove('opacity-60', 'scale-[0.99]');
}, 220);
}
generateBtn?.addEventListener('click', generateNew);
generateBtnMobile?.addEventListener('click', generateNew);
renderAll();
}
function animateCountUp() {
const el = $('#conceptCounter');
if (!el) return;
const start = parseInt(el.textContent.replace(/,/g, '')) || 0;
const target = start + Math.floor(rand(5, 18));
const duration = 800;
const t0 = performance.now();
function tick(t) {
const p = clamp((t - t0) / duration, 0, 1);
const ease = 1 - Math.pow(1 - p, 3);
el.textContent = Math.floor(start + (target - start) * ease).toLocaleString();
if (p < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
// SIGNUP MODAL
function initSignupModal() {
const modal = $('#signupModal');
const openBtn = $('#openSignup');
const closeBtn = $('#closeSignup');
const form = $('#signupForm');
const msg = $('#signupMsg');
const open = () => { modal.classList.remove('hidden'); modal.classList.add('modal-enter'); };
const close = () => { modal.classList.add('hidden'); modal.classList.remove('modal-enter'); msg.textContent = ''; };
openBtn?.addEventListener('click', open);
closeBtn?.addEventListener('click', close);
modal?.addEventListener('click', (e) => { if (e.target === modal) close(); });
form?.addEventListener('submit', (e) => {
e.preventDefault();
msg.textContent = 'Creating your workspace...';
setTimeout(() => {
msg.textContent = 'Success! Check your email to confirm your account.';
setTimeout(close, 1000);
}, 900);
});
}
// NEWSLETTER
function initNewsletter() {
const form = $('#newsletter');
const msg = $('#newsletterMsg');
form?.addEventListener('submit', (e) => {
e.preventDefault();
msg.textContent = 'Subscribed! Welcome to the loop.';
form.reset();
});
}
// ACCESSIBILITY: close modals with Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
$('#mobileNav')?.classList.add('hidden');
const modal = $('#signupModal');
if (modal && !modal.classList.contains('hidden')) modal.classList.add('hidden');
}
});