12 Commits

Author SHA1 Message Date
9276c7cd75 Markets: the price chart is AP3X/USD across every pool, not one pair
The chart card read one DexScreener pair (bAP3X/USDC on Aerodrome). It now
draws AP3X in USD aggregated over every pool with at least $1K of liquidity
- four on Base (Aerodrome USDC and WETH, Uniswap and QuickSwap cbBTC) and
Minswap's cAP3X/ADA on Cardano - from GeckoTerminal's per-pool USD candles:
price liquidity-weighted (a pool with no trade holds its last close), volume
summed. 15m / 1h / 4h / 1D, an OHLC + volume readout, and a footer naming the
pools. GeckoTerminal is keyless and rate-limited, so the pool list (6 h) and
candles (3 min) are kept in localStorage; when it is busy the card shows the
largest pool's DexScreener chart and retries. VyFi and LBank are not in its
feed and say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:28:38 -05:00
de5b01cd01 Apex Universe: daily figures 2026-10-02 2026-10-02 06:15:06 +00:00
2373ea5299 Apex Universe: daily figures 2026-10-01 2026-10-01 06:15:04 +00:00
a3960a5bf9 Apex Universe: daily figures 2026-09-30 2026-09-30 06:15:03 +00:00
7347a647e8 Apex Universe: daily figures 2026-09-29 2026-09-29 06:15:05 +00:00
78f1df4934 Apex Universe: daily figures 2026-09-28 2026-09-28 06:15:03 +00:00
16126e9203 Merge pull request 'Fusion AI launch film: 'Now live' as in the site is live' (#4) from fix/launch-film-live into main 2026-09-27 06:52:15 +00:00
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
d7b0434e58 Merge pull request 'Fusion AI launch film: HAL 8 card and the widget lightbox' (#3) from feat/fusion-launch-film into main 2026-09-27 06:34:17 +00:00
dfa72eec45 Fusion AI launch film: the HAL 8 card and the widget's lightbox
A 32 s trailer rendered in Blender from the Apex Universe scene. The
pane in it is the real widget replaying answers Fusion AI gave on the
live route, voiced by ElevenLabs Brian, with an original score.
fusion/launch/ holds the 16:9 cut, its poster and English captions.
The HAL 8 section gets a 'Meet Fusion AI' card (Talk to Fusion AI opens
the widget through a fusion:open event), and the widget's welcome
screen a 'Watch the launch film' chip that plays it in a lightbox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 01:34:11 -05:00
c97d524025 Apex Universe: daily figures 2026-09-27 2026-09-27 06:15:05 +00:00
b9b9fe06d8 Merge pull request 'Fusion AI, powered by HAL 8: red eye, Standard | Incognito, code, media and voice' (#2) from feat/fusion-ai-hal8 into main 2026-09-27 00:56:47 +00:00
9 changed files with 118 additions and 4 deletions

View File

@@ -89,6 +89,14 @@ contract is `docs/FUSION.md` in the HAL 8 repository.
- Chat, code, web search, images, video and voice are always on.
- Python code blocks run in the visitor's browser.
The launch film lives in `fusion/launch/`. It includes:
- `fusion-ai-launch.mp4`, the 32-second, 16:9 cut shown on the HAL 8 page (the "Meet Fusion AI" card) and in the widget's "Watch the launch film" lightbox;
- `poster.jpg`, its poster frame;
- `fusion-ai-launch.vtt`, its subtitles.
The film was rendered in Blender from the Apex Universe scene. The Fusion pane in it is the real widget, playing answers Fusion AI actually gave. The voice is ElevenLabs "Brian", and the score is original.
The widget is `fusion/fusion.js` and `fusion/fusion.css`. After editing
either, run `python3 tools/fusion_inject.py`: it inlines the CSS and
re-stamps the module version inside `index.html`, and re-running it

View File

@@ -76,3 +76,18 @@
.f8-fab{right:18px;bottom:18px}
.f8-open .f8-fab{display:none}
}
.f8-watch{margin-top:14px;display:flex;align-items:center;gap:9px;width:100%;padding:10px 13px;border:1px solid rgba(255,42,26,.35);border-radius:10px;background:linear-gradient(90deg,rgba(255,42,26,.10),rgba(255,42,26,0));color:var(--ink);font-size:13.5px;text-align:left}
.f8-watch i{width:9px;height:9px;border-radius:50%;background:#FF2A1A;box-shadow:0 0 12px #FF2A1A;flex:none}
.f8-watch span{margin-left:auto;font-family:var(--f-mono);font-size:10.5px;color:var(--ink-3)}
.f8-watch:hover{border-color:rgba(255,42,26,.7)}
.f8-film{position:fixed;inset:0;z-index:300;background:rgba(0,0,0,.86);display:flex;align-items:center;justify-content:center;padding:24px}
.f8-film-frame{position:relative;width:min(1200px,100%);aspect-ratio:16/9;border-radius:12px;overflow:hidden;box-shadow:0 30px 90px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.08)}
.f8-film video{width:100%;height:100%;display:block;background:#000}
.f8-film-x{position:absolute;top:10px;right:10px;width:38px;height:38px;border-radius:50%;border:0;background:rgba(0,0,0,.55);color:#fff;font-size:24px;line-height:1;cursor:pointer}
.f8-launch{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);gap:28px;align-items:center;margin:30px 0 8px;padding:18px;border:1px solid var(--rule);border-radius:16px;background:linear-gradient(135deg,rgba(255,42,26,.06),rgba(255,255,255,.015) 45%)}
.f8-launch-media{border-radius:12px;overflow:hidden;background:#000;aspect-ratio:16/9;box-shadow:0 18px 50px rgba(0,0,0,.5)}
.f8-launch-media video{width:100%;height:100%;display:block}
.f8-launch-kicker{font-family:var(--f-mono);font-size:10.5px;letter-spacing:.22em;color:#FF5A47;margin-bottom:10px}
.f8-launch h3{font-family:var(--f-display);font-size:30px;line-height:1.1;margin:0 0 12px;color:var(--ink)}
.f8-launch p{color:var(--ink-2);font-size:15px;line-height:1.55;margin:0 0 18px}
@media (max-width:900px){.f8-launch{grid-template-columns:1fr}}

View File

@@ -8,6 +8,8 @@
// 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/';
@@ -147,7 +149,8 @@ export function mount(root, opts = {}) {
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></div>`;
<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('');
@@ -286,6 +289,27 @@ export function mount(root, opts = {}) {
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();
});
return { open: () => setOpen(true), destroy() { state.ctrl?.abort(); stopVoice(); root.innerHTML = ''; } };
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 = ''; },
};
}

Binary file not shown.

View File

@@ -0,0 +1,45 @@
WEBVTT
1
00:00:01.600 --> 00:00:03.700
Across three chains…
2
00:00:06.100 --> 00:00:08.800
…one intelligence was always watching.
3
00:00:12.200 --> 00:00:13.600
Ask it anything.
4
00:00:14.300 --> 00:00:15.500
Write code.
5
00:00:16.350 --> 00:00:17.900
Create worlds.
6
00:00:19.600 --> 00:00:21.100
Or just… talk.
7
00:00:22.100 --> 00:00:23.900
And when it’s just you…
8
00:00:24.000 --> 00:00:25.300
…nothing is kept.
9
00:00:26.450 --> 00:00:27.700
Fusion AI.
10
00:00:27.950 --> 00:00:29.100
Powered by HAL 8.
11
00:00:29.450 --> 00:00:31.500
Now live.

BIN
fusion/launch/poster.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,8 @@ subprocess.run([sys.executable, str(tool), "decode", str(SITE / "index.html"), s
page = tmp.read_text("utf-8")
VER = hashlib.sha1((SITE / "fusion" / "fusion.js").read_bytes()).hexdigest()[:10]
FILM = SITE / "fusion" / "launch" / "fusion-ai-launch.mp4"
FILM_V = hashlib.sha1(FILM.read_bytes()).hexdigest()[:10] if FILM.exists() else "0"
COMPONENT = f"""/*F8-BEGIN*/
// ============================================================================
// FUSION AI — powered by HAL 8 (fusion/fusion.js; the key lives on HAL 8, never here)
@@ -39,6 +41,21 @@ function FusionAI() {{
}}, []);
return MG("div", {{ ref }});
}}
// the launch film, on the HAL 8 page (fusion/launch/; "Talk to Fusion AI" opens the widget)
function FusionLaunchCard() {{
const film = "fusion/launch/fusion-ai-launch";
return MG("div", {{ className: "f8-launch" }},
MG("div", {{ className: "f8-launch-media" }},
MG("video", {{ src: film + ".mp4?v={FILM_V}", poster: "fusion/launch/poster.jpg?v={FILM_V}", controls: true, playsInline: true, preload: "none" }},
MG("track", {{ kind: "captions", src: film + ".vtt?v={FILM_V}", srcLang: "en", label: "English" }}))),
MG("div", {{ className: "f8-launch-copy" }},
MG("div", {{ className: "f8-launch-kicker" }}, "NEW · FUSION AI"),
MG("h3", null, "Meet Fusion AI. ", MG("span", {{ className: "serif-i" }}, "Powered by HAL 8.")),
MG("p", null, "The assistant on this site. Ask anything, write and run code, make images and short video, or just talk. Standard keeps your chat in this browser; Incognito keeps nothing."),
MG("div", {{ className: "h8-cta" }},
MG("button", {{ className: "mgx-btn pri", onClick: () => window.dispatchEvent(new CustomEvent("fusion:open")) }}, "Talk to Fusion AI"),
MG("a", {{ className: "mgx-btn", href: film + ".mp4", download: "fusion-ai-launch.mp4" }}, "Download the film"))));
}}
/*F8-END*/
"""
@@ -54,6 +71,11 @@ else:
assert old.count("function ") == 1 and "SYSTEM_PROMPT" in old and "Powered by Claude" in old, "unexpected old block"
page = page[:i] + COMPONENT + page[j:]
assert "Powered by Claude" not in page and page.count("function FusionAI()") == 1
# the card sits in the HAL 8 section, right above "Inside the harness"
HOOK = 'MG("div", { className: "mg-subhead" }, "Inside the harness"),'
if "MG(FusionLaunchCard, null)" not in page:
assert page.count(HOOK) == 1, "HAL 8 section hook not found"
page = page.replace(HOOK, "MG(FusionLaunchCard, null),\n " + HOOK)
css = (SITE / "fusion" / "fusion.css").read_text("utf-8")
page = re.sub(r"<style>/\*f8-css-begin\*/.*?/\*f8-css-end\*/</style>\n", "", page, flags=re.S)

File diff suppressed because one or more lines are too long