Skip to content

Commit a3b1c15

Browse files
envelope
1 parent fcb7b84 commit a3b1c15

3 files changed

Lines changed: 42 additions & 22 deletions

File tree

‎css/11-little-world.css‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,14 @@
136136
.env-glow { position: absolute; left: 50%; top: -74px; width: 260px; height: 190px; border-radius: 50%; opacity: 0; pointer-events: none;
137137
background: radial-gradient(ellipse at 50% 66%, rgba(255, 250, 207, .98) 0%, rgba(255, 220, 151, .62) 28%, rgba(247, 194, 224, .25) 54%, rgba(205, 188, 241, 0) 78%);
138138
filter: blur(10px); transform: translateX(-50%); }
139+
.env-ring { position: absolute; left: 50%; top: -30px; width: 238px; height: 172px; box-sizing: border-box; border: 2px solid rgba(255, 237, 177, .75); border-radius: 50%; opacity: 0; pointer-events: none;
140+
box-shadow: 0 0 14px rgba(255, 221, 145, .55), inset 0 0 18px rgba(242, 195, 224, .28); filter: blur(.4px); }
139141
.env-ray { --ray-angle: 0deg; position: absolute; left: 50%; top: -130px; width: 20px; height: 155px; opacity: 0; pointer-events: none; transform-origin: 50% 100%;
140142
background: linear-gradient(to top, rgba(255, 248, 208, .58), rgba(255, 226, 174, .2) 58%, transparent); filter: blur(5px); border-radius: 50% 50% 20% 20%; }
141143
.env-ray.r1 { --ray-angle: -48deg; } .env-ray.r2 { --ray-angle: -24deg; height: 170px; top: -145px; }
142144
.env-ray.r3 { --ray-angle: 25deg; height: 164px; top: -139px; } .env-ray.r4 { --ray-angle: 49deg; }
143145
.env-hearts { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
144-
.env-heart { position: absolute; left: 24px; top: 11px; width: 18px; height: 17px; opacity: 0; pointer-events: none; filter: drop-shadow(0 2px 3px rgba(163, 104, 137, .18)); }
146+
.env-heart { position: absolute; left: 22px; top: 9px; width: 22px; height: 21px; opacity: 0; pointer-events: none; filter: drop-shadow(0 2px 4px rgba(163, 104, 137, .28)) drop-shadow(0 0 5px rgba(255, 237, 205, .42)); }
145147
.env-heart svg { display: block; width: 100%; height: 100%; }
146148
.env-spark { width: 10px; height: 10px; left: 27px; top: 13px; filter: drop-shadow(0 0 3px rgba(255, 226, 151, .45)); }
147149

@@ -167,11 +169,13 @@
167169
.env-panel.tl { border-radius: 8px 0 0 0; } .env-panel.tr { border-radius: 0 9px 0 0; } .env-panel.bl { border-radius: 0 0 0 9px; } .env-panel.br { border-radius: 0 0 8px 0; }
168170
.env-panel .shade, .env-row > .shade { position: absolute; inset: 0; opacity: 0; pointer-events: none; background: linear-gradient(160deg, rgba(120, 85, 125, 0.28), rgba(120, 85, 125, 0.06)); border-radius: inherit; }
169171
.env-row > .shade { left: 50%; width: 50%; border-radius: 0 9px 0 0; } /* only over the folded stack, not the empty half the left panel left behind */
170-
.env-text { position: absolute; inset: 0; display: flex; overflow: auto; overscroll-behavior: contain; }
172+
.env-paper-shimmer { position: absolute; inset: 0; z-index: 1; border-radius: 9px; opacity: 0; pointer-events: none; background: linear-gradient(112deg, transparent 34%, rgba(255,255,255,.76) 45%, rgba(255,239,184,.42) 51%, rgba(225,207,250,.32) 57%, transparent 68%); background-size: 260% 100%; background-position: 135% 0; }
173+
.env-text { position: absolute; inset: 0; z-index: 2; display: flex; overflow: hidden; }
171174
.env-copy { margin: auto 0; width: 100%; padding: 10px 14px; box-sizing: border-box; }
172175
.env-copy span { display: block; }
173-
.env-copy span + span { margin-top: 3px; }
176+
.env-copy span + span { margin-top: 7px; }
174177
.env-copy .env-hello { white-space: nowrap; font-size: 1.3rem; font-weight: 600; color: #c2457e; }
178+
.env-copy-heart { display: inline-block; margin-left: 2px; color: #d96b93; font-size: 1.25em; line-height: .8; font-weight: 700; filter: drop-shadow(0 1px 2px rgba(194,69,126,.18)); }
175179
.env-close { position: absolute; top: -10px; right: -10px; width: 28px; height: 28px; padding: 0; border: 1.5px solid #e6c9d4; border-radius: 50%; background: #fff7fa; cursor: pointer; display: grid; place-items: center; box-shadow: 0 2px 5px rgba(90, 67, 102, 0.18);
176180
opacity: 0; visibility: hidden; transition: opacity 0.2s ease; touch-action: manipulation; }
177181
.env-close::after { content: ''; position: absolute; inset: -8px; }
@@ -186,7 +190,7 @@
186190
.w-envelope, .w-envelope.settling, .env-back { transition: none; }
187191
.env-letter { transition: opacity 0.3s ease; }
188192
.env-hearts { display: none; }
189-
.env-magic .env-ray { display: none; }
193+
.env-magic .env-ray, .env-magic .env-ring, .env-paper-shimmer { display: none; }
190194
.env-magic.is-still .env-glow { opacity: .24; transform: translate(-50%, -2px) scale(.95); }
191195
}
192196
@keyframes envFade { from { opacity: 0; } to { opacity: 1; } }

‎index.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<link rel="stylesheet" href="css/08-garden-game-v7-v8.css?v=4">
2020
<link rel="stylesheet" href="css/09-v9-refinements.css?v=2">
2121
<link rel="stylesheet" href="css/10-botanical.css?v=3">
22-
<link rel="stylesheet" href="css/11-little-world.css?v=13">
22+
<link rel="stylesheet" href="css/11-little-world.css?v=14">
2323
<link rel="stylesheet" href="css/12-polish-pass.css?v=2">
2424
<link rel="stylesheet" href="css/13-ecosystem.css?v=2">
2525
<link rel="stylesheet" href="css/14-side-vines-plants.css?v=3">
@@ -757,7 +757,7 @@ <h2 class="contact-title">Let's <em>Connect</em></h2>
757757
<script src="js/botanical/stage.js?v=2" defer></script>
758758
<script src="js/botanical/links.js?v=1" defer></script>
759759
<script src="js/easter-eggs/easter-eggs.js?v=1" defer></script>
760-
<script src="js/easter-eggs/envelope.js?v=24" defer></script>
760+
<script src="js/easter-eggs/envelope.js?v=25" defer></script>
761761
<script src="js/environment/breeze.js?v=2" defer></script>
762762
<script src="js/animals/caterpillar.js?v=2" defer></script>
763763
<script src="js/plants/dandelions.js?v=2" defer></script>

‎js/easter-eggs/envelope.js‎

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
4343
];
4444
const SPARKS = [
4545
['star', '#f9dfa0', '#d6ab4f'], ['glint', '#d8c9f1', '#9d85c9'], ['dot', '#c9e4f6', '#82b5d5'],
46-
['star', '#f7bfd4', '#d985aa'], ['glint', '#f9dfa0', '#d6ab4f']
46+
['star', '#f7bfd4', '#d985aa'], ['glint', '#f9dfa0', '#d6ab4f'], ['dot', '#e0d4f5', '#a18acb'],
47+
['star', '#cbe8f6', '#82b5d5'], ['glint', '#f8c4d5', '#d985aa']
4748
];
4849
const spark = (kind, fill, stroke) => kind === 'dot'
4950
? '<svg viewBox="0 0 12 12" aria-hidden="true"><circle cx="6" cy="6" r="3.2" fill="' + fill + '" stroke="' + stroke + '" stroke-width=".7"/></svg>'
5051
: kind === 'glint'
5152
? '<svg viewBox="0 0 12 12" aria-hidden="true"><path d="M6 .7 L6.7 5.3 L11.3 6 L6.7 6.7 L6 11.3 L5.3 6.7 L.7 6 L5.3 5.3Z" fill="' + fill + '" stroke="' + stroke + '" stroke-width=".55"/></svg>'
5253
: '<svg viewBox="0 0 12 12" aria-hidden="true"><path d="M6 .9 L7.5 4.5 L11.1 6 L7.5 7.5 L6 11.1 L4.5 7.5 L.9 6 L4.5 4.5Z" fill="' + fill + '" stroke="' + stroke + '" stroke-width=".55" stroke-linejoin="round"/></svg>';
5354
const svg = (cls, inner, vb) => '<svg class="' + cls + '" viewBox="' + (vb || '0 -14 64 60') + '" aria-hidden="true">' + inner + '</svg>';
54-
const COPY = '<span class="env-hello">hello, curious soul &nbsp;♡</span><span>the garden has secrets.</span><span>look closely, explore, and see what comes to life.</span>';
55+
const COPY = '<span class="env-hello">hello, curious soul</span><span>the garden has secrets</span><span>come explore <b class="env-copy-heart" aria-label="heart">♡</b></span>';
5556
const LABEL = 'A tiny envelope with a heart seal. Press to open it; arrow keys move it';
5657
/* the letter is one sheet of four panels (folded in quarters), so the folds are real: the top row hinges up, then the left panels swing open */
5758
const SHEET = '<div class="env-sheet" aria-hidden="true">' +
@@ -60,10 +61,10 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
6061
const MARKUP =
6162
svg('env-back', BODY) +
6263
'<svg class="env-flap-open" viewBox="0 -12 64 21" aria-hidden="true">' + FLAP_OPEN + '</svg>' +
63-
'<div class="env-magic" aria-hidden="true"><span class="env-glow"></span><span class="env-ray r1"></span><span class="env-ray r2"></span><span class="env-ray r3"></span><span class="env-ray r4"></span></div>' +
64+
'<div class="env-magic" aria-hidden="true"><span class="env-glow"></span><span class="env-ring"></span><span class="env-ray r1"></span><span class="env-ray r2"></span><span class="env-ray r3"></span><span class="env-ray r4"></span></div>' +
6465
'<div class="env-hearts" aria-hidden="true"></div>' +
6566
'<div class="env-letter-box"><div class="env-letter" role="region" aria-label="A handwritten note" aria-hidden="true">' + SHEET +
66-
'<div class="env-text"><div class="env-copy">' + COPY + '</div></div>' +
67+
'<div class="env-paper-shimmer" aria-hidden="true"></div><div class="env-text"><div class="env-copy">' + COPY + '</div></div>' +
6768
'<button type="button" class="env-close" aria-label="Close the note"><svg viewBox="0 0 12 12" aria-hidden="true"><path d="M2.5 2.5 L9.5 9.5 M9.5 2.5 L2.5 9.5" stroke="#8c5a73" stroke-width="1.6" stroke-linecap="round" fill="none"/></svg></button>' +
6869
'</div></div>' +
6970
svg('env-front', PANELS) +
@@ -188,16 +189,31 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
188189
t = setTimeout(clean, 1300); hearts.add(clean);
189190
return;
190191
}
191-
const glow = q('.env-glow'), rays = Array.from(magic.querySelectorAll('.env-ray'));
192+
const glow = q('.env-glow'), ring = q('.env-ring'), shimmer = q('.env-paper-shimmer');
193+
const rays = Array.from(magic.querySelectorAll('.env-ray'));
192194
const animations = [glow.animate([
193195
{ opacity: 0, transform: 'translate(-50%, 10px) scale(.58)' },
194-
{ opacity: .72, transform: 'translate(-50%, 0) scale(1)', offset: .32 },
195-
{ opacity: .42, transform: 'translate(-50%, -7px) scale(1.14)', offset: .68 },
196+
{ opacity: .88, transform: 'translate(-50%, 0) scale(1)', offset: .32 },
197+
{ opacity: .54, transform: 'translate(-50%, -7px) scale(1.14)', offset: .68 },
196198
{ opacity: 0, transform: 'translate(-50%, -12px) scale(1.22)' }
197-
], { duration: 1450, delay: 90, easing: 'ease-out', fill: 'both' })];
199+
], { duration: 1550, delay: 70, easing: 'ease-out', fill: 'both' }), ring.animate([
200+
{ opacity: 0, transform: 'translate(-50%, -50%) scale(.46)' },
201+
{ opacity: .62, transform: 'translate(-50%, -50%) scale(.76)', offset: .28 },
202+
{ opacity: .28, transform: 'translate(-50%, -50%) scale(1)', offset: .66 },
203+
{ opacity: 0, transform: 'translate(-50%, -50%) scale(1.16)' }
204+
], { duration: 1550, delay: 130, easing: 'cubic-bezier(.2,.7,.2,1)', fill: 'both' }), shimmer.animate([
205+
{ opacity: 0, backgroundPosition: '135% 0' },
206+
{ opacity: .72, backgroundPosition: '80% 0', offset: .28 },
207+
{ opacity: .5, backgroundPosition: '15% 0', offset: .68 },
208+
{ opacity: 0, backgroundPosition: '-35% 0' }
209+
], { duration: 1050, delay: 760, easing: 'ease-in-out', fill: 'both' }), q('.env-front').animate([
210+
{ filter: 'drop-shadow(0 0 0 rgba(255,225,154,0))' },
211+
{ filter: 'drop-shadow(0 0 10px rgba(255,225,154,.82))', offset: .42 },
212+
{ filter: 'drop-shadow(0 0 0 rgba(255,225,154,0))' }
213+
], { duration: 1100, delay: 90, easing: 'ease-out', fill: 'both' })];
198214
rays.forEach((ray, i) => animations.push(ray.animate([
199215
{ opacity: 0, transform: 'translateX(-50%) rotate(var(--ray-angle)) scaleY(.3)' },
200-
{ opacity: .34, transform: 'translateX(-50%) rotate(var(--ray-angle)) scaleY(1)', offset: .38 },
216+
{ opacity: .48, transform: 'translateX(-50%) rotate(var(--ray-angle)) scaleY(1)', offset: .38 },
201217
{ opacity: 0, transform: 'translateX(-50%) rotate(var(--ray-angle)) scaleY(1.18)' }
202218
], { duration: 1250 + i * 55, delay: 210 + i * 35, easing: 'ease-out', fill: 'both' })));
203219
let left = animations.length;
@@ -216,7 +232,7 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
216232
const scale = parseFloat(style.scale) || 1;
217233
const pieces = HEARTS.map((colors, i) => ({ heart: true, i, colors })).concat(SPARKS.map((spec, i) => ({ heart: false, i, spec })));
218234
for (let k = 0; k < pieces.length && FX.room(1); k++) {
219-
const piece = pieces[k], h = document.createElement('span'), size = piece.heart ? rand(17, 23) : rand(7, 12);
235+
const piece = pieces[k], h = document.createElement('span'), size = piece.heart ? rand(21, 30) : rand(8, 14);
220236
h.className = piece.heart ? 'env-heart' : 'env-heart env-spark env-' + piece.spec[0];
221237
h.style.width = size.toFixed(1) + 'px'; h.style.height = (size * (piece.heart ? .94 : 1)).toFixed(1) + 'px';
222238
h.style.left = (32 - size / 2 + rand(-7, 7)).toFixed(1) + 'px'; h.style.top = (12 + rand(-3, 5)).toFixed(1) + 'px';
@@ -226,8 +242,8 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
226242
heartBox.appendChild(h);
227243
const box = h.getBoundingClientRect(), cx = box.left + box.width / 2, cy = box.top + box.height / 2;
228244
const side = piece.i % 2 ? 1 : -1, lane = piece.heart ? Math.floor(piece.i / 2) : piece.i % 3;
229-
const dx = side * rand(104 + lane * 8, 122 + lane * 10), rise = rand(piece.heart ? 72 : 54, piece.heart ? 118 : 96);
230-
const turn = rand(-24, 24), startTurn = rand(-18, 18);
245+
const dx = side * rand(116 + lane * 8, 136 + lane * 10), rise = rand(piece.heart ? 82 : 62, piece.heart ? 134 : 110);
246+
const turn = rand(-34, 34), startTurn = rand(-24, 24);
231247
/* Sample the entire rise with overlapping padded footprints, including
232248
the envelope's tilt/hover scale. Try a shorter path in tight spaces. */
233249
const pathClear = factor => {
@@ -237,14 +253,14 @@ MB.define('easter-eggs.envelope', ['core.utils', 'core.scheduler', 'core.safe-zo
237253
}
238254
return true;
239255
};
240-
const factor = [1, 0.7, 0.45].find(pathClear);
256+
const factor = [1, 0.82, 0.64, 0.5].find(pathClear);
241257
if (!factor) { h.remove(); continue; }
242258
const a = h.animate([
243259
{ transform: 'translate(0, 7px) rotate(' + startTurn.toFixed(1) + 'deg) scale(.3)', opacity: 0 },
244-
{ transform: 'translate(' + (dx * factor * .58).toFixed(1) + 'px, ' + (3 - rise * factor * .58).toFixed(1) + 'px) rotate(' + (startTurn + turn * .55).toFixed(1) + 'deg) scale(1.06)', opacity: piece.heart ? .92 : .84, offset: .4 },
260+
{ transform: 'translate(' + (dx * factor * .58).toFixed(1) + 'px, ' + (3 - rise * factor * .58).toFixed(1) + 'px) rotate(' + (startTurn + turn * .55).toFixed(1) + 'deg) scale(1.14)', opacity: piece.heart ? .98 : 1, offset: .4 },
245261
{ transform: 'translate(' + (dx * factor).toFixed(1) + 'px, ' + (-rise * factor).toFixed(1) + 'px) rotate(' + (startTurn + turn).toFixed(1) + 'deg) scale(.82)', opacity: 0 }
246-
], { duration: rand(1300, 1550), delay: 300 + k * 18, easing: 'cubic-bezier(.2,.7,.25,1)', fill: 'both' });
247-
const release = FX.track(h, a, 2150);
262+
], { duration: rand(1400, 1750), delay: 270 + k * 16, easing: 'cubic-bezier(.2,.7,.25,1)', fill: 'both' });
263+
const release = FX.track(h, a, 2250);
248264
const clean = () => { release(); hearts.delete(clean); a.cancel(); };
249265
hearts.add(clean);
250266
a.addEventListener('finish', clean, { once: true });

0 commit comments

Comments
 (0)