Spaces:
Sleeping
Sleeping
animations
Browse files- .gitignore +4 -0
- cards.html +74 -3
.gitignore
CHANGED
|
@@ -1 +1,5 @@
|
|
| 1 |
__pycache__/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
__pycache__/
|
| 2 |
+
|
| 3 |
+
.venv/
|
| 4 |
+
__pycache__/
|
| 5 |
+
*.pyc
|
cards.html
CHANGED
|
@@ -133,12 +133,12 @@
|
|
| 133 |
.modal-backdrop::after { animation-duration: 16s; animation-direction: reverse; filter: blur(1px); opacity: 0.22; }
|
| 134 |
.modal {
|
| 135 |
width: min(1040px, 100%); max-height: 92vh; overflow: auto; border: 0;
|
| 136 |
-
background: transparent; border-radius: 28px; padding: 0;
|
| 137 |
color: var(--text); transform: translateY(18px) scale(0.96);
|
| 138 |
}
|
| 139 |
.modal-backdrop.open .modal { animation: modalDrop 0.52s cubic-bezier(.19,1,.22,1) forwards; }
|
| 140 |
.modal-shell {
|
| 141 |
-
position: relative; isolation: isolate;
|
| 142 |
display: grid; grid-template-columns: minmax(280px, 390px) minmax(320px, 1fr);
|
| 143 |
gap: 24px; align-items: stretch; padding: 22px;
|
| 144 |
border: 1px solid rgba(255,255,255,0.18); border-radius: 28px;
|
|
@@ -258,6 +258,44 @@
|
|
| 258 |
.sparkles i:nth-child(3) { left: 84%; top: 52%; animation-delay: .82s; }
|
| 259 |
.sparkles i:nth-child(4) { left: 24%; top: 72%; animation-delay: 1.1s; }
|
| 260 |
.sparkles i:nth-child(5) { left: 55%; top: 84%; animation-delay: 1.45s; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
.modal-info { display: flex; flex-direction: column; min-width: 0; }
|
| 262 |
.modal-copy {
|
| 263 |
margin-top: auto; padding: 14px; border-radius: 16px;
|
|
@@ -317,7 +355,7 @@
|
|
| 317 |
@media (prefers-reduced-motion: reduce) {
|
| 318 |
.modal-backdrop::before, .modal-backdrop::after, .modal-shell::before,
|
| 319 |
.modal-card-stage::before, .showcase-card, .showcase-card::before,
|
| 320 |
-
.showcase-art::before, .sparkles i { animation: none !important; }
|
| 321 |
}
|
| 322 |
|
| 323 |
.legend { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
@@ -737,6 +775,38 @@ function hashCode(s) {
|
|
| 737 |
return h;
|
| 738 |
}
|
| 739 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 740 |
function openModal(m) {
|
| 741 |
const rarity = rarityFor(m);
|
| 742 |
const { v, a } = aggregateVA(m.profile);
|
|
@@ -747,6 +817,7 @@ function openModal(m) {
|
|
| 747 |
const cardNo = String(Math.abs(hashCode(m.id)) % 999).padStart(3, "0");
|
| 748 |
|
| 749 |
document.getElementById("modal-content").innerHTML = `
|
|
|
|
| 750 |
<div class="modal-shell" style="--foil-a:${top[0].color}; --foil-b:${top[1].color}; --foil-c:${top[2].color}; --rarity-color:var(--r-${rarity});">
|
| 751 |
<div class="modal-card-stage">
|
| 752 |
<div class="showcase-card r-${rarity}" aria-label="${escapeHtml(m.name)} trading card">
|
|
|
|
| 133 |
.modal-backdrop::after { animation-duration: 16s; animation-direction: reverse; filter: blur(1px); opacity: 0.22; }
|
| 134 |
.modal {
|
| 135 |
width: min(1040px, 100%); max-height: 92vh; overflow: auto; border: 0;
|
| 136 |
+
position: relative; background: transparent; border-radius: 28px; padding: 0;
|
| 137 |
color: var(--text); transform: translateY(18px) scale(0.96);
|
| 138 |
}
|
| 139 |
.modal-backdrop.open .modal { animation: modalDrop 0.52s cubic-bezier(.19,1,.22,1) forwards; }
|
| 140 |
.modal-shell {
|
| 141 |
+
position: relative; z-index: 1; isolation: isolate;
|
| 142 |
display: grid; grid-template-columns: minmax(280px, 390px) minmax(320px, 1fr);
|
| 143 |
gap: 24px; align-items: stretch; padding: 22px;
|
| 144 |
border: 1px solid rgba(255,255,255,0.18); border-radius: 28px;
|
|
|
|
| 258 |
.sparkles i:nth-child(3) { left: 84%; top: 52%; animation-delay: .82s; }
|
| 259 |
.sparkles i:nth-child(4) { left: 24%; top: 72%; animation-delay: 1.1s; }
|
| 260 |
.sparkles i:nth-child(5) { left: 55%; top: 84%; animation-delay: 1.45s; }
|
| 261 |
+
.confetti-field {
|
| 262 |
+
position: absolute; inset: -18px; z-index: 4; pointer-events: none;
|
| 263 |
+
overflow: hidden; border-radius: 30px;
|
| 264 |
+
animation: confettiFieldVanish 4.2s ease forwards;
|
| 265 |
+
}
|
| 266 |
+
.confetti-piece {
|
| 267 |
+
--x: 50%; --drift: 0px; --delay: 0s; --dur: 3s; --spin: 1turn; --size: 18px;
|
| 268 |
+
position: absolute; left: var(--x); top: -42px;
|
| 269 |
+
display: grid; place-items: center; min-width: calc(var(--size) + 12px);
|
| 270 |
+
height: calc(var(--size) + 12px); padding: 0 5px;
|
| 271 |
+
border-radius: 999px; font-size: var(--size); line-height: 1;
|
| 272 |
+
background: rgba(255,255,255,0.10); border: 1px solid rgba(255,255,255,0.16);
|
| 273 |
+
box-shadow: 0 0 18px rgba(255,255,255,0.16), 0 0 28px var(--foil-b);
|
| 274 |
+
backdrop-filter: blur(4px);
|
| 275 |
+
animation: confettiFall var(--dur) cubic-bezier(.16,.8,.35,1) var(--delay) both;
|
| 276 |
+
}
|
| 277 |
+
.confetti-piece.logo {
|
| 278 |
+
font-family: var(--mono); font-weight: 800; letter-spacing: -0.06em;
|
| 279 |
+
color: #0d1117; background: #fff;
|
| 280 |
+
}
|
| 281 |
+
.confetti-piece.hf {
|
| 282 |
+
color: #111; background: linear-gradient(135deg, #ffcc4d, #ff9f1c);
|
| 283 |
+
text-shadow: 0 1px 0 rgba(255,255,255,0.45);
|
| 284 |
+
}
|
| 285 |
+
.confetti-piece.jp {
|
| 286 |
+
color: #fff; background: linear-gradient(135deg, rgba(255,92,138,0.82), rgba(188,140,255,0.62));
|
| 287 |
+
}
|
| 288 |
+
.confetti-piece:nth-child(3n) { filter: hue-rotate(32deg); }
|
| 289 |
+
.confetti-piece:nth-child(4n) { border-radius: 8px; }
|
| 290 |
+
@keyframes confettiFall {
|
| 291 |
+
0% { transform: translate3d(0, -56px, 0) rotate(0deg); opacity: 1; }
|
| 292 |
+
78% { opacity: 1; }
|
| 293 |
+
100% { transform: translate3d(var(--drift), 86vh, 0) rotate(var(--spin)); opacity: 0; }
|
| 294 |
+
}
|
| 295 |
+
@keyframes confettiFieldVanish {
|
| 296 |
+
0%, 72% { opacity: 1; }
|
| 297 |
+
100% { opacity: 0; visibility: hidden; }
|
| 298 |
+
}
|
| 299 |
.modal-info { display: flex; flex-direction: column; min-width: 0; }
|
| 300 |
.modal-copy {
|
| 301 |
margin-top: auto; padding: 14px; border-radius: 16px;
|
|
|
|
| 355 |
@media (prefers-reduced-motion: reduce) {
|
| 356 |
.modal-backdrop::before, .modal-backdrop::after, .modal-shell::before,
|
| 357 |
.modal-card-stage::before, .showcase-card, .showcase-card::before,
|
| 358 |
+
.showcase-art::before, .sparkles i, .confetti-field, .confetti-piece { animation: none !important; }
|
| 359 |
}
|
| 360 |
|
| 361 |
.legend { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
|
|
| 775 |
return h;
|
| 776 |
}
|
| 777 |
|
| 778 |
+
const CONFETTI_MARKS = [
|
| 779 |
+
{ text: "🌸", cls: "jp" },
|
| 780 |
+
{ text: "💮", cls: "jp" },
|
| 781 |
+
{ text: "🍥", cls: "jp" },
|
| 782 |
+
{ text: "⛩", cls: "jp" },
|
| 783 |
+
{ text: "🗾", cls: "jp" },
|
| 784 |
+
{ text: "✨", cls: "jp" },
|
| 785 |
+
{ text: "🤗", cls: "hf" },
|
| 786 |
+
{ text: "HF", cls: "hf logo" },
|
| 787 |
+
{ text: "GH", cls: "logo" },
|
| 788 |
+
{ text: "🐙", cls: "logo" },
|
| 789 |
+
];
|
| 790 |
+
|
| 791 |
+
function confettiHTML(seed) {
|
| 792 |
+
let s = Math.abs(hashCode(seed)) || 1;
|
| 793 |
+
const pieces = [];
|
| 794 |
+
for (let i = 0; i < 34; i++) {
|
| 795 |
+
s = (s * 1664525 + 1013904223) >>> 0;
|
| 796 |
+
const mark = CONFETTI_MARKS[s % CONFETTI_MARKS.length];
|
| 797 |
+
const x = 3 + ((s >>> 8) % 94);
|
| 798 |
+
const drift = ((s >>> 10) % 121) - 60;
|
| 799 |
+
const delay = ((s >>> 16) % 140) / 100;
|
| 800 |
+
const dur = 2.2 + ((s >>> 4) % 24) / 10;
|
| 801 |
+
const spin = ((s % 2) ? 1 : -1) * (0.7 + ((s >>> 12) % 20) / 10);
|
| 802 |
+
const size = 18 + ((s >>> 20) % 15);
|
| 803 |
+
pieces.push(
|
| 804 |
+
`<span class="confetti-piece ${mark.cls}" style="--x:${x}%; --drift:${drift}px; --delay:${delay}s; --dur:${dur.toFixed(1)}s; --spin:${spin.toFixed(1)}turn; --size:${size}px;">${mark.text}</span>`
|
| 805 |
+
);
|
| 806 |
+
}
|
| 807 |
+
return `<div class="confetti-field" aria-hidden="true">${pieces.join("")}</div>`;
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
function openModal(m) {
|
| 811 |
const rarity = rarityFor(m);
|
| 812 |
const { v, a } = aggregateVA(m.profile);
|
|
|
|
| 817 |
const cardNo = String(Math.abs(hashCode(m.id)) % 999).padStart(3, "0");
|
| 818 |
|
| 819 |
document.getElementById("modal-content").innerHTML = `
|
| 820 |
+
${confettiHTML(m.id)}
|
| 821 |
<div class="modal-shell" style="--foil-a:${top[0].color}; --foil-b:${top[1].color}; --foil-c:${top[2].color}; --rarity-color:var(--r-${rarity});">
|
| 822 |
<div class="modal-card-stage">
|
| 823 |
<div class="showcase-card r-${rarity}" aria-label="${escapeHtml(m.name)} trading card">
|