File size: 13,019 Bytes
faba2b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815dffe
faba2b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815dffe
 
 
 
 
 
 
 
 
 
 
 
 
 
faba2b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
// 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');
  }
});