From d657c49c835a563481630440df963dfc4b37bc92 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 1 Oct 2026 22:07:12 +0700 Subject: [PATCH] feat(gacha): give the beta card a polychrome rainbow foil --- renderer/src/gacha-beta/page/page.css | 59 ++++++++++++++++++++++++++- renderer/src/gacha-beta/page/page.js | 22 +++++++++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/renderer/src/gacha-beta/page/page.css b/renderer/src/gacha-beta/page/page.css index f939dab..9210b12 100644 --- a/renderer/src/gacha-beta/page/page.css +++ b/renderer/src/gacha-beta/page/page.css @@ -48,9 +48,66 @@ body { text-align: center; } +/* + * Polychrome: a rainbow band pattern glazed over the card under the print, + * sliding diagonally so the colours shift. Only a transform animates, which + * the compositor moves without repainting the foil each frame. + */ +.wish-polychrome { + border-radius: inherit; + inset: 0; + mix-blend-mode: screen; + opacity: var(--wish-polychrome); + overflow: hidden; + pointer-events: none; + position: absolute; +} + +.wish-polychrome::before { + animation: wish-polychrome 2.4s ease-in-out infinite alternate; + background: repeating-linear-gradient( + 125deg, + #ff5f9e 0%, + #ffb347 6%, + #fff275 12%, + #6dffb0 18%, + #5fd4ff 24%, + #9a7bff 30%, + #ff5f9e 36% + ); + content: ''; + height: 300%; + left: -100%; + position: absolute; + top: -100%; + width: 300%; +} + +/* The band overhangs the card by a third of its size on each side, so it may slide at most that far. */ +@keyframes wish-polychrome { + to { + transform: translate(30%, 30%); + } +} + +.wish-card > :not(.wish-polychrome) { + position: relative; +} + +/* + * The spectrum foil sets --accent inline on the card to its own colour; the + * print inside keeps the rarity colour. + */ +.wish-card > * { + --accent: var(--wish-accent); +} + .wish-rank { color: var(--accent); - font: italic 700 13vh/1.1 'Noto Serif', Georgia, serif; + font: + italic 700 13vh/1.1 'Noto Serif', + Georgia, + serif; } .wish-label { diff --git a/renderer/src/gacha-beta/page/page.js b/renderer/src/gacha-beta/page/page.js index ffb9a9a..7b5e4e6 100644 --- a/renderer/src/gacha-beta/page/page.js +++ b/renderer/src/gacha-beta/page/page.js @@ -33,6 +33,9 @@ const el = (tag, className, text) => { return node; }; +/** @type {Record} */ +const polychromeStrength = {3: 0.3, 4: 0.42, 5: 0.55}; + const createFace = () => { const face = el('article', 'wish-card'); const header = el('header', 'recap-card-header'); @@ -43,7 +46,10 @@ const createFace = () => { content.append(el('span', 'wish-rank', wish.rank), title, el('p', 'wish-stars', '★'.repeat(wish.stars))); const footer = el('footer', 'recap-card-footer'); footer.append(el('span', '', `${wish.stars}★`), el('span', '', '01 / 01')); - face.append(header, content, footer); + // A rainbow sheen drifting across the whole face, stronger on rarer cards. + const sheen = el('span', 'wish-polychrome'); + sheen.style.setProperty('--wish-polychrome', String(polychromeStrength[wish.stars] ?? 0.3)); + face.append(sheen, header, content, footer); return face; }; @@ -114,6 +120,18 @@ const burstSparkles = (deck, delay, duration) => { setTimeout(() => layer.remove(), delay + duration + 1200); }; +/** + * Polychrome foil: every rarity gets pack-cards' rainbow holographic print, + * from a border on 3★ to the whole card on 4★ and 5★. + * + * @type {import('pack-cards').AppearanceSettingsOptions['rarities']} + */ +const polychrome = Object.freeze({ + rare: {foil: 'holographic', coverage: 'border', palette: 'spectrum', pattern: 'stardust'}, + epic: {foil: 'holographic', coverage: 'full', palette: 'spectrum', pattern: 'stardust'}, + legendary: {foil: 'holographic', coverage: 'full', palette: 'spectrum', pattern: 'facets'}, +}); + const animate = Element.prototype.animate; /** * @this {Element} @@ -159,7 +177,7 @@ const view = createPackView(stage, { label: 'Gacha', artwork: wish.artwork, labels: {title: 'Gacha', swipe: '', tap: ''}, - appearance: {opening: 'animated', motion: 'interactive', glow: wish.glow, pack_zoom: true}, + appearance: {opening: 'animated', motion: 'interactive', glow: wish.glow, pack_zoom: true, rarities: polychrome}, }); view.showPack({