first-commit
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
/* html-ppt :: animations.css
|
||||
* Apply by adding class="anim-<name>" or data-anim="<name>".
|
||||
* Durations are deliberately snappy; tweak --anim-dur per element.
|
||||
*/
|
||||
:root{--anim-dur:.7s;--anim-ease:cubic-bezier(.4,0,.2,1)}
|
||||
|
||||
/* ---------- FADE DIRECTIONALS ---------- */
|
||||
@keyframes kf-fade-up{from{opacity:0;transform:translateY(32px)}to{opacity:1;transform:none}}
|
||||
@keyframes kf-fade-down{from{opacity:0;transform:translateY(-32px)}to{opacity:1;transform:none}}
|
||||
@keyframes kf-fade-left{from{opacity:0;transform:translateX(-40px)}to{opacity:1;transform:none}}
|
||||
@keyframes kf-fade-right{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
|
||||
.anim-fade-up{animation:kf-fade-up var(--anim-dur) var(--anim-ease) both}
|
||||
.anim-fade-down{animation:kf-fade-down var(--anim-dur) var(--anim-ease) both}
|
||||
.anim-fade-left{animation:kf-fade-left var(--anim-dur) var(--anim-ease) both}
|
||||
.anim-fade-right{animation:kf-fade-right var(--anim-dur) var(--anim-ease) both}
|
||||
|
||||
/* ---------- RISE / DROP / ZOOM / BLUR / GLITCH ---------- */
|
||||
@keyframes kf-rise{from{opacity:0;transform:translateY(60px) scale(.97);filter:blur(6px)}to{opacity:1;transform:none;filter:none}}
|
||||
@keyframes kf-drop{from{opacity:0;transform:translateY(-60px) scale(.97)}to{opacity:1;transform:none}}
|
||||
@keyframes kf-zoom{0%{opacity:0;transform:scale(.6)}60%{transform:scale(1.04)}100%{opacity:1;transform:scale(1)}}
|
||||
@keyframes kf-blur{from{opacity:0;filter:blur(18px)}to{opacity:1;filter:none}}
|
||||
@keyframes kf-glitch{0%{opacity:0;transform:translateX(0);clip-path:inset(0 0 0 0)}
|
||||
20%{opacity:1;transform:translateX(-6px);clip-path:inset(20% 0 30% 0)}
|
||||
40%{transform:translateX(4px);clip-path:inset(50% 0 10% 0)}
|
||||
60%{transform:translateX(-3px);clip-path:inset(10% 0 60% 0)}
|
||||
80%{transform:translateX(2px);clip-path:inset(0 0 0 0)}
|
||||
100%{opacity:1;transform:none}}
|
||||
.anim-rise-in{animation:kf-rise .9s var(--anim-ease) both}
|
||||
.anim-drop-in{animation:kf-drop .8s var(--anim-ease) both}
|
||||
.anim-zoom-pop{animation:kf-zoom .7s cubic-bezier(.22,1.3,.36,1) both}
|
||||
.anim-blur-in{animation:kf-blur .8s var(--anim-ease) both}
|
||||
.anim-glitch-in{animation:kf-glitch .8s steps(5,end) both}
|
||||
|
||||
/* ---------- TYPEWRITER ---------- */
|
||||
.anim-typewriter{display:inline-block;overflow:hidden;white-space:nowrap;border-right:2px solid currentColor;
|
||||
width:0;animation:kf-type 2.4s steps(40,end) forwards, kf-caret 1s step-end infinite}
|
||||
@keyframes kf-type{to{width:100%}}
|
||||
@keyframes kf-caret{50%{border-color:transparent}}
|
||||
|
||||
/* ---------- GLOW / SHIMMER / GRADIENT-FLOW ---------- */
|
||||
@keyframes kf-neon{0%,100%{text-shadow:0 0 8px var(--accent),0 0 20px var(--accent)}
|
||||
50%{text-shadow:0 0 16px var(--accent),0 0 40px var(--accent),0 0 80px var(--accent)}}
|
||||
.anim-neon-glow{animation:kf-neon 2s ease-in-out infinite}
|
||||
|
||||
.anim-shimmer-sweep{position:relative;overflow:hidden}
|
||||
.anim-shimmer-sweep::after{content:"";position:absolute;inset:0;
|
||||
background:linear-gradient(110deg,transparent 40%,rgba(255,255,255,.55) 50%,transparent 60%);
|
||||
transform:translateX(-100%);animation:kf-shimmer 2.4s var(--anim-ease) infinite}
|
||||
@keyframes kf-shimmer{to{transform:translateX(100%)}}
|
||||
|
||||
.anim-gradient-flow{background:linear-gradient(90deg,var(--accent),var(--accent-2,var(--accent)),var(--accent-3,var(--accent)),var(--accent));
|
||||
background-size:300% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;
|
||||
animation:kf-gradflow 4s linear infinite}
|
||||
@keyframes kf-gradflow{to{background-position:300% 0}}
|
||||
|
||||
/* ---------- STAGGER LIST ---------- */
|
||||
.anim-stagger-list > *{opacity:0;animation:kf-rise .65s var(--anim-ease) both}
|
||||
.anim-stagger-list > *:nth-child(1){animation-delay:.05s}
|
||||
.anim-stagger-list > *:nth-child(2){animation-delay:.15s}
|
||||
.anim-stagger-list > *:nth-child(3){animation-delay:.25s}
|
||||
.anim-stagger-list > *:nth-child(4){animation-delay:.35s}
|
||||
.anim-stagger-list > *:nth-child(5){animation-delay:.45s}
|
||||
.anim-stagger-list > *:nth-child(6){animation-delay:.55s}
|
||||
.anim-stagger-list > *:nth-child(7){animation-delay:.65s}
|
||||
.anim-stagger-list > *:nth-child(8){animation-delay:.75s}
|
||||
.anim-stagger-list > *:nth-child(n+9){animation-delay:.85s}
|
||||
|
||||
/* ---------- COUNTER-UP (JS-driven, marker class only) ---------- */
|
||||
.counter{font-variant-numeric:tabular-nums}
|
||||
|
||||
/* ---------- SVG PATH DRAW ---------- */
|
||||
.anim-path-draw path,.anim-path-draw line,.anim-path-draw polyline,.anim-path-draw circle,.anim-path-draw rect{
|
||||
stroke-dasharray:1000;stroke-dashoffset:1000;animation:kf-draw 2s var(--anim-ease) forwards}
|
||||
@keyframes kf-draw{to{stroke-dashoffset:0}}
|
||||
|
||||
/* ---------- PARALLAX TILT (hover) ---------- */
|
||||
.anim-parallax-tilt{transform-style:preserve-3d;transition:transform .4s var(--anim-ease)}
|
||||
.anim-parallax-tilt:hover{transform:perspective(900px) rotateX(6deg) rotateY(-8deg) translateZ(10px)}
|
||||
|
||||
/* ---------- CARD FLIP 3D ---------- */
|
||||
@keyframes kf-flip{from{transform:perspective(1200px) rotateY(-90deg);opacity:0}
|
||||
to{transform:perspective(1200px) rotateY(0);opacity:1}}
|
||||
.anim-card-flip-3d{animation:kf-flip .9s var(--anim-ease) both;transform-style:preserve-3d;backface-visibility:hidden}
|
||||
|
||||
/* ---------- CUBE ROTATE 3D ---------- */
|
||||
@keyframes kf-cube{from{transform:perspective(1200px) rotateX(20deg) rotateY(-90deg) translateZ(-200px);opacity:0}
|
||||
to{transform:perspective(1200px) rotateX(0) rotateY(0) translateZ(0);opacity:1}}
|
||||
.anim-cube-rotate-3d{animation:kf-cube 1s var(--anim-ease) both}
|
||||
|
||||
/* ---------- PAGE TURN 3D ---------- */
|
||||
@keyframes kf-pageturn{from{transform:perspective(1600px) rotateY(-85deg);transform-origin:left center;opacity:0}
|
||||
to{transform:perspective(1600px) rotateY(0);opacity:1}}
|
||||
.anim-page-turn-3d{animation:kf-pageturn 1s var(--anim-ease) both;transform-origin:left center}
|
||||
|
||||
/* ---------- PERSPECTIVE ZOOM ---------- */
|
||||
@keyframes kf-pzoom{from{opacity:0;transform:perspective(1400px) translateZ(-400px) rotateX(12deg)}
|
||||
to{opacity:1;transform:none}}
|
||||
.anim-perspective-zoom{animation:kf-pzoom 1s var(--anim-ease) both}
|
||||
|
||||
/* ---------- MARQUEE SCROLL ---------- */
|
||||
.anim-marquee-scroll{display:flex;gap:48px;white-space:nowrap;animation:kf-marquee 20s linear infinite}
|
||||
@keyframes kf-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
|
||||
|
||||
/* ---------- KEN BURNS ---------- */
|
||||
@keyframes kf-kenburns{0%{transform:scale(1) translate(0,0)}100%{transform:scale(1.15) translate(-2%,-1%)}}
|
||||
.anim-kenburns{animation:kf-kenburns 14s ease-in-out infinite alternate}
|
||||
|
||||
/* ---------- CONFETTI BURST (pseudo — pure CSS sparkles) ---------- */
|
||||
.anim-confetti-burst{position:relative}
|
||||
.anim-confetti-burst::before,.anim-confetti-burst::after{
|
||||
content:"";position:absolute;top:50%;left:50%;width:8px;height:8px;border-radius:50%;
|
||||
background:var(--accent);box-shadow:
|
||||
20px -30px 0 var(--accent-2,var(--accent)),-25px -20px 0 var(--accent-3,var(--accent)),
|
||||
30px 20px 0 var(--good,#1aaf6c),-30px 25px 0 var(--warn,#f5a524),
|
||||
40px -10px 0 var(--bad,#e0445a),-45px 0 0 var(--accent),
|
||||
10px 40px 0 var(--accent-2,var(--accent)),-15px -40px 0 var(--accent-3,var(--accent));
|
||||
opacity:0;animation:kf-confetti 1.2s var(--anim-ease) forwards}
|
||||
.anim-confetti-burst::after{animation-delay:.15s;transform:rotate(45deg)}
|
||||
@keyframes kf-confetti{0%{opacity:0;transform:scale(.2)}30%{opacity:1}100%{opacity:0;transform:scale(2.2)}}
|
||||
|
||||
/* ---------- SPOTLIGHT ---------- */
|
||||
@keyframes kf-spot{0%{clip-path:circle(0% at 50% 50%)}100%{clip-path:circle(140% at 50% 50%)}}
|
||||
.anim-spotlight{animation:kf-spot 1.1s var(--anim-ease) both}
|
||||
|
||||
/* ---------- MORPH SHAPE (SVG) ---------- */
|
||||
.anim-morph-shape path{animation:kf-morph 6s ease-in-out infinite alternate}
|
||||
@keyframes kf-morph{0%{d:path("M60,120 Q120,20 180,120 T300,120")}
|
||||
100%{d:path("M60,120 Q120,220 180,120 T300,120")}}
|
||||
|
||||
/* ---------- RIPPLE REVEAL ---------- */
|
||||
@keyframes kf-ripple{0%{clip-path:circle(0% at 20% 80%);opacity:.4}
|
||||
100%{clip-path:circle(160% at 20% 80%);opacity:1}}
|
||||
.anim-ripple-reveal{animation:kf-ripple 1.2s var(--anim-ease) both}
|
||||
|
||||
/* reduced motion */
|
||||
@media (prefers-reduced-motion: reduce){
|
||||
[class*="anim-"]{animation:none!important;transition:none!important}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* html-ppt :: fx-runtime.js
|
||||
* Canvas FX autoloader + lifecycle manager.
|
||||
* - Dynamically loads all fx modules listed in FX_LIST
|
||||
* - Initializes [data-fx] elements when their slide becomes active
|
||||
* - Calls handle.stop() when the slide leaves
|
||||
*/
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
const FX_LIST = [
|
||||
'_util',
|
||||
'particle-burst','confetti-cannon','firework','starfield','matrix-rain',
|
||||
'knowledge-graph','neural-net','constellation','orbit-ring','galaxy-swirl',
|
||||
'word-cascade','letter-explode','chain-react','magnetic-field','data-stream',
|
||||
'gradient-blob','sparkle-trail','shockwave','typewriter-multi','counter-explosion'
|
||||
];
|
||||
|
||||
// Resolve base path of this script so it works from any page location.
|
||||
const myScript = document.currentScript || (function(){
|
||||
const all = document.getElementsByTagName('script');
|
||||
for (const s of all){ if (s.src && s.src.indexOf('fx-runtime.js')>-1) return s; }
|
||||
return null;
|
||||
})();
|
||||
const base = myScript ? myScript.src.replace(/fx-runtime\.js.*$/, 'fx/') : 'assets/animations/fx/';
|
||||
|
||||
let loaded = 0;
|
||||
const total = FX_LIST.length;
|
||||
const ready = new Promise((resolve) => {
|
||||
if (!total) return resolve();
|
||||
FX_LIST.forEach((name) => {
|
||||
const s = document.createElement('script');
|
||||
s.src = base + name + '.js';
|
||||
s.async = false;
|
||||
s.onload = s.onerror = () => { if (++loaded >= total) resolve(); };
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
});
|
||||
|
||||
window.__hpxActive = window.__hpxActive || new Map();
|
||||
|
||||
function initFxIn(root){
|
||||
if (!window.HPX) return;
|
||||
const els = root.querySelectorAll('[data-fx]');
|
||||
els.forEach((el) => {
|
||||
if (window.__hpxActive.has(el)) return;
|
||||
const name = el.getAttribute('data-fx');
|
||||
const fn = window.HPX[name];
|
||||
if (typeof fn !== 'function') return;
|
||||
try {
|
||||
const handle = fn(el, {}) || { stop(){} };
|
||||
window.__hpxActive.set(el, handle);
|
||||
} catch(e){ console.warn('[hpx-fx]', name, e); }
|
||||
});
|
||||
}
|
||||
|
||||
function stopFxIn(root){
|
||||
const els = root.querySelectorAll('[data-fx]');
|
||||
els.forEach((el) => {
|
||||
const h = window.__hpxActive.get(el);
|
||||
if (h && typeof h.stop === 'function'){
|
||||
try{ h.stop(); }catch(e){}
|
||||
}
|
||||
window.__hpxActive.delete(el);
|
||||
});
|
||||
}
|
||||
|
||||
function reinitFxIn(root){
|
||||
stopFxIn(root);
|
||||
initFxIn(root);
|
||||
}
|
||||
window.__hpxReinit = reinitFxIn;
|
||||
|
||||
function boot(){
|
||||
ready.then(() => {
|
||||
const active = document.querySelector('.slide.is-active') || document.querySelector('.slide');
|
||||
if (active) initFxIn(active);
|
||||
|
||||
// Watch all slides for class changes
|
||||
const slides = document.querySelectorAll('.slide');
|
||||
slides.forEach((sl) => {
|
||||
const mo = new MutationObserver((muts) => {
|
||||
for (const m of muts){
|
||||
if (m.attributeName === 'class'){
|
||||
if (sl.classList.contains('is-active')) initFxIn(sl);
|
||||
else stopFxIn(sl);
|
||||
}
|
||||
}
|
||||
});
|
||||
mo.observe(sl, { attributes: true, attributeFilter: ['class'] });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading'){
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,63 @@
|
||||
/* html-ppt fx :: shared helpers */
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
const U = window.HPX._u = {};
|
||||
|
||||
U.css = (el, name, fb) => {
|
||||
const v = getComputedStyle(el).getPropertyValue(name).trim();
|
||||
return v || fb;
|
||||
};
|
||||
|
||||
U.accent = (el, fb) => U.css(el, '--accent', fb || '#7c5cff');
|
||||
U.accent2 = (el, fb) => U.css(el, '--accent-2', fb || '#22d3ee');
|
||||
U.text = (el, fb) => U.css(el, '--text-1', fb || '#eaeaf2');
|
||||
|
||||
U.palette = (el) => [
|
||||
U.accent(el, '#7c5cff'),
|
||||
U.accent2(el, '#22d3ee'),
|
||||
U.css(el, '--ok', '#22c55e'),
|
||||
U.css(el, '--warn', '#f59e0b'),
|
||||
U.css(el, '--danger', '#ef4444'),
|
||||
];
|
||||
|
||||
U.canvas = (el) => {
|
||||
if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
|
||||
const c = document.createElement('canvas');
|
||||
c.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;pointer-events:none;display:block;';
|
||||
el.appendChild(c);
|
||||
const ctx = c.getContext('2d');
|
||||
let w = 0, h = 0, dpr = Math.max(1, Math.min(2, window.devicePixelRatio||1));
|
||||
const fit = () => {
|
||||
const r = el.getBoundingClientRect();
|
||||
w = Math.max(1, r.width|0);
|
||||
h = Math.max(1, r.height|0);
|
||||
c.width = (w*dpr)|0;
|
||||
c.height = (h*dpr)|0;
|
||||
ctx.setTransform(dpr,0,0,dpr,0,0);
|
||||
};
|
||||
fit();
|
||||
const ro = new ResizeObserver(fit);
|
||||
ro.observe(el);
|
||||
return {
|
||||
c, ctx,
|
||||
get w(){return w;}, get h(){return h;}, get dpr(){return dpr;},
|
||||
destroy(){
|
||||
try{ro.disconnect();}catch(e){}
|
||||
if (c.parentNode) c.parentNode.removeChild(c);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
U.loop = (fn) => {
|
||||
let raf = 0, stopped = false, t0 = performance.now();
|
||||
const tick = (t) => {
|
||||
if (stopped) return;
|
||||
fn((t - t0)/1000);
|
||||
raf = requestAnimationFrame(tick);
|
||||
};
|
||||
raf = requestAnimationFrame(tick);
|
||||
return () => { stopped = true; cancelAnimationFrame(raf); };
|
||||
};
|
||||
|
||||
U.rand = (a,b) => a + Math.random()*(b-a);
|
||||
})();
|
||||
@@ -0,0 +1,41 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['chain-react'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const ac = U.accent(el,'#7c5cff'), ac2 = U.accent2(el,'#22d3ee');
|
||||
const N = 8;
|
||||
const stop = U.loop((t) => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
const cy = k.h/2;
|
||||
const pad = 60;
|
||||
const dx = (k.w - pad*2)/(N-1);
|
||||
const period = 2.4;
|
||||
const phase = (t % period) / period; // 0..1
|
||||
for (let i=0;i<N;i++){
|
||||
const x = pad + i*dx;
|
||||
const my = i/(N-1);
|
||||
const d = Math.abs(phase - my);
|
||||
const pulse = Math.max(0, 1 - d*6);
|
||||
const r = 18 + pulse*18;
|
||||
// glow
|
||||
const g = ctx.createRadialGradient(x,cy,0,x,cy,r*2);
|
||||
g.addColorStop(0, `rgba(124,92,255,${0.4*pulse})`);
|
||||
g.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
ctx.fillStyle = g;
|
||||
ctx.fillRect(x-r*2, cy-r*2, r*4, r*4);
|
||||
// circle
|
||||
ctx.fillStyle = pulse>0.1 ? ac2 : ac;
|
||||
ctx.beginPath(); ctx.arc(x,cy,r,0,Math.PI*2); ctx.fill();
|
||||
ctx.strokeStyle='rgba(255,255,255,0.4)'; ctx.lineWidth=2;
|
||||
ctx.stroke();
|
||||
// connectors
|
||||
if (i<N-1){
|
||||
ctx.strokeStyle='rgba(200,200,230,0.3)'; ctx.lineWidth=2;
|
||||
ctx.beginPath(); ctx.moveTo(x+r,cy); ctx.lineTo(x+dx-r,cy); ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,49 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['confetti-cannon'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
let parts = [];
|
||||
const fire = () => {
|
||||
for (let side=0; side<2; side++){
|
||||
const x0 = side===0 ? 20 : k.w-20;
|
||||
const y0 = k.h - 20;
|
||||
for (let i=0;i<40;i++){
|
||||
const a = side===0 ? U.rand(-Math.PI*0.7, -Math.PI*0.4) : U.rand(-Math.PI*0.6, -Math.PI*0.3) - Math.PI/2 - Math.PI/6;
|
||||
const spd = U.rand(300, 520);
|
||||
parts.push({
|
||||
x: x0, y: y0,
|
||||
vx: Math.cos(a)*spd, vy: Math.sin(a)*spd,
|
||||
w: U.rand(6,12), h: U.rand(3,7),
|
||||
rot: Math.random()*Math.PI, vr: U.rand(-6,6),
|
||||
c: pal[(Math.random()*pal.length)|0],
|
||||
life: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
fire();
|
||||
let last = 0;
|
||||
const stop = U.loop((t) => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
if (t - last > 3) { fire(); last = t; }
|
||||
const dt = 1/60;
|
||||
parts = parts.filter(p => p.life > 0 && p.y < k.h+40);
|
||||
for (const p of parts){
|
||||
p.vy += 520*dt;
|
||||
p.x += p.vx*dt; p.y += p.vy*dt;
|
||||
p.rot += p.vr*dt;
|
||||
p.life -= 0.006;
|
||||
ctx.save();
|
||||
ctx.translate(p.x, p.y); ctx.rotate(p.rot);
|
||||
ctx.globalAlpha = Math.max(0, p.life);
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.fillRect(-p.w/2, -p.h/2, p.w, p.h);
|
||||
ctx.restore();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,44 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['constellation'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const ac = U.accent(el,'#9fb4ff');
|
||||
const N = 70;
|
||||
let pts = [];
|
||||
const seed = () => {
|
||||
pts = Array.from({length:N}, () => ({
|
||||
x: Math.random()*k.w, y: Math.random()*k.h,
|
||||
vx: U.rand(-0.3,0.3), vy: U.rand(-0.3,0.3)
|
||||
}));
|
||||
};
|
||||
seed();
|
||||
let lw=k.w, lh=k.h;
|
||||
const stop = U.loop(() => {
|
||||
if (k.w!==lw||k.h!==lh){ seed(); lw=k.w; lh=k.h; }
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
for (const p of pts){
|
||||
p.x += p.vx; p.y += p.vy;
|
||||
if (p.x<0||p.x>k.w) p.vx*=-1;
|
||||
if (p.y<0||p.y>k.h) p.vy*=-1;
|
||||
}
|
||||
for (let i=0;i<N;i++){
|
||||
for (let j=i+1;j<N;j++){
|
||||
const a=pts[i], b=pts[j];
|
||||
const d = Math.hypot(a.x-b.x, a.y-b.y);
|
||||
if (d < 150){
|
||||
ctx.globalAlpha = 1 - d/150;
|
||||
ctx.strokeStyle = ac; ctx.lineWidth=1;
|
||||
ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.fillStyle = ac;
|
||||
for (const p of pts){
|
||||
ctx.beginPath(); ctx.arc(p.x,p.y,1.8,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,58 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['counter-explosion'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
|
||||
const target = parseInt(el.getAttribute('data-fx-to') || '2400', 10);
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
// number overlay
|
||||
const num = document.createElement('div');
|
||||
num.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font:900 120px system-ui,sans-serif;color:var(--text-1,#fff);pointer-events:none;text-shadow:0 4px 40px rgba(124,92,255,0.5);';
|
||||
num.textContent = '0';
|
||||
el.appendChild(num);
|
||||
let parts = [];
|
||||
let state = 'count'; // count | burst | hold
|
||||
let stateT = 0;
|
||||
let value = 0;
|
||||
let cycle = 0;
|
||||
const burst = () => {
|
||||
const cx = k.w/2, cy = k.h/2;
|
||||
for (let i=0;i<120;i++){
|
||||
const a = Math.random()*Math.PI*2;
|
||||
const s = U.rand(120, 400);
|
||||
parts.push({x:cx,y:cy,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:1,r:U.rand(2,5),c:pal[(Math.random()*pal.length)|0]});
|
||||
}
|
||||
};
|
||||
const stop = U.loop(() => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
const dt = 1/60;
|
||||
stateT += dt;
|
||||
if (state === 'count'){
|
||||
const dur = 2.2;
|
||||
const p = Math.min(1, stateT/dur);
|
||||
const eased = 1 - Math.pow(1-p,3);
|
||||
value = Math.round(target*eased);
|
||||
num.textContent = value.toLocaleString();
|
||||
if (p >= 1){ state='burst'; stateT=0; burst(); }
|
||||
} else if (state === 'burst'){
|
||||
if (stateT > 0.05 && stateT < 0.3 && parts.length < 200) {}
|
||||
if (stateT > 2.5){ state='hold'; stateT=0; }
|
||||
} else if (state === 'hold'){
|
||||
if (stateT > 1.5){
|
||||
state='count'; stateT=0; value=0; num.textContent='0'; cycle++;
|
||||
}
|
||||
}
|
||||
parts = parts.filter(p => p.life > 0);
|
||||
for (const p of parts){
|
||||
p.vy += 260*dt; p.vx *= 0.985; p.vy *= 0.985;
|
||||
p.x += p.vx*dt; p.y += p.vy*dt; p.life -= 0.01;
|
||||
ctx.globalAlpha = Math.max(0,p.life);
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); if (num.parentNode) num.parentNode.removeChild(num); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,45 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['data-stream'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const ac = U.accent(el,'#22d3ee'), ac2 = U.accent2(el,'#7c5cff');
|
||||
const rows = [];
|
||||
const rh = 22;
|
||||
const genRow = (y) => ({
|
||||
y, dir: Math.random()<0.5?-1:1,
|
||||
speed: U.rand(30, 90),
|
||||
offset: Math.random()*2000,
|
||||
text: Array.from({length:120}, () => {
|
||||
const r = Math.random();
|
||||
if (r<0.3) return Math.random()<0.5?'0':'1';
|
||||
if (r<0.6) return '0x' + Math.floor(Math.random()*256).toString(16).padStart(2,'0');
|
||||
return Math.random().toString(16).slice(2,6);
|
||||
}).join(' ')
|
||||
});
|
||||
const init = () => {
|
||||
rows.length = 0;
|
||||
const n = Math.ceil(k.h/rh);
|
||||
for (let i=0;i<n;i++) rows.push(genRow(i*rh + rh*0.7));
|
||||
};
|
||||
init();
|
||||
let lh = k.h;
|
||||
const stop = U.loop((t) => {
|
||||
if (k.h!==lh){ init(); lh=k.h; }
|
||||
ctx.fillStyle = 'rgba(5,8,14,0.35)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
ctx.font = '13px ui-monospace,Menlo,monospace';
|
||||
for (let i=0;i<rows.length;i++){
|
||||
const r = rows[i];
|
||||
const x = r.dir>0
|
||||
? ((t*r.speed + r.offset) % (k.w+400)) - 400
|
||||
: k.w - (((t*r.speed + r.offset) % (k.w+400)) - 400);
|
||||
ctx.fillStyle = (i%3===0)?ac:ac2;
|
||||
ctx.globalAlpha = 0.65 + (i%2)*0.3;
|
||||
ctx.fillText(r.text, x, r.y);
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['firework'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
let rockets = [], sparks = [];
|
||||
const launch = () => {
|
||||
rockets.push({
|
||||
x: U.rand(k.w*0.2, k.w*0.8), y: k.h+10,
|
||||
vx: U.rand(-30,30), vy: U.rand(-520,-380),
|
||||
tgtY: U.rand(k.h*0.15, k.h*0.45),
|
||||
c: pal[(Math.random()*pal.length)|0]
|
||||
});
|
||||
};
|
||||
const burst = (x, y, c) => {
|
||||
const n = 70;
|
||||
for (let i=0;i<n;i++){
|
||||
const a = Math.random()*Math.PI*2;
|
||||
const s = U.rand(60, 240);
|
||||
sparks.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:1,c});
|
||||
}
|
||||
};
|
||||
let last = -1;
|
||||
const stop = U.loop((t) => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.18)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
if (t - last > 0.7) { launch(); last = t; }
|
||||
const dt = 1/60;
|
||||
rockets = rockets.filter(r => {
|
||||
r.x += r.vx*dt; r.y += r.vy*dt; r.vy += 260*dt;
|
||||
ctx.fillStyle = r.c;
|
||||
ctx.beginPath(); ctx.arc(r.x, r.y, 2.5, 0, Math.PI*2); ctx.fill();
|
||||
if (r.y <= r.tgtY || r.vy >= 0) { burst(r.x, r.y, r.c); return false; }
|
||||
return true;
|
||||
});
|
||||
sparks = sparks.filter(p => p.life > 0);
|
||||
for (const p of sparks){
|
||||
p.vy += 90*dt;
|
||||
p.vx *= 0.98; p.vy *= 0.98;
|
||||
p.x += p.vx*dt; p.y += p.vy*dt;
|
||||
p.life -= 0.012;
|
||||
ctx.globalAlpha = Math.max(0, p.life);
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.beginPath(); ctx.arc(p.x, p.y, 2, 0, Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,33 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['galaxy-swirl'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const N = 800;
|
||||
const parts = Array.from({length:N}, (_,i) => {
|
||||
const arm = i%3;
|
||||
const t = Math.random();
|
||||
const r = t*180 + 8;
|
||||
const base = (arm/3)*Math.PI*2;
|
||||
return { r, a: base + Math.log(r+1)*1.6 + U.rand(-0.2,0.2),
|
||||
c: pal[arm%pal.length],
|
||||
s: U.rand(0.8, 2.2) };
|
||||
});
|
||||
const stop = U.loop((t) => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.15)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
const cx=k.w/2, cy=k.h/2;
|
||||
for (const p of parts){
|
||||
const a = p.a + t*0.15;
|
||||
const x = cx + Math.cos(a)*p.r;
|
||||
const y = cy + Math.sin(a)*p.r*0.7;
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.globalAlpha = 0.7;
|
||||
ctx.beginPath(); ctx.arc(x,y,p.s,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['gradient-blob'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const blobs = Array.from({length:4}, (_,i) => ({
|
||||
x: U.rand(0,1), y: U.rand(0,1),
|
||||
vx: U.rand(-0.08,0.08), vy: U.rand(-0.08,0.08),
|
||||
r: U.rand(180,320),
|
||||
c: pal[i%pal.length]
|
||||
}));
|
||||
const hex2rgb = (h) => {
|
||||
const m = h.replace('#','').match(/.{2}/g);
|
||||
if (!m) return [124,92,255];
|
||||
return m.map(x=>parseInt(x,16));
|
||||
};
|
||||
const stop = U.loop((t) => {
|
||||
ctx.fillStyle = 'rgba(10,12,22,0.2)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
ctx.globalCompositeOperation = 'lighter';
|
||||
for (const b of blobs){
|
||||
b.x += b.vx*0.01; b.y += b.vy*0.01;
|
||||
if (b.x<0||b.x>1) b.vx*=-1;
|
||||
if (b.y<0||b.y>1) b.vy*=-1;
|
||||
const px = b.x*k.w, py = b.y*k.h;
|
||||
const r = b.r + Math.sin(t*0.8 + b.x*6)*30;
|
||||
const [R,G,B] = hex2rgb(b.c);
|
||||
const grad = ctx.createRadialGradient(px,py,0,px,py,r);
|
||||
grad.addColorStop(0, `rgba(${R},${G},${B},0.55)`);
|
||||
grad.addColorStop(1, `rgba(${R},${G},${B},0)`);
|
||||
ctx.fillStyle = grad;
|
||||
ctx.beginPath(); ctx.arc(px,py,r,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,69 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['knowledge-graph'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const tx = U.text(el, '#e7e7ef');
|
||||
const labels = ['AI','ML','LLM','Graph','Node','Edge','Claude','GPT','RAG','Vector',
|
||||
'Embed','Neural','Agent','Tool','Memory','Logic','Data','Train','Infer','Token',
|
||||
'Prompt','Chain','Plan','Skill','Cloud','Edge','GPU','Code','Task','Flow'];
|
||||
const N = 28;
|
||||
const nodes = Array.from({length:N}, (_,i) => ({
|
||||
x: U.rand(40, 300), y: U.rand(40, 200),
|
||||
vx: 0, vy: 0, label: labels[i%labels.length],
|
||||
c: pal[i%pal.length]
|
||||
}));
|
||||
const edges = [];
|
||||
const made = new Set();
|
||||
while (edges.length < 50){
|
||||
const a = (Math.random()*N)|0, b = (Math.random()*N)|0;
|
||||
if (a===b) continue;
|
||||
const key = a<b ? a+'-'+b : b+'-'+a;
|
||||
if (made.has(key)) continue;
|
||||
made.add(key); edges.push([a,b]);
|
||||
}
|
||||
const stop = U.loop(() => {
|
||||
// physics
|
||||
for (let i=0;i<N;i++){
|
||||
for (let j=i+1;j<N;j++){
|
||||
const a=nodes[i], b=nodes[j];
|
||||
const dx=b.x-a.x, dy=b.y-a.y;
|
||||
let d2=dx*dx+dy*dy; if (d2<1) d2=1;
|
||||
const d=Math.sqrt(d2);
|
||||
const f=1600/d2;
|
||||
const fx=(dx/d)*f, fy=(dy/d)*f;
|
||||
a.vx-=fx; a.vy-=fy; b.vx+=fx; b.vy+=fy;
|
||||
}
|
||||
}
|
||||
for (const [i,j] of edges){
|
||||
const a=nodes[i], b=nodes[j];
|
||||
const dx=b.x-a.x, dy=b.y-a.y, d=Math.hypot(dx,dy)||1;
|
||||
const f=(d-90)*0.008;
|
||||
const fx=(dx/d)*f, fy=(dy/d)*f;
|
||||
a.vx+=fx; a.vy+=fy; b.vx-=fx; b.vy-=fy;
|
||||
}
|
||||
const cx=k.w/2, cy=k.h/2;
|
||||
for (const n of nodes){
|
||||
n.vx += (cx-n.x)*0.002;
|
||||
n.vy += (cy-n.y)*0.002;
|
||||
n.vx *= 0.85; n.vy *= 0.85;
|
||||
n.x += n.vx; n.y += n.vy;
|
||||
}
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
ctx.strokeStyle = 'rgba(180,180,220,0.25)'; ctx.lineWidth=1;
|
||||
for (const [i,j] of edges){
|
||||
const a=nodes[i], b=nodes[j];
|
||||
ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.stroke();
|
||||
}
|
||||
ctx.font='11px system-ui,sans-serif'; ctx.textAlign='center'; ctx.textBaseline='middle';
|
||||
for (const n of nodes){
|
||||
ctx.fillStyle = n.c;
|
||||
ctx.beginPath(); ctx.arc(n.x,n.y,7,0,Math.PI*2); ctx.fill();
|
||||
ctx.fillStyle = tx;
|
||||
ctx.fillText(n.label, n.x, n.y-14);
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,50 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['letter-explode'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
|
||||
const src = el.querySelector('[data-fx-text]') || el;
|
||||
const text = (el.getAttribute('data-fx-text-value') || src.textContent || 'EXPLODE').trim();
|
||||
// Build a container, hide source text
|
||||
const wrap = document.createElement('div');
|
||||
wrap.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;';
|
||||
const inner = document.createElement('div');
|
||||
inner.style.cssText = 'font-size:64px;font-weight:900;letter-spacing:0.02em;color:var(--text-1,#fff);white-space:nowrap;';
|
||||
wrap.appendChild(inner);
|
||||
el.appendChild(wrap);
|
||||
const spans = [];
|
||||
for (const ch of text){
|
||||
const s = document.createElement('span');
|
||||
s.textContent = ch === ' ' ? '\u00A0' : ch;
|
||||
s.style.display='inline-block';
|
||||
s.style.transform='translate(0,0)';
|
||||
s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms';
|
||||
s.style.opacity='0';
|
||||
inner.appendChild(s);
|
||||
spans.push(s);
|
||||
}
|
||||
let stopped = false;
|
||||
const run = () => {
|
||||
if (stopped) return;
|
||||
spans.forEach((s,i) => {
|
||||
const dx = U.rand(-400, 400), dy = U.rand(-300, 300);
|
||||
s.style.transition='none';
|
||||
s.style.transform=`translate(${dx}px,${dy}px) rotate(${U.rand(-180,180)}deg)`;
|
||||
s.style.opacity='0';
|
||||
});
|
||||
// force reflow
|
||||
void inner.offsetWidth;
|
||||
spans.forEach((s,i) => {
|
||||
setTimeout(() => {
|
||||
if (stopped) return;
|
||||
s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms';
|
||||
s.style.transform='translate(0,0) rotate(0deg)';
|
||||
s.style.opacity='1';
|
||||
}, i*35);
|
||||
});
|
||||
};
|
||||
run();
|
||||
const iv = setInterval(run, 4500);
|
||||
return { stop(){ stopped=true; clearInterval(iv); if (wrap.parentNode) wrap.parentNode.removeChild(wrap); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,40 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['magnetic-field'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const N = 60;
|
||||
const parts = Array.from({length:N}, (_,i) => ({
|
||||
phase: Math.random()*Math.PI*2,
|
||||
freq: U.rand(0.4, 1.2),
|
||||
amp: U.rand(30, 90),
|
||||
y0: U.rand(0.15, 0.85),
|
||||
c: pal[i%pal.length],
|
||||
trail: []
|
||||
}));
|
||||
const stop = U.loop((t) => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.08)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
for (const p of parts){
|
||||
const x = ((t*80 + p.phase*50) % (k.w+100)) - 50;
|
||||
const y = k.h*p.y0 + Math.sin(x*0.02 + p.phase + t*p.freq)*p.amp;
|
||||
p.trail.push([x,y]);
|
||||
if (p.trail.length > 18) p.trail.shift();
|
||||
ctx.strokeStyle = p.c;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
for (let i=0;i<p.trail.length;i++){
|
||||
const [tx,ty] = p.trail[i];
|
||||
if (i===0) ctx.moveTo(tx,ty); else ctx.lineTo(tx,ty);
|
||||
}
|
||||
ctx.globalAlpha = 0.7;
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.beginPath(); ctx.arc(x,y,2.5,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,33 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['matrix-rain'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const glyphs = 'アイウエオカキクケコサシスセソタチツテトナニヌネノ0123456789ABCDEF'.split('');
|
||||
const fs = 16;
|
||||
let cols = 0, drops = [];
|
||||
const init = () => {
|
||||
cols = Math.ceil(k.w/fs);
|
||||
drops = Array.from({length:cols}, () => U.rand(-20, 0));
|
||||
};
|
||||
init();
|
||||
let lw = k.w, lh = k.h;
|
||||
const stop = U.loop(() => {
|
||||
if (k.w!==lw || k.h!==lh){ init(); lw=k.w; lh=k.h; }
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.08)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
ctx.font = fs+'px monospace';
|
||||
for (let i=0;i<cols;i++){
|
||||
const ch = glyphs[(Math.random()*glyphs.length)|0];
|
||||
const x = i*fs, y = drops[i]*fs;
|
||||
ctx.fillStyle = '#9fffc9';
|
||||
ctx.fillText(ch, x, y);
|
||||
ctx.fillStyle = '#00ff6a';
|
||||
ctx.fillText(ch, x, y - fs);
|
||||
drops[i] += 1;
|
||||
if (y > k.h && Math.random() > 0.975) drops[i] = 0;
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,75 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['neural-net'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const ac = U.accent(el,'#7c5cff'), ac2 = U.accent2(el,'#22d3ee');
|
||||
const layers = [4,6,6,3];
|
||||
let nodes = [], edges = [], pulses = [];
|
||||
const layout = () => {
|
||||
nodes = [];
|
||||
const pad = 40;
|
||||
const cw = k.w - pad*2, ch = k.h - pad*2;
|
||||
for (let L=0; L<layers.length; L++){
|
||||
const x = pad + (cw * L / (layers.length-1));
|
||||
const n = layers[L];
|
||||
for (let i=0;i<n;i++){
|
||||
const y = pad + (ch * (i+0.5) / n);
|
||||
nodes.push({x,y,L,i});
|
||||
}
|
||||
}
|
||||
edges = [];
|
||||
for (let L=0; L<layers.length-1; L++){
|
||||
const a = nodes.filter(n=>n.L===L), b = nodes.filter(n=>n.L===L+1);
|
||||
for (const x of a) for (const y of b) edges.push([nodes.indexOf(x),nodes.indexOf(y)]);
|
||||
}
|
||||
};
|
||||
layout();
|
||||
let lw=k.w, lh=k.h, last=0;
|
||||
const stop = U.loop((t) => {
|
||||
if (k.w!==lw||k.h!==lh){ layout(); lw=k.w; lh=k.h; }
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
ctx.strokeStyle = 'rgba(160,160,200,0.22)'; ctx.lineWidth=1;
|
||||
for (const [i,j] of edges){
|
||||
const a=nodes[i], b=nodes[j];
|
||||
ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.stroke();
|
||||
}
|
||||
if (t - last > 0.25){
|
||||
last = t;
|
||||
const starts = nodes.filter(n=>n.L===0);
|
||||
const s = starts[(Math.random()*starts.length)|0];
|
||||
pulses.push({node:s, L:0, t:0});
|
||||
}
|
||||
pulses = pulses.filter(p => p.L < layers.length-1);
|
||||
for (const p of pulses){
|
||||
p.t += 0.03;
|
||||
if (p.t >= 1){
|
||||
const next = nodes.filter(n=>n.L===p.L+1);
|
||||
p.node2 = next[(Math.random()*next.length)|0];
|
||||
if (!p._started){ p._started = true; }
|
||||
}
|
||||
}
|
||||
// animate progression
|
||||
for (const p of pulses){
|
||||
if (!p.target){
|
||||
const next = nodes.filter(n=>n.L===p.L+1);
|
||||
p.target = next[(Math.random()*next.length)|0];
|
||||
}
|
||||
p.t += 0.04;
|
||||
const a = p.node, b = p.target;
|
||||
const x = a.x + (b.x-a.x)*Math.min(1,p.t);
|
||||
const y = a.y + (b.y-a.y)*Math.min(1,p.t);
|
||||
ctx.fillStyle = ac2;
|
||||
ctx.beginPath(); ctx.arc(x,y,4,0,Math.PI*2); ctx.fill();
|
||||
if (p.t >= 1){ p.node = b; p.target=null; p.L++; p.t=0; }
|
||||
}
|
||||
for (const n of nodes){
|
||||
ctx.fillStyle = ac;
|
||||
ctx.beginPath(); ctx.arc(n.x,n.y,6,0,Math.PI*2); ctx.fill();
|
||||
ctx.strokeStyle = ac2; ctx.lineWidth=1.5;
|
||||
ctx.beginPath(); ctx.arc(n.x,n.y,8,0,Math.PI*2); ctx.stroke();
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,38 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['orbit-ring'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const rings = [
|
||||
{r:40, n:3, sp:1.2, c:pal[0]},
|
||||
{r:75, n:5, sp:0.8, c:pal[1]},
|
||||
{r:110, n:8, sp:-0.6, c:pal[2]},
|
||||
{r:145, n:12, sp:0.4, c:pal[3]},
|
||||
{r:180, n:16, sp:-0.3, c:pal[4]}
|
||||
];
|
||||
const stop = U.loop((t) => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
const cx=k.w/2, cy=k.h/2;
|
||||
// radial glow
|
||||
const g = ctx.createRadialGradient(cx,cy,0,cx,cy,210);
|
||||
g.addColorStop(0,'rgba(124,92,255,0.25)');
|
||||
g.addColorStop(1,'rgba(0,0,0,0)');
|
||||
ctx.fillStyle = g; ctx.fillRect(0,0,k.w,k.h);
|
||||
for (const R of rings){
|
||||
ctx.strokeStyle = 'rgba(200,200,230,0.2)'; ctx.lineWidth=1;
|
||||
ctx.beginPath(); ctx.arc(cx,cy,R.r,0,Math.PI*2); ctx.stroke();
|
||||
for (let i=0;i<R.n;i++){
|
||||
const a = (i/R.n)*Math.PI*2 + t*R.sp;
|
||||
const x = cx + Math.cos(a)*R.r;
|
||||
const y = cy + Math.sin(a)*R.r;
|
||||
ctx.fillStyle = R.c;
|
||||
ctx.beginPath(); ctx.arc(x,y,4,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
}
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.beginPath(); ctx.arc(cx,cy,5,0,Math.PI*2); ctx.fill();
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,42 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['particle-burst'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
let parts = [];
|
||||
const spawn = () => {
|
||||
const cx = k.w/2, cy = k.h/2;
|
||||
const n = 90;
|
||||
for (let i=0;i<n;i++){
|
||||
const a = Math.random()*Math.PI*2;
|
||||
const s = U.rand(80, 260);
|
||||
parts.push({
|
||||
x: cx, y: cy,
|
||||
vx: Math.cos(a)*s, vy: Math.sin(a)*s,
|
||||
life: 1, r: U.rand(2,5),
|
||||
c: pal[(Math.random()*pal.length)|0]
|
||||
});
|
||||
}
|
||||
};
|
||||
spawn();
|
||||
let lastSpawn = 0;
|
||||
const stop = U.loop((t) => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
if (t - lastSpawn > 2.5) { spawn(); lastSpawn = t; }
|
||||
const dt = 1/60;
|
||||
parts = parts.filter(p => p.life > 0);
|
||||
for (const p of parts){
|
||||
p.vy += 220*dt;
|
||||
p.vx *= 0.985; p.vy *= 0.985;
|
||||
p.x += p.vx*dt; p.y += p.vy*dt;
|
||||
p.life -= 0.012;
|
||||
ctx.globalAlpha = Math.max(0, p.life);
|
||||
ctx.fillStyle = p.c;
|
||||
ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['shockwave'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const ac = U.accent(el,'#7c5cff'), ac2 = U.accent2(el,'#22d3ee');
|
||||
let waves = [];
|
||||
let last = -1;
|
||||
const stop = U.loop((t) => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.12)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
if (t - last > 0.6){ last = t; waves.push({t:0}); }
|
||||
const cx=k.w/2, cy=k.h/2;
|
||||
const max = Math.hypot(k.w,k.h)/2;
|
||||
waves = waves.filter(w => w.t < 1);
|
||||
for (const w of waves){
|
||||
w.t += 0.012;
|
||||
const r = w.t * max;
|
||||
const alpha = 1 - w.t;
|
||||
ctx.strokeStyle = w.t<0.5?ac2:ac;
|
||||
ctx.globalAlpha = alpha;
|
||||
ctx.lineWidth = 3 + (1-w.t)*3;
|
||||
ctx.beginPath(); ctx.arc(cx,cy,r,0,Math.PI*2); ctx.stroke();
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.globalAlpha = alpha*0.4;
|
||||
ctx.beginPath(); ctx.arc(cx,cy,r*0.92,0,Math.PI*2); ctx.stroke();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
// core
|
||||
const g = ctx.createRadialGradient(cx,cy,0,cx,cy,40);
|
||||
g.addColorStop(0,'rgba(255,255,255,0.9)');
|
||||
g.addColorStop(1,'rgba(124,92,255,0)');
|
||||
ctx.fillStyle = g;
|
||||
ctx.beginPath(); ctx.arc(cx,cy,40,0,Math.PI*2); ctx.fill();
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,62 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['sparkle-trail'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
k.c.style.pointerEvents = 'none';
|
||||
el.style.cursor = 'crosshair';
|
||||
const pal = U.palette(el);
|
||||
let sparks = [];
|
||||
const onMove = (e) => {
|
||||
const r = el.getBoundingClientRect();
|
||||
const x = e.clientX - r.left, y = e.clientY - r.top;
|
||||
for (let i=0;i<3;i++){
|
||||
sparks.push({
|
||||
x, y,
|
||||
vx: U.rand(-60,60), vy: U.rand(-80,20),
|
||||
life: 1, c: pal[(Math.random()*pal.length)|0],
|
||||
r: U.rand(1.5,3.5)
|
||||
});
|
||||
}
|
||||
};
|
||||
// auto-wiggle if no mouse moves
|
||||
let auto = true, autoT = 0;
|
||||
const onAny = () => { auto = false; };
|
||||
el.addEventListener('pointermove', onMove);
|
||||
el.addEventListener('pointerenter', onAny);
|
||||
const stop = U.loop(() => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.15)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
if (auto){
|
||||
autoT += 0.04;
|
||||
const x = k.w/2 + Math.cos(autoT)*k.w*0.3;
|
||||
const y = k.h/2 + Math.sin(autoT*1.3)*k.h*0.3;
|
||||
for (let i=0;i<3;i++){
|
||||
sparks.push({
|
||||
x, y,
|
||||
vx: U.rand(-60,60), vy: U.rand(-80,20),
|
||||
life: 1, c: pal[(Math.random()*pal.length)|0],
|
||||
r: U.rand(1.5,3.5)
|
||||
});
|
||||
}
|
||||
}
|
||||
const dt = 1/60;
|
||||
sparks = sparks.filter(s => s.life > 0);
|
||||
for (const s of sparks){
|
||||
s.vy += 160*dt;
|
||||
s.x += s.vx*dt; s.y += s.vy*dt;
|
||||
s.life -= 0.018;
|
||||
ctx.globalAlpha = Math.max(0, s.life);
|
||||
ctx.fillStyle = s.c;
|
||||
ctx.beginPath(); ctx.arc(s.x,s.y,s.r,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){
|
||||
el.removeEventListener('pointermove', onMove);
|
||||
el.removeEventListener('pointerenter', onAny);
|
||||
el.style.cursor = '';
|
||||
stop(); k.destroy();
|
||||
}};
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,30 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['starfield'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const tx = U.text(el, '#ffffff');
|
||||
const N = 260;
|
||||
const stars = Array.from({length:N}, () => ({
|
||||
x: U.rand(-1,1), y: U.rand(-1,1), z: Math.random()
|
||||
}));
|
||||
const stop = U.loop(() => {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.25)';
|
||||
ctx.fillRect(0,0,k.w,k.h);
|
||||
const cx = k.w/2, cy = k.h/2;
|
||||
for (const s of stars){
|
||||
s.z -= 0.006;
|
||||
if (s.z <= 0.02) { s.x = U.rand(-1,1); s.y = U.rand(-1,1); s.z = 1; }
|
||||
const px = cx + (s.x/s.z)*cx;
|
||||
const py = cy + (s.y/s.z)*cy;
|
||||
if (px<0||py<0||px>k.w||py>k.h) continue;
|
||||
const r = (1-s.z)*2.4;
|
||||
ctx.globalAlpha = 1-s.z;
|
||||
ctx.fillStyle = tx;
|
||||
ctx.beginPath(); ctx.arc(px,py,r,0,Math.PI*2); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['typewriter-multi'] = function(el){
|
||||
if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
|
||||
const lines = [
|
||||
(el.getAttribute('data-fx-line1') || '> initializing knowledge graph...'),
|
||||
(el.getAttribute('data-fx-line2') || '> loading 28 concept nodes'),
|
||||
(el.getAttribute('data-fx-line3') || '> agent ready. awaiting prompt_'),
|
||||
];
|
||||
const wrap = document.createElement('div');
|
||||
wrap.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;gap:14px;padding:32px 48px;font:600 22px ui-monospace,Menlo,monospace;color:var(--text-1,#e7e7ef);';
|
||||
el.appendChild(wrap);
|
||||
const rows = lines.map((txt) => {
|
||||
const row = document.createElement('div');
|
||||
row.style.cssText = 'white-space:pre;display:flex;align-items:center;';
|
||||
const span = document.createElement('span'); span.textContent = '';
|
||||
const cur = document.createElement('span');
|
||||
cur.textContent = '\u2588';
|
||||
cur.style.cssText = 'display:inline-block;margin-left:2px;color:var(--accent,#22d3ee);animation:hpxBlink 1s steps(2) infinite;';
|
||||
row.appendChild(span); row.appendChild(cur);
|
||||
wrap.appendChild(row);
|
||||
return {row, span, txt, i:0};
|
||||
});
|
||||
// inject blink keyframes once
|
||||
if (!document.getElementById('hpx-blink-kf')){
|
||||
const st = document.createElement('style');
|
||||
st.id = 'hpx-blink-kf';
|
||||
st.textContent = '@keyframes hpxBlink{50%{opacity:0}}';
|
||||
document.head.appendChild(st);
|
||||
}
|
||||
let stopped = false;
|
||||
const speeds = [55, 70, 45];
|
||||
rows.forEach((r, idx) => {
|
||||
const tick = () => {
|
||||
if (stopped) return;
|
||||
if (r.i < r.txt.length){
|
||||
r.span.textContent += r.txt[r.i++];
|
||||
setTimeout(tick, speeds[idx]);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
if (stopped) return;
|
||||
r.i = 0; r.span.textContent = '';
|
||||
tick();
|
||||
}, 2200);
|
||||
}
|
||||
};
|
||||
setTimeout(tick, idx*400);
|
||||
});
|
||||
return { stop(){ stopped = true; if (wrap.parentNode) wrap.parentNode.removeChild(wrap); } };
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,47 @@
|
||||
(function(){
|
||||
window.HPX = window.HPX || {};
|
||||
window.HPX['word-cascade'] = function(el){
|
||||
const U = window.HPX._u;
|
||||
const k = U.canvas(el), ctx = k.ctx;
|
||||
const pal = U.palette(el);
|
||||
const WORDS = ['AI','知识','Graph','Claude','LLM','Agent','Vector','RAG','Token','神经',
|
||||
'Prompt','Chain','Skill','Code','Cloud','GPU','Flow','推理','Data','Model'];
|
||||
let items = [];
|
||||
let last = -1;
|
||||
let piles = {}; // column -> stack height
|
||||
const stop = U.loop((t) => {
|
||||
ctx.clearRect(0,0,k.w,k.h);
|
||||
if (t - last > 0.18){
|
||||
last = t;
|
||||
const w = WORDS[(Math.random()*WORDS.length)|0];
|
||||
items.push({
|
||||
text: w, x: U.rand(40, k.w-40), y: -20,
|
||||
vy: 0, c: pal[(Math.random()*pal.length)|0],
|
||||
size: U.rand(16,26), landed: false
|
||||
});
|
||||
}
|
||||
ctx.textAlign='center'; ctx.textBaseline='middle';
|
||||
for (const it of items){
|
||||
if (!it.landed){
|
||||
it.vy += 0.4;
|
||||
it.y += it.vy;
|
||||
const col = Math.round(it.x/60);
|
||||
const floor = k.h - (piles[col]||0) - it.size*0.6;
|
||||
if (it.y >= floor){
|
||||
it.y = floor; it.landed = true;
|
||||
piles[col] = (piles[col]||0) + it.size*1.1;
|
||||
if ((piles[col]||0) > k.h*0.8) piles[col] = 0; // reset if too high
|
||||
}
|
||||
}
|
||||
ctx.fillStyle = it.c;
|
||||
ctx.font = `700 ${it.size}px system-ui,sans-serif`;
|
||||
ctx.fillText(it.text, it.x, it.y);
|
||||
}
|
||||
// prune old landed
|
||||
if (items.length > 120){
|
||||
items = items.filter(i => !i.landed).concat(items.filter(i=>i.landed).slice(-60));
|
||||
}
|
||||
});
|
||||
return { stop(){ stop(); k.destroy(); } };
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user