feat: hero intro overlay + embossed Plan-B background
Three-stage typographic intro that plays once per browser session before the hero reveals, plus a subtle embossed-text pattern that fades in underneath the wordmark afterwards. Intro overlay - Full-viewport #FAFAFA panel with three sequential stages: "Wisdom is to prepare" → "Even if crisis is not here yet" → "Figure out your Plan B in less than two minutes." (DE: "Weise ist, wer vorsorgt." → "Auch wenn noch keine Krise da ist." → "Finden Sie Ihren Plan B in weniger als zwei Minuten."). Both languages added to the i18n table. - Each stage word-cascades — text is split per-space into <span class ="word"> at play time with an inline animation-delay; each word smoke-rises into place (0 → 1 opacity, blur 8px → 0, translateY 14 → 0). 0.32s stagger × 1.5s per-word duration = half-speed cinematic pacing. - Stages 1 + 2 exit with the introOut smoke-out (re-blur to 16px, drift up 14px, fade to 0 over 0.8s). Stage 3 stays on screen and rides the overlay's 1.1s fade as a single dissolve so we don't double-outro the closing line. - During the intro the body lacks .intro-done; the hero/header/lang toggle are pinned to opacity 0 + animation-name: none. Once the loop completes the body picks up .intro-done and the original hero fadeUp animations fire from scratch. - Replay is gated on sessionStorage.kammergut.intro.shown.v1 — runs once per tab. Skipped automatically when loadState() restores a saved quiz/results stage so a refresh mid-flow doesn't replay. Embossed Plan-B background - 7 rows × ~6 phrases of "Plan B" in mixed scripts (Plan B, Piano B, Plano B, План Б, プランB, 备用计划, 플랜 B, خطة ب, योजना बी, תוכנית ב, Σχέδιο Β) tiled diagonally at -18°. - Embossed effect via text-shadow only: glyph colour = bg colour (#F0F0F0) so only the 1px white top-left highlight and ~6%-black bottom-right shadow render, looking pressed into the panel. - font-size clamps from 42px (mobile) to 60px (desktop) so the pattern reads comfortably on small screens. DM Serif Display matches the wordmark family. - Pattern is opacity 0 until body.intro-done, then fades in over 1.6s with a 0.3s delay so it emerges underneath the cascading wordmark rather than appearing as a separate layer. Hero / misc - Removed the bg-1.jpg background — the hero is now flat #F0F0F0 matching the white-paint inner-card colour. Mobile @media override (which mixed a 50% white veil over the JPG) dropped. - Test page at public/intro-test.html with 10 cinematic styles plus matching outros for picking entry/exit variants. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
src/App.vue
24
src/App.vue
@@ -273,6 +273,18 @@
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="hero" id="hero-section">
|
||||
<!-- Embossed "Plan B" background — diagonal grid of translations
|
||||
that fades in alongside the brand wordmark after the intro
|
||||
overlay clears. Pure decoration, hidden from screen readers. -->
|
||||
<div class="hero-bg-pattern" aria-hidden="true">
|
||||
<div class="bg-row"><span>Plan B</span><span>Piano B</span><span>Plano B</span><span>Plan B</span><span>План Б</span><span>プランB</span></div>
|
||||
<div class="bg-row"><span>Plan B</span><span>备用计划</span><span>Plan B</span><span>플랜 B</span><span>Plan B</span><span>योजना बी</span></div>
|
||||
<div class="bg-row"><span>Piano B</span><span>Plan B</span><span>Σχέδιο Β</span><span>Plano B</span><span>خطة ب</span><span>Plan B</span></div>
|
||||
<div class="bg-row"><span>Plan B</span><span>תוכנית ב</span><span>プランB</span><span>Plan B</span><span>План Б</span><span>Plan B</span></div>
|
||||
<div class="bg-row"><span>备用计划</span><span>Plan B</span><span>Piano B</span><span>플랜 B</span><span>Plan B</span><span>Plano B</span></div>
|
||||
<div class="bg-row"><span>Plan B</span><span>योजना बी</span><span>Plan B</span><span>خطة ب</span><span>Σχέδιο Β</span><span>Plan B</span></div>
|
||||
<div class="bg-row"><span>Plan B</span><span>プランB</span><span>Plan B</span><span>План Б</span><span>Plan B</span><span>Piano B</span></div>
|
||||
</div>
|
||||
<h1 class="paint-3d" data-i18n="brand">Deepstock</h1>
|
||||
<p class="hero-sub" data-i18n="hero_sub">Preparedness, refined.</p>
|
||||
<button class="cta-btn" @click="startQuiz">
|
||||
@@ -1786,12 +1798,12 @@ async function playIntro() {
|
||||
// stages 1 and 3). Stage 2 needs ~2.6s to land both staggered lines
|
||||
// (line-a 0.1+1.5s, line-b 1.1+1.5s). Holds are tuned so the viewer
|
||||
// can read each line after it lands.
|
||||
// Every stage word-cascades. Entry duration = words × 0.16s stagger
|
||||
// + 0.75s per-word + 0.05s base delay. JS rebuilds per-word spans
|
||||
// for every stage so language switches still split correctly, and
|
||||
// measures the entry length from the live word count.
|
||||
const STAGGER = 0.16
|
||||
const PER_WORD = 0.75
|
||||
// Every stage word-cascades, half speed so each line lands more
|
||||
// deliberately. Entry = words × 0.32s stagger + 1.5s per-word + 0.05s
|
||||
// base delay. JS rebuilds the spans per play so language switches
|
||||
// still split correctly and measures entry from live word count.
|
||||
const STAGGER = 0.32
|
||||
const PER_WORD = 1.5
|
||||
const BASE = 0.05
|
||||
const stages = []
|
||||
for (let n = 1; n <= 3; n++) {
|
||||
|
||||
@@ -106,6 +106,56 @@ body { background: #FAFAFA; color: var(--text); font-family: var(--font-body); f
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Embossed "Plan B" background pattern — diagonal grid of the phrase
|
||||
in different languages, carved into the hero panel. Text colour
|
||||
matches the bg so only the highlight + shadow text-shadows render,
|
||||
giving a subtle pressed-into-the-surface look. Sits behind hero
|
||||
content (z-index 0; .hero h1 / cta etc. are z-index 1). */
|
||||
.hero-bg-pattern {
|
||||
position: absolute;
|
||||
inset: -20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
align-items: stretch;
|
||||
transform: rotate(-18deg);
|
||||
transform-origin: center;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.hero-bg-pattern .bg-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
gap: clamp(28px, 5vw, 64px);
|
||||
white-space: nowrap;
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400;
|
||||
/* Mobile floor bumped up from 28px → 42px so the embossed pattern reads
|
||||
comfortably on small screens; desktop ceiling bumped slightly. */
|
||||
font-size: clamp(42px, 8vw, 60px);
|
||||
letter-spacing: 0.04em;
|
||||
/* Embossed effect: text colour matches the panel so only the
|
||||
shadows render. Highlight on top-left, faint shadow on bottom-right. */
|
||||
color: #F0F0F0;
|
||||
text-shadow:
|
||||
-1px -1px 0 rgba(255, 255, 255, 0.95),
|
||||
1px 1px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.hero-bg-pattern .bg-row span { display: inline-block; }
|
||||
|
||||
/* Reveal the pattern alongside the hero wordmark after the intro
|
||||
overlay clears. Slow ease-in so it feels like the surface emerges
|
||||
underneath rather than appearing as a new layer. */
|
||||
body.intro-done .hero-bg-pattern {
|
||||
animation: heroBgFade 1.6s 0.3s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
}
|
||||
@keyframes heroBgFade {
|
||||
to { opacity: 1; }
|
||||
}
|
||||
.hero-eyebrow {
|
||||
position: relative; z-index: 1;
|
||||
font-family: var(--font-body);
|
||||
@@ -1078,7 +1128,7 @@ input[type=range]::-moz-range-thumb {
|
||||
opacity: 0;
|
||||
}
|
||||
.intro-stage.active .intro-text > .word {
|
||||
animation: introWord 0.75s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
animation: introWord 1.5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
}
|
||||
@keyframes introWord {
|
||||
0% { opacity: 0; transform: translateY(14px); filter: blur(8px); }
|
||||
|
||||
Reference in New Issue
Block a user