Files
apex-fusion-site/fusion/fusion.js
jerry 830d021f94 Fusion AI launch film: 'Now live' as in the site is live
The closing line was voiced as live (to live). Re-voiced so it rhymes
with five (checked against Brian's own 'five' and 'drive' by formant),
everything else unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 01:52:00 -05:00

316 lines
22 KiB
JavaScript

// Fusion AI, powered by HAL 8: the hub's consumer assistant.
// One control (Standard | Incognito); everything else is always on: chat and code, images and
// video, web search, a Python interpreter that runs in the visitor's browser, and voice.
// The browser never holds a key: it talks to HAL 8's public Fusion endpoint, which runs the
// request through HAL 8's headless pipeline under its own capped service account.
// Standard - hal8-auto; the conversation is kept in this browser (localStorage) until cleared.
// Incognito - a Venice private model; no conversation is kept, here or on HAL 8, and the
// pictures and clips it makes are deleted after a day.
const EYE = 'universe/logos/hal8-eye.png';
const LAUNCH = new URL('launch/', import.meta.url);
const FILM_V = '2';
const STORE = 'f8.chat.v1';
const VISITOR = 'f8.visitor';
const PYODIDE = 'https://cdn.jsdelivr.net/pyodide/v0.26.4/full/';
const SUGGEST = {
standard: [['Ask', 'How do I stake AP3X?'], ['Code', 'A Python snippet that converts DFM to AP3X'],
['Image', 'The AP3X star rising over PRIME'], ['Video', 'A five-second flight through an asteroid belt']],
incognito: [['Ask', 'Explain AP3X tokenomics simply'], ['Image', 'A night sky over the Nexus world']],
};
const I = {
incog: '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l18 18"/><path d="M10.6 5.1A10.4 10.4 0 0 1 12 5c5 0 9 4.5 10 7-.4 1-1.2 2.3-2.4 3.5M6.2 6.3C4.2 7.6 2.7 9.6 2 12c1 2.5 5 7 10 7 1.7 0 3.3-.5 4.6-1.3"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>',
mic: '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/></svg>',
send: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>',
stop: '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"/></svg>',
plus: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>',
copy: '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M16 8V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3"/></svg>',
speak: '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M11 5 6 9H3v6h3l5 4zM15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13"/></svg>',
dl: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M12 4v11M7 10l5 5 5-5M5 20h14"/></svg>',
};
const esc = s => String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
// media and links: https only; paths HAL 8 returns relative to itself resolve against the endpoint
let ORIGIN = 'https://hal8.odyssey-works.io';
const safeUrl = u => {
if (/^\/(?!\/)/.test(u)) return ORIGIN + u;
if (/^https:\/\//i.test(u)) return u;
if (ORIGIN.startsWith('http://127.0.0.1') && /^http:\/\/127\.0\.0\.1[:/]/.test(u)) return u; // local testing only
return null;
};
const isVideo = u => /\.(mp4|webm|mov)(\?|#|$)/i.test(u) || /[?&](type|kind)=video/i.test(u);
// HAL 8's signed file links carry no extension: a HAL 8 file linked as "video" / "clip" is one
const isHal8File = u => u.startsWith(ORIGIN + '/api/v1/files/');
const namedVideo = (label, u) => isHal8File(u) && /^\s*(video|clip|watch)\b/i.test(label);
// ------------------------------------------------------------------ a small, safe markdown renderer
// Everything is escaped first; only code fences, inline code, emphasis, headings, lists, links,
// images and videos (https only) are turned back into markup.
export function renderMarkdown(src) {
const blocks = [];
let text = String(src ?? '').replace(/```([\w+-]*)[^\n]*\n([\s\S]*?)(```|$)/g, (_, lang, code) => {
blocks.push({ lang: (lang || '').toLowerCase(), code: code.replace(/\n$/, '') });
return `\u0000${blocks.length - 1}\u0000`;
});
text = esc(text);
const inline = s => s
.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g, (m, alt, u) => { u = u.replace(/&amp;/g, '&'); const ok = safeUrl(u); if (!ok) return esc(alt);
return isVideo(ok) ? media(ok, 'video', alt) : media(ok, 'image', alt); })
.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (m, t, u) => { u = u.replace(/&amp;/g, '&'); const ok = safeUrl(u); if (!ok) return t;
return isVideo(ok) || namedVideo(t, ok) ? media(ok, 'video', t) : `<a href="${esc(ok)}" target="_blank" rel="noopener nofollow">${t}</a>`; })
.replace(/`([^`]+)`/g, '<code>$1</code>')
.replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>').replace(/(^|[\s(])\*([^*\n]+)\*/g, '$1<i>$2</i>');
const out = [];
let list = null;
const flush = () => { if (list) { out.push(`<${list.t}>${list.items.map(x => `<li>${inline(x)}</li>`).join('')}</${list.t}>`); list = null; } };
for (const raw of text.split('\n')) {
const line = raw.trimEnd();
const code = line.match(/^\u0000(\d+)\u0000$/);
if (code) { flush(); out.push(codeBlock(blocks[+code[1]])); continue; }
const h = line.match(/^(#{1,4})\s+(.*)$/);
if (h) { flush(); out.push(`<h4>${inline(h[2])}</h4>`); continue; }
const ul = line.match(/^\s*[-*•]\s+(.*)$/), ol = line.match(/^\s*\d+[.)]\s+(.*)$/);
if (ul || ol) { const t = ul ? 'ul' : 'ol'; if (!list || list.t !== t) { flush(); list = { t, items: [] }; } list.items.push((ul || ol)[1]); continue; }
flush();
if (!line.trim()) continue;
out.push(`<p>${inline(line).replace(/\u0000(\d+)\u0000/g, (_, n) => codeBlock(blocks[+n]))}</p>`);
}
flush();
return out.join('');
}
function media(u, kind, label) {
const body = kind === 'video' ? `<video src="${esc(u)}" controls playsinline preload="metadata"></video>` : `<img src="${esc(u)}" alt="${esc(label || '')}" loading="lazy">`;
return `<span class="f8-media">${body}<span class="f8-media-bar"><span>${kind === 'video' ? 'Video' : 'Image'} &middot; HAL 8</span><a href="${esc(u)}" download target="_blank" rel="noopener" title="Download">${I.dl}</a></span></span>`;
}
function codeBlock(b) {
const runnable = ['python', 'py', ''].includes(b.lang) && /print|=|def |import /.test(b.code);
return `<div class="f8-code" data-lang="${esc(b.lang || 'code')}"><div class="f8-code-h"><span>${esc(b.lang || 'code')}</span><span class="f8-code-act">` +
(runnable ? '<button data-f8="run">&#9654; Run</button>' : '') + `<button data-f8="copy-code">${I.copy} Copy</button></span></div><pre>${esc(b.code)}</pre></div>`;
}
// ------------------------------------------------------------------ the widget
export function mount(root, opts = {}) {
const endpoint = opts.endpoint;
try { ORIGIN = new URL(endpoint).origin; } catch { /* keep HAL 8 */ }
const state = { open: false, mode: 'standard', msgs: { standard: load(), incognito: [] }, busy: false, ctrl: null, voiceTurn: false };
root.classList.add('f8-root');
root.innerHTML = `
<button class="f8-fab" aria-label="Ask Fusion AI" aria-expanded="false" aria-controls="f8-pane"><img src="${EYE}" alt="HAL 8"><span class="f8-fab-x" aria-hidden="true">&times;</span></button>
<div class="f8-pane" id="f8-pane" role="dialog" aria-label="Fusion AI" hidden>
<div class="f8-head">
<div><div class="f8-title serif">Fusion <span class="serif-i">AI</span></div><div class="f8-power"><img src="${EYE}" alt="">POWERED BY HAL 8</div></div>
<div class="f8-head-actions"><button data-f8="new" title="New chat" aria-label="New chat">${I.plus}</button><button data-f8="close" class="f8-x" title="Close" aria-label="Close">&times;</button></div>
</div>
<div class="f8-modebar"><div class="f8-pill" role="tablist" aria-label="Mode">
<button role="tab" data-mode="standard" aria-selected="true" class="on">Standard</button>
<button role="tab" data-mode="incognito" aria-selected="false">${I.incog} Incognito</button></div></div>
<div class="f8-incog-note">${I.incog} Incognito &middot; nothing is saved &middot; pictures vanish in a day</div>
<div class="f8-body" aria-live="polite"></div>
<div class="f8-compose">
<div class="f8-listen" hidden><span class="f8-wave"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span><span class="f8-heard">Listening&hellip;</span></div>
<textarea rows="1" placeholder="Ask anything, or tap the mic" aria-label="Message Fusion AI"></textarea>
<button class="f8-mic" data-f8="mic" title="Speak" aria-label="Speak">${I.mic}</button>
<button class="f8-send" data-f8="send" title="Send" aria-label="Send">${I.send}</button>
</div>
</div>`;
const $ = s => root.querySelector(s);
const fab = $('.f8-fab'), pane = $('.f8-pane'), body = $('.f8-body'), ta = $('textarea'), sendBtn = $('.f8-send'), micBtn = $('.f8-mic');
// a HAL 8 file embedded as an image that will not decode is a clip: play it instead
body.addEventListener('error', e => {
const img = e.target;
if (img.tagName !== 'IMG' || !img.closest('.f8-media') || !isHal8File(img.src)) return;
const v = document.createElement('video');
Object.assign(v, { src: img.src, controls: true, playsInline: true, preload: 'metadata' });
img.replaceWith(v);
const tag = v.parentElement?.querySelector('.f8-media-bar span');
if (tag) tag.innerHTML = 'Video &middot; HAL 8';
}, true);
function load() { try { return JSON.parse(localStorage.getItem(STORE) || '[]').slice(-60); } catch { return []; } }
function save() { if (state.mode !== 'standard') return; try { localStorage.setItem(STORE, JSON.stringify(state.msgs.standard.slice(-60))); } catch { /* storage off */ } }
function visitor() {
try { let v = localStorage.getItem(VISITOR); if (!v) { v = crypto.randomUUID(); localStorage.setItem(VISITOR, v); } return v; } catch { return 'anon'; }
}
const msgs = () => state.msgs[state.mode];
function setOpen(o) {
state.open = o; pane.hidden = !o; root.classList.toggle('f8-open', o); fab.setAttribute('aria-expanded', String(o));
if (o) { draw(); setTimeout(() => ta.focus(), 30); } else { stopVoice(); speechSynthesis?.cancel?.(); }
}
function setMode(m) {
if (m === state.mode) return;
state.ctrl?.abort();
if (state.mode === 'incognito') state.msgs.incognito = []; // leaving incognito forgets it
state.mode = m; root.classList.toggle('f8-incognito', m === 'incognito');
root.querySelectorAll('.f8-pill button').forEach(b => { const on = b.dataset.mode === m; b.classList.toggle('on', on); b.setAttribute('aria-selected', String(on)); });
draw();
}
function draw() {
const list = msgs();
if (!list.length) {
const s = SUGGEST[state.mode];
body.innerHTML = `<div class="f8-empty"><p class="serif">${state.mode === 'incognito' ? "You're incognito. <span class=\"serif-i\">Nothing you say here is kept.</span>" : "Hi, I'm Fusion AI. <span class=\"serif-i\">Ask, code, create or just talk.</span>"}</p>
<div class="f8-sugg">${s.map(([k, t]) => `<button data-f8="suggest"><b>${k}</b>${esc(t)}</button>`).join('')}</div>
${state.mode === 'standard' ? '<button class="f8-watch" data-f8="watch"><i></i>Watch the launch film<span>0:32</span></button>' : ''}</div>`;
return;
}
body.innerHTML = list.map((m, i) => bubble(m, i)).join('');
body.scrollTop = body.scrollHeight;
}
function bubble(m, i) {
if (m.role === 'user') return `<div class="f8-u">${esc(m.content)}</div>`;
if (m.kind === 'limit') return `<div class="f8-a f8-limit">${esc(m.content)}</div>`;
const tools = m.content && !m.pending ? `<div class="f8-meta"><button data-f8="copy" data-i="${i}" title="Copy">${I.copy}</button><button data-f8="speak" data-i="${i}" title="Read aloud">${I.speak}</button></div>` : '';
const status = m.pending && m.status ? `<div class="f8-status"><span class="f8-dots"><i></i><i></i><i></i></span>${esc(m.status)}</div>` : '';
const html = m.content ? renderMarkdown(m.content) : '';
return `<div class="f8-a${m.pending && !m.content ? ' f8-thinking' : ''}">${html}${status || (m.pending && !m.content ? '<span class="f8-dots"><i></i><i></i><i></i></span>' : '')}${tools}</div>`;
}
function redrawLast() {
const list = msgs(), el = body.lastElementChild;
if (!el || !list.length) return draw();
const tmp = document.createElement('div'); tmp.innerHTML = bubble(list[list.length - 1], list.length - 1);
el.replaceWith(tmp.firstElementChild); body.scrollTop = body.scrollHeight;
}
// ---------------------------------------------------------------- sending, streamed
async function send(text) {
text = (text || '').trim();
if (!text || state.busy) return;
const list = msgs();
list.push({ role: 'user', content: text });
const reply = { role: 'assistant', content: '', pending: true };
list.push(reply);
ta.value = ''; autoGrow(); state.busy = true; sendBtn.innerHTML = I.stop; sendBtn.title = 'Stop'; draw();
const ctrl = new AbortController(); state.ctrl = ctrl;
const history = list.filter(m => !m.pending && m.kind !== 'limit').slice(-16).map(m => ({ role: m.role, content: m.content }));
try {
const r = await fetch(endpoint, {
method: 'POST', signal: ctrl.signal, headers: { 'Content-Type': 'application/json', Accept: 'text/event-stream' },
body: JSON.stringify({ mode: state.mode, messages: history, visitor: state.mode === 'incognito' ? undefined : visitor(), stream: true }),
});
if (!r.ok) {
let e = {}; try { e = (await r.json()).error || {}; } catch { /* not json */ }
reply.pending = false;
if (r.status === 429) { reply.kind = 'limit'; reply.content = e.message || "That's today's allowance for Fusion AI. It resets at 00:00 UTC; see you then."; }
else reply.content = e.message || "I couldn't reach HAL 8 just now. Try again in a moment.";
return;
}
const ct = r.headers.get('content-type') || '';
if (ct.includes('text/event-stream') && r.body) {
const rd = r.body.getReader(), dec = new TextDecoder(); let buf = '';
for (;;) {
const { value, done } = await rd.read(); if (done) break;
buf += dec.decode(value, { stream: true });
let k;
while ((k = buf.indexOf('\n\n')) >= 0) {
const evt = buf.slice(0, k); buf = buf.slice(k + 2);
for (const ln of evt.split('\n')) {
if (!ln.startsWith('data:')) continue;
const d = ln.slice(5).trim(); if (!d || d === '[DONE]') continue;
let j; try { j = JSON.parse(d); } catch { continue; }
if (j.error) { reply.kind = j.error.code && /limit|budget/.test(j.error.code) ? 'limit' : ''; reply.content = j.error.message || 'Something went wrong.'; continue; }
if (j.status) reply.status = j.status; // e.g. "Searching the web", "Rendering video"
const delta = j.choices?.[0]?.delta?.content ?? j.choices?.[0]?.message?.content ?? '';
if (delta) reply.content += delta;
}
redrawLast();
}
}
} else {
const j = await r.json();
reply.content = j.choices?.[0]?.message?.content || j.text || '';
}
if (!reply.content) reply.content = 'Hmm, an empty answer. Try asking again.';
} catch (e) {
if (e.name !== 'AbortError') reply.content = reply.content || "I couldn't reach HAL 8 just now. Try again in a moment.";
} finally {
reply.pending = false; reply.status = ''; state.busy = false; state.ctrl = null; sendBtn.innerHTML = I.send; sendBtn.title = 'Send';
draw(); save();
if (state.voiceTurn && reply.content && reply.kind !== 'limit') speak(reply.content);
state.voiceTurn = false;
}
}
// ---------------------------------------------------------------- voice: speak in, read out
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
let rec = null;
function startVoice() {
if (!SR) { toast('Voice needs Chrome, Edge or Safari on this device.'); return; }
speechSynthesis?.cancel?.();
rec = new SR(); rec.lang = navigator.language || 'en-US'; rec.interimResults = true; rec.continuous = false;
let finalText = '';
const heard = $('.f8-heard'); $('.f8-listen').hidden = false; root.classList.add('f8-voice');
rec.onresult = ev => { let interim = ''; for (let i = ev.resultIndex; i < ev.results.length; i++) { const t = ev.results[i][0].transcript; if (ev.results[i].isFinal) finalText += t; else interim += t; }
heard.innerHTML = `Listening&hellip; <em>${esc((finalText + ' ' + interim).trim())}</em>`; };
rec.onerror = ev => { if (ev.error === 'not-allowed') toast('Allow the microphone to talk to Fusion AI.'); };
rec.onend = () => { stopVoice(); if (finalText.trim()) { state.voiceTurn = true; send(finalText); } };
rec.start();
}
function stopVoice() { root.classList.remove('f8-voice'); $('.f8-listen').hidden = true; $('.f8-heard').innerHTML = 'Listening&hellip;'; if (rec) { try { rec.stop(); } catch { /* already stopped */ } rec = null; } }
function speak(md) {
if (!('speechSynthesis' in window)) return;
const plain = md.replace(/```[\s\S]*?```/g, ' (code shown on screen) ').replace(/!?\[([^\]]*)\]\([^)]+\)/g, '$1').replace(/[#*`>_]/g, '').slice(0, 1800);
speechSynthesis.cancel(); const u = new SpeechSynthesisUtterance(plain); u.lang = navigator.language || 'en-US'; speechSynthesis.speak(u);
}
// ---------------------------------------------------------------- the code interpreter (Pyodide, in this browser)
let py = null;
async function runPython(btn) {
const box = btn.closest('.f8-code'); const code = box.querySelector('pre').textContent;
let out = box.querySelector('.f8-out'); if (!out) { out = document.createElement('div'); out.className = 'f8-out'; box.appendChild(out); }
out.innerHTML = '<span>output</span>Starting Python&hellip;';
try {
if (!py) py = (async () => { await new Promise((res, rej) => { const s = document.createElement('script'); s.src = PYODIDE + 'pyodide.js'; s.onload = res; s.onerror = rej; document.head.appendChild(s); }); return window.loadPyodide({ indexURL: PYODIDE }); })();
const p = await py; let buf = '';
p.setStdout({ batched: s => { buf += s + '\n'; } }); p.setStderr({ batched: s => { buf += s + '\n'; } });
await p.loadPackagesFromImports(code);
const res = await p.runPythonAsync(code);
if (res !== undefined && res !== null && !buf) buf = String(res);
out.innerHTML = `<span>output</span>${esc(buf.trim() || '(no output)')}`;
} catch (e) { out.innerHTML = `<span>error</span>${esc(String(e.message || e).split('\n').slice(-3).join('\n'))}`; }
}
// ---------------------------------------------------------------- events
function toast(t) { const el = document.createElement('div'); el.className = 'f8-toast'; el.textContent = t; pane.appendChild(el); setTimeout(() => el.remove(), 3200); }
function autoGrow() { ta.style.height = 'auto'; ta.style.height = Math.min(ta.scrollHeight, 120) + 'px'; }
fab.addEventListener('click', () => setOpen(!state.open));
ta.addEventListener('input', autoGrow);
ta.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(ta.value); } });
root.addEventListener('keydown', e => { if (e.key === 'Escape' && state.open) setOpen(false); });
root.addEventListener('click', e => {
const b = e.target.closest('[data-f8],[data-mode]'); if (!b) return;
if (b.dataset.mode) return setMode(b.dataset.mode);
const act = b.dataset.f8, list = msgs();
if (act === 'close') setOpen(false);
else if (act === 'new') { state.ctrl?.abort(); state.msgs[state.mode] = []; if (state.mode === 'standard') { try { localStorage.removeItem(STORE); } catch { /* */ } } draw(); }
else if (act === 'send') { if (state.busy) state.ctrl?.abort(); else send(ta.value); }
else if (act === 'mic') { if (root.classList.contains('f8-voice')) stopVoice(); else startVoice(); }
else if (act === 'suggest') send(b.childNodes[1]?.textContent || b.textContent);
else if (act === 'copy') navigator.clipboard?.writeText(list[+b.dataset.i]?.content || '');
else if (act === 'speak') speak(list[+b.dataset.i]?.content || '');
else if (act === 'copy-code') navigator.clipboard?.writeText(b.closest('.f8-code').querySelector('pre').textContent);
else if (act === 'run') runPython(b);
else if (act === 'watch') watchFilm();
});
function watchFilm() {
const box = document.createElement('div');
box.className = 'f8-film';
box.setAttribute('role', 'dialog');
box.setAttribute('aria-label', 'Fusion AI launch film');
box.innerHTML = `<div class="f8-film-frame"><video controls autoplay playsinline preload="auto"
src="${new URL('fusion-ai-launch.mp4?v=' + FILM_V, LAUNCH)}" poster="${new URL('poster.jpg?v=' + FILM_V, LAUNCH)}">
<track kind="captions" srclang="en" label="English" src="${new URL('fusion-ai-launch.vtt?v=' + FILM_V, LAUNCH)}"></video>
<button class="f8-film-x" aria-label="Close">&times;</button></div>`;
const close = () => { box.querySelector('video')?.pause(); box.remove(); document.removeEventListener('keydown', onKey); };
const onKey = e => { if (e.key === 'Escape') close(); };
box.addEventListener('click', e => { if (e.target === box || e.target.closest('.f8-film-x')) close(); });
document.addEventListener('keydown', onKey);
document.body.appendChild(box);
}
const onExternalOpen = () => { setOpen(true); };
window.addEventListener('fusion:open', onExternalOpen);
return {
open: () => setOpen(true),
destroy() { state.ctrl?.abort(); stopVoice(); window.removeEventListener('fusion:open', onExternalOpen); root.innerHTML = ''; },
};
}