It's your cult leader Abby. When I decided one late night that I needed to create a blog & start living out the life I have always dreamed, I started with doing A LOT of research. That research lead me to noticing a lot of blogging, especially on blogger, requires at least some knowledge in coding. Luckily for me & all the different lives i've lived I do have a little background in coding. & Since I am not one to gate keep, here are codes I've created or codes I've found from other crazy talented bloggers for you to copy & paste into your own blog. :)
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Links
https://gify.pet/
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Sparkle Screen
<!-- Enhanced Site-Wide Soft Falling Sparkles Animation Overlay -->
<canvas id="blogSparkleCanvas" style="position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; pointer-events: none !important; z-index: 9999 !important; background: transparent !important;"></canvas>
<script>
(function() {
const canvas = document.getElementById('blogSparkleCanvas');
const ctx = canvas.getContext('2d');
let sparklesList = [];
const maxSparkles = 95; // Doubled density for a richer, more noticeable falling effect
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function createSparkle(isInitial = false) {
return {
x: Math.random() * canvas.width,
y: isInitial ? Math.random() * canvas.height : -15,
size: Math.random() * 2.5 + 1.2, // Slightly larger size for better visibility
speedY: Math.random() * 0.8 + 0.4, // Gentle, varying falling drifts
speedX: Math.sin(Math.random() * 2) * 0.3, // Soft horizontal swaying sway
opacity: Math.random() * 0.6 + 0.4, // Brighter glowing alpha profiles
fadeSpeed: Math.random() * 0.004 + 0.001,
colorType: Math.floor(Math.random() * 3) // Cycles through three gorgeous matching color states
};
}
for (let i = 0; i < maxSparkles; i++) {
sparklesList.push(createSparkle(true));
}
function animateSparkles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < sparklesList.length; i++) {
let p = sparklesList[i];
p.y += p.speedY;
p.x += p.speedX;
p.opacity -= p.fadeSpeed;
if (p.y > canvas.height || p.opacity <= 0 || p.x < 0 || p.x > canvas.width) {
sparklesList[i] = createSparkle(false);
p = sparklesList[i];
}
ctx.save();
ctx.globalAlpha = p.opacity;
// Custom 3-Color Tone Palette Selection Matrix
if (p.colorType === 0) ctx.fillStyle = '#ffffff'; // Bright Crystal White
else if (p.colorType === 1) ctx.fillStyle = '#ffdfeb'; // Sweet Velvet Pastel Pink
else ctx.fillStyle = '#f7e7b4'; // Soft Warm Champagne Gold
// Draw crisp diamond starburst sparkles using custom vectors
ctx.beginPath();
ctx.moveTo(p.x, p.y - p.size * 2.2);
ctx.lineTo(p.x + p.size * 1.2, p.y);
ctx.lineTo(p.x, p.y + p.size * 2.2);
ctx.lineTo(p.x - p.size * 1.2, p.y);
ctx.closePath();
ctx.fill();
ctx.restore();
}
requestAnimationFrame(animateSparkles);
}
animateSparkles();
})();
</script>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Kindle
<!-- Text-Safe Permanent Image Map Kindle Reading Log Widget -->
<div style="display: flex !important; flex-direction: column !important; align-items: center !important; gap: 8px !important; padding: 10px !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; max-width: 250px !important; margin: 0 auto !important; position: relative !important;">
<!-- Main Secure Kindle Body Shell Container (Width: 220px, Height: 335px) -->
<div style="width: 220px !important; height: 335px !important; background: #1a1a1a !important; border-radius: 12px !important; box-shadow: 0 6px 20px rgba(0,0,0,0.2) !important; padding: 18px 12px 30px 12px !important; box-sizing: border-box !important; display: flex !important; flex-direction: column !important; align-items: center !important; position: relative !important; overflow: hidden !important;">
<!-- Kindle Paperwhite Matte Digital Display Screen Area -->
<div style="width: 100% !important; height: 100% !important; background: #f5f4ef !important; border-radius: 2px !important; border: 1px solid #111 !important; box-shadow: inset 0 2px 5px rgba(0,0,0,0.2) !important; position: relative !important; overflow: hidden !important; display: flex !important; flex-direction: column !important; justify-content: space-between !important; padding: 8px 10px !important; box-sizing: border-box !important; color: #222 !important;">
<!-- Invisible Left Click Sensor to Flip Reviews Backwards (30% Width Layout Layer) -->
<div onclick="prevKindlePage()" style="position: absolute !important; top: 0 !important; left: 0 !important; width: 30% !important; height: 100% !important; cursor: w-resize !important; z-index: 10 !important; background: transparent !important;"></div>
<!-- Invisible Right Click Sensor to Flip Reviews Forwards (70% Width Layout Layer) -->
<div onclick="nextKindlePage()" style="position: absolute !important; top: 0 !important; right: 0 !important; width: 70% !important; height: 100% !important; cursor: e-resize !important; z-index: 10 !important; background: transparent !important;"></div>
<!-- Top Device Header Status Row Layout Tracking -->
<div style="display: flex !important; justify-content: space-between !important; align-items: center !important; font-size: 7.5px !important; color: #555 !important; border-bottom: 1px dashed #ccc !important; padding-bottom: 2px !important; font-weight: 500 !important; pointer-events: none !important;">
<span id="kindleMiniTitle">The Haar</span>
<div style="display: flex !important; align-items: center !important; gap: 3px !important;">
<span>11:54 PM</span>
<div style="width: 9px !important; height: 5px !important; border: 0.5px solid #555 !important; position: relative !important; padding: 0.2px !important;"><div style="width: 90% !important; height: 100% !important; background: #222 !important;"></div></div>
</div>
</div>
<!-- Center Book Content Review Frame Block Area -->
<div style="flex-grow: 1 !important; display: flex !important; flex-direction: column !important; justify-content: center !important; align-items: center !important; text-align: center !important; padding: 3px 0 !important; pointer-events: none !important;">
<div id="kindleStatusTag" style="font-size: 7.5px !important; font-weight: bold !important; letter-spacing: 1px !important; color: #811d43 !important; text-transform: uppercase !important; margin-bottom: 3px !important;">NOW READING</div>
<h4 id="kindleMainBookTitle" style="font-size: 11.5px !important; margin: 0 0 1px 0 !important; font-family: Georgia, serif !important; font-weight: bold !important; color: #000 !important; line-height: 1.2 !important;">The Haar</h4>
<p id="kindleAuthorLabel" style="font-size: 8.5px !important; font-style: italic !important; margin: 0 0 2px 0 !important; color: #555 !important;">by David Sodergren</p>
<!-- Text-Based Clean Star Rating Tracker Row -->
<div id="kindleStarRating" style="font-size: 9px !important; color: #d4af37 !important; margin-bottom: 4px !important; letter-spacing: 0.5px !important; font-weight: bold !important;">RATING: 5/5 STARS</div>
<div id="kindleReviewText" style="font-size: 9.5px !important; line-height: 1.3 !important; font-weight: 500 !important; color: #222 !important; max-height: 100px !important; overflow-y: auto !important; padding: 0 2px !important; font-family: -apple-system, sans-serif !important;">
"An '80s style slasher disguised as a love story, wrapped in denial, obession, & the fear of what we refuse to see."
</div>
</div>
<!-- Bottom Page Index Status Row Layout Tracking -->
<div style="display: flex !important; justify-content: space-between !important; align-items: center !important; font-size: 7.5px !important; color: #555 !important; border-top: 1px solid rgba(0,0,0,0.05) !important; padding-top: 2px !important; pointer-events: none !important;">
<span id="kindlePageCount">Page 1 of 4</span>
<span id="kindlePercentCount">Tap screen to turn page...</span>
</div>
</div>
<!-- Bottom Logo Branding Stamp Row -->
<div style="font-size: 8px !important; font-weight: bold !important; color: #444 !important; letter-spacing: 2px !important; text-transform: uppercase !important; margin-top: 5px !important; pointer-events: none !important;">
KINDLE
</div>
</div>
</div>
<script>
// Kindle Dataset Master Database Array Loop (Completely Text-Safe & Emoji-Free)
const kindleBookDatabase = [
{
mini: "The Haar",
status: "NOW READING",
title: "The Haar",
author: "by David Sodergren",
stars: "RATING: 5/5 STARS",
review: `"An '80s style slasher disguised as a love story, wrapped in denial, obession, & the fear of what we refuse to see."`,
page: "Page 1 of 4",
percent: "Next >"
},
{
mini: "Night Watcher",
status: "CURRENT REVIEWS",
title: "Night Watcher",
author: "by Daphne Woolsoncroft",
stars: "RATING: 3/5 STARS",
review: `"A late night talk show host is haunted by their past, exploring how the choices you make in passing can alter the course of your life decades later."`,
page: "Page 2 of 4",
percent: "< Back | Next >"
},
{
mini: "The Sorrowstones",
status: "CURRENT REVIEWS",
title: "The Sorrowstones",
author: "by Felix Blackwell",
stars: "RATING: 5/5 STARS",
review: `"A boy receives a trinket on halloween that changes his life as he knows it. While everyone around him seems to be falling apart, he gets everything he's ever dreamed of - but how far is he willing to go, & who is he willing to sacrifice?"`,
page: "Page 3 of 4",
percent: "< Back | Next >"
},
{
mini: "Monumental",
status: "CURRENT REVIEWS",
title: "Monumental",
author: "by Adam L.G. Nevill",
stars: "RATING: 4/5 STARS",
review: `"A kayaking trip that turns into a fight for survival against the wilderness, isolation, & something otherworldly."`,
page: "Page 4 of 4",
percent: "< Back"
}
];
let currentKindleIndex = 0;
function updateKindleScreenView() {
const data = kindleBookDatabase[currentKindleIndex];
document.getElementById('kindleMiniTitle').textContent = data.mini;
document.getElementById('kindleStatusTag').textContent = data.status;
document.getElementById('kindleMainBookTitle').textContent = data.title;
document.getElementById('kindleAuthorLabel').textContent = data.author;
document.getElementById('kindleStarRating').textContent = data.stars;
document.getElementById('kindleReviewText').innerHTML = data.review;
document.getElementById('kindlePageCount').textContent = data.page;
document.getElementById('kindlePercentCount').textContent = data.percent;
}
function nextKindlePage() {
currentKindleIndex = (currentKindleIndex + 1) % kindleBookDatabase.length;
updateKindleScreenView();
}
function prevKindlePage() {
currentKindleIndex = (currentKindleIndex - 1 + kindleBookDatabase.length) % kindleBookDatabase.length;
updateKindleScreenView();
}
</script>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Camera Photobooth
<!-- RETRO Y2K DIGICAM PHOTO BOOTH - BLOGGER VERSION -->
<div id="digiPhotoBooth" style="
display:flex;
flex-direction:column;
align-items:center;
gap:20px;
padding:10px;
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
max-width:280px;
margin:0 auto;
">
<!-- CAMERA -->
<div style="
width:260px;
height:260px;
background:url('https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbmcqabK0i6f1dfAyA0YjAZ0080cFhCDtyK6XVYgvRQ6mTqWg3xoj5WiVYZfQgZMIAQvydRJol-n6EhqsrK-J6o8nsYONK7IxTBRAEz0m9yAbaGAEerWUa6perNPEPTX1_cU05jua3qTDgyDBD5weuPTHL8uvgER4sr-gW-nIsS6GoSKT3gaDhTrGyisU/s1080/Untitled%20-%20September%2015,%202026%20at%2017.08.02.png') center/contain no-repeat;
position:relative;
box-sizing:border-box;
">
<!-- LCD SCREEN -->
<div style="
position:absolute;
top:96px;
left:42px;
width:105px;
height:75px;
background:#1c1c1c;
border-radius:1px;
overflow:hidden;
display:flex;
justify-content:center;
align-items:center;
box-shadow:inset 0 2px 4px rgba(0,0,0,.6);
">
<video
id="digiCamFeed"
autoplay
playsinline
muted
style="
width:100%;
height:100%;
object-fit:cover;
transform:scaleX(-1);
display:none;
"
></video>
<canvas
id="digiHiddenCanvas"
style="display:none;"
></canvas>
<div
id="digiStandbyText"
style="
position:absolute;
color:#666;
font-size:8px;
text-transform:uppercase;
letter-spacing:.5px;
font-weight:bold;
text-align:center;
pointer-events:none;
line-height:1.2;
"
>
CAMERA STANDBY<br>
<span style="font-size:6px;color:#444;font-weight:normal;">
POWER ON BELOW
</span>
</div>
<div
id="digiFlashLayer"
style="
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background:#fff;
opacity:0;
pointer-events:none;
z-index:10;
"
></div>
<div
id="digiCountdownNumber"
style="
position:absolute;
font-size:22px;
font-weight:bold;
color:#fff;
text-shadow:0 1.5px 3px rgba(0,0,0,.8);
display:none;
z-index:5;
"
>
3
</div>
</div>
</div>
<!-- CONTROLS -->
<div style="
width:100%;
background:#fff;
border-radius:10px;
border:1px solid #e2e8f0;
padding:12px;
box-sizing:border-box;
display:flex;
flex-direction:column;
gap:8px;
box-shadow:0 4px 10px rgba(0,0,0,.05);
">
<div>
<label style="
font-size:9px;
font-weight:bold;
color:#64748b;
text-transform:uppercase;
display:block;
margin-bottom:4px;
">
Select Strip Theme:
</label>
<select
id="digiStripThemeMenu"
style="
width:100%;
padding:5px;
font-size:11px;
border:1px solid #cbd5e1;
border-radius:4px;
background:#fff;
color:#334155;
cursor:pointer;
"
>
<option value="classic-white">Classic Polar White</option>
<option value="sleek-black">Dark Room Onyx</option>
<option value="zebra-print">Retro Zebra Print</option>
</select>
</div>
<button
id="digiPowerToggleBtn"
type="button"
style="
width:100%;
background:#4a0d25;
color:#fff;
border:none;
padding:7px;
font-size:10px;
font-weight:bold;
border-radius:4px;
cursor:pointer;
text-transform:uppercase;
"
>
Power On Camera
</button>
<button
id="digiCaptureStripBtn"
type="button"
style="
width:100%;
background:#2196f3;
color:#fff;
border:none;
padding:7px;
font-size:10px;
font-weight:bold;
border-radius:4px;
cursor:pointer;
display:none;
text-transform:uppercase;
"
>
📸 Take Photo Strip (3 Pics)
</button>
<div
id="digiStatusMessage"
style="
font-size:9px;
color:#64748b;
text-align:center;
min-height:12px;
"
></div>
</div>
<!-- PREVIEW -->
<div
id="digiPreviewCard"
style="
width:100%;
background:#fff;
border-radius:10px;
border:1px solid #e2e8f0;
padding:12px;
box-sizing:border-box;
display:none;
flex-direction:column;
align-items:center;
gap:10px;
box-shadow:0 4px 10px rgba(0,0,0,.05);
"
>
<div style="
font-size:9px;
font-weight:bold;
color:#64748b;
text-transform:uppercase;
letter-spacing:1px;
">
Your Photo Strip
</div>
<div id="digiRenderedStripBox"></div>
<button
id="digiSaveGalleryBtn"
type="button"
style="
width:100%;
background:#6366f1;
color:#fff;
border:none;
padding:7px;
font-size:10px;
font-weight:bold;
border-radius:4px;
cursor:pointer;
text-transform:uppercase;
"
>
💾 Save to Gallery Page
</button>
</div>
<!-- GALLERY -->
<div style="
width:100%;
background:#fff;
border-radius:10px;
border:1px solid #e2e8f0;
padding:12px;
box-sizing:border-box;
box-shadow:0 4px 10px rgba(0,0,0,.05);
">
<div style="
font-size:9px;
font-weight:bold;
color:#64748b;
text-transform:uppercase;
letter-spacing:1px;
text-align:center;
margin-bottom:10px;
">
📖 Photo Booth Gallery Hub
</div>
<div
id="digiGalleryDisplayShelf"
style="
display:flex;
gap:12px;
overflow-x:auto;
padding:5px 0;
scrollbar-width:thin;
min-height:40px;
"
>
<div
id="digiEmptyNoticeElement"
style="
font-size:10px;
color:#94a3b8;
text-align:center;
width:100%;
padding:10px 0;
"
>
No photo strips saved yet.
</div>
</div>
</div>
</div>
<style>
.digi-theme-classic-white {
background:#fff;
border:1px solid #e2e8f0;
}
.digi-theme-sleek-black {
background:#1a1a1a;
border:1px solid #000;
}
.digi-theme-zebra-print {
background:
repeating-linear-gradient(
-45deg,
#000,
#000 7px,
#fff 7px,
#fff 14px
);
border:1px solid #222;
}
.digi-photo-strip {
width:120px;
padding:8px;
box-sizing:border-box;
border-radius:2px;
box-shadow:0 3px 10px rgba(0,0,0,.25);
}
.digi-strip-photo {
width:100%;
display:block;
margin-bottom:6px;
object-fit:cover;
}
.digi-strip-photo:last-child {
margin-bottom:0;
}
.digi-gallery-strip {
flex:0 0 auto;
width:75px;
padding:5px;
background:#fff;
border:1px solid #ddd;
box-shadow:0 2px 7px rgba(0,0,0,.15);
cursor:pointer;
}
.digi-gallery-strip img {
display:block;
width:100%;
}
</style>
<script>
(function () {
"use strict";
/* =========================================================
DIGI CAMERA STATE
========================================================= */
let digiMediaStream = null;
let digiCapturedImagesBuffer = [];
let digiCurrentStripData = null;
/* =========================================================
ELEMENTS
========================================================= */
const digiVideo = document.getElementById("digiCamFeed");
const digiCanvas = document.getElementById("digiHiddenCanvas");
const digiStandby = document.getElementById("digiStandbyText");
const digiFlash = document.getElementById("digiFlashLayer");
const digiCountdown = document.getElementById("digiCountdownNumber");
const digiPowerButton =
document.getElementById("digiPowerToggleBtn");
const digiCaptureButton =
document.getElementById("digiCaptureStripBtn");
const digiPreview =
document.getElementById("digiPreviewCard");
const digiStripBox =
document.getElementById("digiRenderedStripBox");
const digiThemeMenu =
document.getElementById("digiStripThemeMenu");
const digiStatus =
document.getElementById("digiStatusMessage");
const digiSaveButton =
document.getElementById("digiSaveGalleryBtn");
const digiGallery =
document.getElementById("digiGalleryDisplayShelf");
/* =========================================================
STATUS MESSAGE
========================================================= */
function setDigiStatus(message, color) {
digiStatus.textContent = message || "";
digiStatus.style.color = color || "#64748b";
}
/* =========================================================
CAMERA POWER
========================================================= */
async function toggleDigiCameraEngine() {
/* CAMERA IS CURRENTLY ON */
if (digiMediaStream) {
stopDigiCamera();
return;
}
/* CAMERA IS CURRENTLY OFF */
if (!navigator.mediaDevices ||
!navigator.mediaDevices.getUserMedia) {
setDigiStatus(
"Camera access is not supported here.",
"#dc2626"
);
return;
}
digiPowerButton.disabled = true;
digiPowerButton.textContent = "Starting Camera...";
setDigiStatus("Requesting camera permission...", "#64748b");
try {
const stream =
await navigator.mediaDevices.getUserMedia({
video: {
facingMode: "user",
width: {
ideal: 640
},
height: {
ideal: 480
}
},
audio: false
});
digiMediaStream = stream;
digiVideo.srcObject = stream;
digiVideo.style.display = "block";
digiStandby.style.display = "none";
/*
* Make absolutely certain the video actually begins
* rendering before enabling the photo button.
*/
try {
await digiVideo.play();
} catch (playError) {
console.log("Video play notice:", playError);
}
digiPowerButton.textContent = "Power Off";
digiPowerButton.style.background = "#f44336";
digiPowerButton.disabled = false;
digiCaptureButton.style.display = "block";
setDigiStatus(
"Camera ready — take your 3-photo strip!",
"#16a34a"
);
} catch (error) {
console.error("Digi camera error:", error);
digiMediaStream = null;
digiPowerButton.textContent = "Power On Camera";
digiPowerButton.style.background = "#4a0d25";
digiPowerButton.disabled = false;
digiVideo.style.display = "none";
digiStandby.style.display = "block";
digiCaptureButton.style.display = "none";
if (error.name === "NotAllowedError") {
setDigiStatus(
"Camera permission was denied.",
"#dc2626"
);
alert(
"Camera permission was denied.\n\n" +
"Please allow camera access for your Blogger site, " +
"then press Power On Camera again."
);
} else if (error.name === "NotFoundError") {
setDigiStatus(
"No camera was found.",
"#dc2626"
);
} else if (error.name === "NotReadableError") {
setDigiStatus(
"Your camera is being used by another app.",
"#dc2626"
);
} else if (error.name === "SecurityError") {
setDigiStatus(
"Browser security blocked the camera.",
"#dc2626"
);
} else {
setDigiStatus(
"Could not start the camera.",
"#dc2626"
);
}
}
}
/* =========================================================
STOP CAMERA
========================================================= */
function stopDigiCamera() {
if (digiMediaStream) {
digiMediaStream
.getTracks()
.forEach(function (track) {
track.stop();
});
}
digiMediaStream = null;
digiVideo.srcObject = null;
digiVideo.style.display = "none";
digiStandby.style.display = "block";
digiCaptureButton.style.display = "none";
digiPowerButton.textContent = "Power On Camera";
digiPowerButton.style.background = "#4a0d25";
setDigiStatus("Camera is off.", "#64748b");
}
/* =========================================================
PHOTO STRIP SEQUENCE
========================================================= */
async function runDigiBoothSequence() {
if (!digiMediaStream) {
setDigiStatus(
"Please power on the camera first.",
"#dc2626"
);
return;
}
if (!digiVideo.videoWidth ||
!digiVideo.videoHeight) {
setDigiStatus(
"Camera is still starting. Try again in a moment.",
"#dc2626"
);
return;
}
digiCapturedImagesBuffer = [];
digiPreview.style.display = "none";
digiCaptureButton.disabled = true;
digiPowerButton.disabled = true;
setDigiStatus(
"Get ready... your photo strip is starting!",
"#2563eb"
);
try {
for (let photoNumber = 1; photoNumber <= 3; photoNumber++) {
await runDigiCountdown(photoNumber);
await captureDigiPhoto();
/*
* Small pause between photographs so the sequence
* feels like a real photo booth.
*/
if (photoNumber < 3) {
await digiWait(500);
}
}
buildDigiFinalizedFilmStrip();
digiCaptureButton.disabled = false;
digiPowerButton.disabled = false;
setDigiStatus(
"All 3 photos captured!",
"#16a34a"
);
} catch (error) {
console.error("Photo sequence error:", error);
digiCaptureButton.disabled = false;
digiPowerButton.disabled = false;
setDigiStatus(
"Something went wrong while taking the photos.",
"#dc2626"
);
}
}
/* =========================================================
COUNTDOWN
========================================================= */
function runDigiCountdown(photoNumber) {
return new Promise(function (resolve) {
let number = 3;
digiCountdown.textContent = number;
digiCountdown.style.display = "block";
setDigiStatus(
"Photo " + photoNumber + " of 3",
"#2563eb"
);
const timer = setInterval(function () {
number--;
if (number > 0) {
digiCountdown.textContent = number;
} else {
clearInterval(timer);
digiCountdown.style.display = "none";
resolve();
}
}, 700);
});
}
/* =========================================================
CAPTURE CURRENT VIDEO FRAME
========================================================= */
function captureDigiPhoto() {
return new Promise(function (resolve) {
const width = digiVideo.videoWidth || 640;
const height = digiVideo.videoHeight || 480;
digiCanvas.width = width;
digiCanvas.height = height;
const ctx = digiCanvas.getContext("2d");
/*
* Mirror the saved photograph so it matches the
* mirrored camera preview.
*/
ctx.save();
ctx.translate(width, 0);
ctx.scale(-1, 1);
ctx.drawImage(
digiVideo,
0,
0,
width,
height
);
ctx.restore();
/*
* Flash effect.
*/
digiFlash.style.opacity = "1";
setTimeout(function () {
digiFlash.style.opacity = "0";
}, 100);
/*
* Save an independent image.
*/
const imageData =
digiCanvas.toDataURL("image/jpeg", 0.92);
digiCapturedImagesBuffer.push(imageData);
resolve();
});
}
/* =========================================================
BUILD FINAL STRIP
========================================================= */
function buildDigiFinalizedFilmStrip() {
digiStripBox.innerHTML = "";
const theme =
digiThemeMenu.value;
const strip =
document.createElement("div");
strip.id = "digiTargetFilmStripObject";
strip.className =
"digi-photo-strip digi-theme-" + theme;
/*
* Add all three photographs.
*/
digiCapturedImagesBuffer.forEach(function (imageData) {
const image =
document.createElement("img");
image.src = imageData;
image.className =
"digi-strip-photo";
strip.appendChild(image);
});
/*
* Little retro footer.
*/
const footer =
document.createElement("div");
footer.style.cssText =
"font-family:monospace;" +
"font-size:6px;" +
"text-align:center;" +
"padding-top:6px;" +
"letter-spacing:1px;" +
"color:" +
(theme === "sleek-black" ? "#fff" : "#333") +
";";
footer.textContent =
"DIGI • Y2K • PHOTO BOOTH";
strip.appendChild(footer);
digiStripBox.appendChild(strip);
digiCurrentStripData =
createFullStripImage();
digiPreview.style.display = "flex";
}
/* =========================================================
CREATE SINGLE SAVABLE STRIP IMAGE
========================================================= */
function createFullStripImage() {
const photos =
digiCapturedImagesBuffer;
const theme =
digiThemeMenu.value;
if (!photos.length) {
return null;
}
const stripCanvas =
document.createElement("canvas");
const photoWidth = 500;
const photoHeight = 375;
const padding = 30;
const gap = 20;
const footerHeight = 55;
stripCanvas.width =
photoWidth + (padding * 2);
stripCanvas.height =
(photoHeight * photos.length) +
(gap * (photos.length - 1)) +
(padding * 2) +
footerHeight;
const ctx =
stripCanvas.getContext("2d");
/*
* Background.
*/
if (theme === "sleek-black") {
ctx.fillStyle = "#1a1a1a";
ctx.fillRect(
0,
0,
stripCanvas.width,
stripCanvas.height
);
} else if (theme === "zebra-print") {
ctx.fillStyle = "#fff";
ctx.fillRect(
0,
0,
stripCanvas.width,
stripCanvas.height
);
/*
* Zebra effect around the edges.
*/
ctx.strokeStyle = "#000";
ctx.lineWidth = 18;
for (
let y = 0;
y < stripCanvas.height;
y += 35
) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(
stripCanvas.width,
y + 25
);
ctx.stroke();
}
} else {
ctx.fillStyle = "#fff";
ctx.fillRect(
0,
0,
stripCanvas.width,
stripCanvas.height
);
}
/*
* Load each photograph and draw it.
*/
return new Promise(function (resolve) {
let loaded = 0;
photos.forEach(function (src, index) {
const image =
new Image();
image.onload = function () {
const y =
padding +
index * (photoHeight + gap);
/*
* White/black photo border.
*/
ctx.fillStyle =
theme === "sleek-black"
? "#fff"
: "#f8f8f8";
ctx.fillRect(
padding - 4,
y - 4,
photoWidth + 8,
photoHeight + 8
);
ctx.drawImage(
image,
padding,
y,
photoWidth,
photoHeight
);
loaded++;
if (loaded === photos.length) {
const footerY =
stripCanvas.height - 28;
ctx.textAlign = "center";
ctx.font =
"bold 16px monospace";
ctx.fillStyle =
theme === "sleek-black"
? "#fff"
: "#222";
ctx.fillText(
"DIGI • Y2K • PHOTO BOOTH",
stripCanvas.width / 2,
footerY
);
resolve(
stripCanvas.toDataURL(
"image/jpeg",
0.92
)
);
}
};
image.src = src;
});
});
}
/* =========================================================
SAVE TO GALLERY
========================================================= */
async function saveToDigiGalleryShelf() {
if (!digiCapturedImagesBuffer.length) {
setDigiStatus(
"Take a photo strip first.",
"#dc2626"
);
return;
}
digiSaveButton.disabled = true;
digiSaveButton.textContent = "Saving...";
try {
/*
* Because createFullStripImage is asynchronous,
* wait for the final strip image.
*/
const stripImage =
await createFullStripImage();
if (!stripImage) {
throw new Error("Could not create strip image.");
}
const savedGallery =
JSON.parse(
localStorage.getItem("digiPhotoGallery") || "[]"
);
savedGallery.push({
image: stripImage,
created:
new Date().toISOString()
});
/*
* Keep the most recent 20 strips.
*/
const trimmedGallery =
savedGallery.slice(-20);
localStorage.setItem(
"digiPhotoGallery",
JSON.stringify(trimmedGallery)
);
renderDigiGallery();
setDigiStatus(
"Saved to your gallery!",
"#16a34a"
);
} catch (error) {
console.error("Gallery save error:", error);
setDigiStatus(
"Could not save this strip.",
"#dc2626"
);
}
digiSaveButton.disabled = false;
digiSaveButton.textContent =
"💾 Save to Gallery Page";
}
/* =========================================================
RENDER GALLERY
========================================================= */
function renderDigiGallery() {
digiGallery.innerHTML = "";
const savedGallery =
JSON.parse(
localStorage.getItem("digiPhotoGallery") || "[]"
);
if (!savedGallery.length) {
const empty =
document.createElement("div");
empty.style.cssText =
"font-size:10px;" +
"color:#94a3b8;" +
"text-align:center;" +
"width:100%;" +
"padding:10px 0;";
empty.textContent =
"No photo strips saved yet.";
digiGallery.appendChild(empty);
return;
}
savedGallery
.slice()
.reverse()
.forEach(function (item) {
const wrapper =
document.createElement("div");
wrapper.className =
"digi-gallery-strip";
const image =
document.createElement("img");
image.src =
item.image;
/*
* Clicking a saved thumbnail opens it.
*/
wrapper.addEventListener(
"click",
function () {
const popup =
window.open("", "_blank");
if (popup) {
popup.document.write(
"<title>My Y2K Photo Strip</title>" +
"<style>" +
"body{margin:0;background:#111;" +
"display:flex;justify-content:center;" +
"align-items:center;min-height:100vh;}" +
"img{max-width:95vw;max-height:95vh;}" +
"</style>" +
"<img src='" +
item.image +
"'>"
);
}
}
);
wrapper.appendChild(image);
digiGallery.appendChild(wrapper);
});
}
/* =========================================================
WAIT HELPER
========================================================= */
function digiWait(milliseconds) {
return new Promise(function (resolve) {
setTimeout(
resolve,
milliseconds
);
});
}
/* =========================================================
BUTTON EVENTS
========================================================= */
digiPowerButton.addEventListener(
"click",
toggleDigiCameraEngine
);
digiCaptureButton.addEventListener(
"click",
runDigiBoothSequence
);
digiSaveButton.addEventListener(
"click",
saveToDigiGalleryShelf
);
/* =========================================================
INITIALIZE GALLERY
========================================================= */
renderDigiGallery();
/* =========================================================
EXPOSE FUNCTIONS GLOBALLY
This is important for Blogger if it rewrites/handles
inline button handlers.
========================================================= */
window.toggleDigiCameraEngine =
toggleDigiCameraEngine;
window.runDigiBoothSequence =
runDigiBoothSequence;
window.saveToDigiGalleryShelf =
saveToDigiGalleryShelf;
})();
</script>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Ipod with Playlist
<!-- Retro Silver iPod Classic Sidebar Widget -->
<div style="display: flex; justify-content: center; align-items: center; padding: 10px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
<!-- Sleek, Transparent-Edge Silver iPod Body (Width: 200px) -->
<div style="width: 200px; height: 230px; background: linear-gradient(135deg, #e0e0e0 0%, #f5f5f5 25%, #bebebe 70%, #9e9e9e 100%); border-radius: 16px; box-shadow: inset 0 2px 4px rgba(255,255,255,0.6), 0 6px 15px rgba(0,0,0,0.15); padding: 14px 12px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; position: relative;">
<!-- Metallic Sheen Layer -->
<div style="position: absolute; top:0; left:0; width:100%; height:100%; border-radius:16px; background: linear-gradient(to right, rgba(255,255,255,0.15) 0%, rgba(0,0,0,0.02) 50%, rgba(255,255,255,0.15) 100%); pointer-events: none;"></div>
<!-- Pristine Glass Screen Area (Perfect 4:3 Ratio fit) -->
<div style="width: 100%; height: 110px; background: #ffffff; border: 3px solid #333333; border-radius: 4px; box-shadow: inset 0 2px 5px rgba(0,0,0,0.2); overflow: hidden; display: flex; flex-direction: column; position: relative; z-index: 1;">
<!-- Classic Top Navigation Bar -->
<div style="display: flex; justify-content: space-between; align-items: center; padding: 2px 5px; font-size: 9px; font-weight: bold; color: #333; border-bottom: 1px solid #b5b5b5; background: linear-gradient(180deg, #f0f0f0 0%, #dbdbdb 100%); letter-spacing: 0.2px;">
<span style="visibility: hidden; width: 10px;">■</span>
<span>iPod</span>
<!-- Small Battery icon -->
<div style="width: 12px; height: 6px; border: 1px solid #444; padding: 0.5px; display: flex; align-items: center; position: relative;">
<div style="width: 100%; height: 100%; background-color: #4caf50;"></div>
<div style="position: absolute; right: -2px; top: 1px; width: 1px; height: 2px; background-color: #444;"></div>
</div>
</div>
<!-- Live Apple Music Embed Window -->
<div style="flex-grow: 1; width: 100%; overflow: hidden; background: #fff;">
<iframe allow="autoplay *; encrypted-media *; fullscreen *; clipboard-write" frameborder="0" height="85" style="width:100%; border:none;" sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation-by-user-activation" src="https://embed.music.apple.com/us/playlist/fall-essentials/pl.u-d2b0kyjtMo2eYKo"></iframe>
</div>
</div>
<!-- Native Built-In Click Wheel Layer -->
<div style="width: 82px; height: 82px; background: radial-gradient(circle, #ffffff 0%, #fcfcfc 60%, #ededed 100%); border-radius: 50%; margin-top: auto; margin-bottom: 2px; box-shadow: 0 2px 5px rgba(0,0,0,0.1), inset 0 -1px 3px rgba(0,0,0,0.05); display: flex; justify-content: center; align-items: center; position: relative; z-index: 1;">
<!-- Text Labels -->
<span style="position: absolute; top: 5px; font-size: 6.5px; font-weight: bold; color: #777; letter-spacing: 0.1px; cursor: default;">MENU</span>
<span style="position: absolute; right: 6px; font-size: 6.5px; color: #777; cursor: default;">▶▶|</span>
<span style="position: absolute; left: 6px; font-size: 6.5px; color: #777; cursor: default;">|◀◀</span>
<span style="position: absolute; bottom: 5px; font-size: 6.5px; color: #777; cursor: default;">▶||</span>
<!-- Matte Center Action Button -->
<div style="width: 28px; height: 28px; background: radial-gradient(circle, #ffffff 0%, #eaeaea 100%); border-radius: 50%; box-shadow: 0 1px 2px rgba(0,0,0,0.05); border: 1px solid rgba(0,0,0,0.02);"></div>
</div>
</div>
</div>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Paint Gadget
<iframe src="https://jspaint.app/" height="270px" width="250px" title="MS Paint Widget"></iframe>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Rainbow Star Trail Cursor
<!-- Fixed Rainbow Star Trail Cursor Effect -->
<style>
.trail-star {
position: fixed; /* Changed to fixed to prevent pushing text layout */
font-size: 24px;
line-height: 1;
pointer-events: none;
user-select: none;
z-index: 999999;
transform: translate(-50%, -50%);
animation: fadeOut 0.8s forwards ease-out;
}
@keyframes fadeOut {
0% {
opacity: 1;
transform: translate(-50%, -50%) scale(1) rotate(0deg);
}
100% {
opacity: 0;
transform: translate(-50%, -50%) scale(0.3) rotate(180deg);
}
}
</style>
<script>
(function() {
// Array of rainbow colors
const colors = ['#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#0000FF', '#4B0082', '#9400D3'];
let colorIndex = 0;
window.addEventListener('mousemove', function(e) {
const star = document.createElement('div');
star.className = 'trail-star';
star.innerHTML = '★';
star.style.color = colors[colorIndex];
colorIndex = (colorIndex + 1) % colors.length;
// Position directly based on viewport coordinates
star.style.left = e.clientX + 'px';
star.style.top = e.clientY + 'px';
// Append safely to the body body directly without an inner container
document.body.appendChild(star);
setTimeout(() => {
star.remove();
}, 800);
});
})();
</script>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
Daily Tarot Reading
<!-- Daily Tarot Widget -->
<div id="tarot-day-widget">
<style>
#tarot-day-widget {
background-image: url("https://i.pinimg.com/736x/7a/f8/0e/7af80e45f18362edd389744e2c8b32d0.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
font-family: Georgia, serif;
color: #f7efff;
text-align: center;
padding: 16px 10px;
border-radius: 18px;
box-sizing: border-box;
max-width: 235px;
margin: 0 auto;
border: 1px solid rgba(255,255,255,0.28);
box-shadow: 0 10px 30px rgba(45, 20, 60, 0.25);
}
#tarot-day-widget h3 {
margin: 0 0 6px;
font-size: 25px;
font-weight: normal;
letter-spacing: 1px;
}
#tarot-day-widget .intro {
margin: 0 0 11px;
font-size: 14px;
color: #f2e6fb;
opacity: 0.9;
}
.tarot-scene {
width: 125px;
height: 150px;
perspective: 900px;
margin: 0 auto 12px;
}
.tarot-card {
width: 125px;
height: 150px;
position: relative;
transform-style: preserve-3d;
transition: transform 1s ease;
}
.tarot-card.revealed {
transform: rotateY(180deg);
}
.tarot-face {
position: absolute;
width: 125px;
height: 150px;
inset: 0;
backface-visibility: hidden;
border-radius: 12px;
background: linear-gradient(145deg, #a83d78, #7d2859);
border: 1px solid rgba(255,255,255,0.45);
box-shadow:
inset 0 0 0 5px rgba(255,255,255,0.08),
inset 0 0 28px rgba(255,255,255,0.08),
0 8px 20px rgba(45,20,60,0.35);
overflow: hidden;
}
.tarot-back:before,
.tarot-back:after,
.tarot-front:before,
.tarot-front:after {
content: "";
position: absolute;
border: 1px solid rgba(255,255,255,0.42);
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.tarot-back:before,
.tarot-front:before {
width: 72px;
height: 72px;
}
.tarot-back:after,
.tarot-front:after {
width: 44px;
height: 44px;
opacity: 0.65;
}
.card-line {
position: absolute;
background: rgba(255,255,255,0.42);
}
.line-top,
.line-bottom {
width: 78px;
height: 1px;
left: 23px;
}
.line-top {
top: 18px;
}
.line-bottom {
bottom: 18px;
}
.line-left,
.line-right {
width: 1px;
height: 96px;
top: 27px;
}
.line-left {
left: 18px;
}
.line-right {
right: 18px;
}
.css-star {
position: absolute;
width: 1px;
height: 18px;
background: rgba(255,255,255,0.78);
left: 62px;
top: 66px;
}
.css-star:before {
content: "";
position: absolute;
width: 18px;
height: 1px;
background: rgba(255,255,255,0.78);
left: -8.5px;
top: 8.5px;
}
.css-moon {
position: absolute;
width: 24px;
height: 24px;
border-radius: 50%;
background: rgba(255,255,255,0.78);
left: 50px;
top: 57px;
}
.css-moon:after {
content: "";
position: absolute;
width: 24px;
height: 24px;
border-radius: 50%;
background: #76194f;
left: 8px;
top: -1px;
}
.corner-dot {
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
background: rgba(255,255,255,0.55);
}
.dot-a {
top: 12px;
left: 12px;
}
.dot-b {
top: 12px;
right: 12px;
}
.dot-c {
bottom: 12px;
left: 12px;
}
.dot-d {
bottom: 12px;
right: 12px;
}
.tarot-front {
transform: rotateY(180deg);
background: linear-gradient(145deg, #963565, #681f4a);
}
.front-title {
position: absolute;
width: 100%;
top: 104px;
left: 0;
padding: 0 10px;
box-sizing: border-box;
font-size: 14px;
line-height: 1.1;
color: #fff7ff;
letter-spacing: 0.4px;
}
.tarot-button {
font-family: Georgia, serif;
background: rgba(255,255,255,0.12);
color: #fff7ff;
border: 1px solid rgba(255,255,255,0.52);
border-radius: 999px;
padding: 7px 16px;
cursor: pointer;
font-size: 14px;
letter-spacing: 0.5px;
transition: all 0.25s ease;
}
.tarot-button:hover {
background: rgba(255,255,255,0.22);
transform: translateY(-1px);
}
.tarot-button:disabled {
opacity: 0.55;
cursor: default;
transform: none;
}
.tarot-result {
margin-top: 11px;
opacity: 0;
transform: translateY(8px);
transition: opacity 0.7s ease, transform 0.7s ease;
}
.tarot-result.visible {
opacity: 1;
transform: translateY(0);
}
.tarot-result h4 {
margin: 0 0 5px;
font-size: 21px;
font-weight: normal;
color: #fff9ff;
}
.tarot-keywords {
margin: 0 0 7px;
font-size: 12px;
color: #eadcf4;
letter-spacing: 0.4px;
}
.tarot-meaning {
min-height: 38px;
margin: 0 auto;
font-size: 13px;
line-height: 1.3;
color: #f8efff;
max-width: 205px;
}
</style>
<h3>Daily Tarot</h3>
<p class="intro">Reveal your card…</p>
<div class="tarot-scene">
<div class="tarot-card" id="tarotCard">
<div class="tarot-face tarot-back">
<span class="card-line line-top"></span>
<span class="card-line line-bottom"></span>
<span class="card-line line-left"></span>
<span class="card-line line-right"></span>
<span class="corner-dot dot-a"></span>
<span class="corner-dot dot-b"></span>
<span class="corner-dot dot-c"></span>
<span class="corner-dot dot-d"></span>
<span class="css-star"></span>
</div>
<div class="tarot-face tarot-front">
<span class="card-line line-top"></span>
<span class="card-line line-bottom"></span>
<span class="card-line line-left"></span>
<span class="card-line line-right"></span>
<span class="corner-dot dot-a"></span>
<span class="corner-dot dot-b"></span>
<span class="corner-dot dot-c"></span>
<span class="corner-dot dot-d"></span>
<span class="css-moon"></span>
<div class="front-title" id="frontTitle">
Hidden Arcana
</div>
</div>
</div>
</div>
<button class="tarot-button" id="revealTarotBtn">
Reveal card
</button>
<div class="tarot-result" id="tarotResult">
<h4 id="tarotName"></h4>
<p class="tarot-keywords" id="tarotKeywords"></p>
<p class="tarot-meaning" id="tarotMeaning"></p>
</div>
<script>
(function () {
const tarotData = [
{
name: "The Fool",
keywords: ["Beginnings, Trust, Freedom, Threshold"],
meaning: "Step gently into the unknown. Not all paths need proof before beginning."
},
{
name: "The Magician",
keywords: ["Will, Focus, Creation, Skill"],
meaning: "What you need is already close to your hands. Turn your intention into action."
},
{
name: "The High Priestess",
keywords: ["Intuition, Silence, Mystery, Knowledge"],
meaning: "There is wisdom beneath the surface. Listen before responding."
},
{
name: "The Empress",
keywords: ["Nurturing, Beauty, Growth, Reception"],
meaning: "Protect what is delicate. Something grows when it is not forced to rush."
},
{
name: "The Emperor",
keywords: ["Structure, Authority, Order, Discipline"],
meaning: "A quiet boundary can also be an act of love. Build something that can sustain you."
},
{
name: "The Hierophant",
keywords: ["Tradition, Guidance, Ritual, Learning"],
meaning: "Return to that which is sacred and stable. A lesson arrives through patience."
},
{
name: "The Lovers",
keywords: ["Choice, Union, Values, Devotion"],
meaning: "Choose from calm rather than fear. The heart knows when it is divided."
},
{
name: "The Chariot",
keywords: ["Direction, Victory, Control, Determination"],
meaning: "Gather your will and move forward with purpose. Momentum is born of your own decision."
},
{
name: "Strength",
keywords: ["Courage, Grace, Patience, Compassion"],
meaning: "Gentleness is not weakness. Your tenderness can be today's most powerful strength."
},
{
name: "The Hermit",
keywords: ["Solitude, Reflection, Wisdom, Inner Light"],
meaning: "Step away without disappearing. The quiet path reveals what the noise conceals."
},
{
name: "Wheel of Fortune",
keywords: ["Change, Cycles, Destiny, Movement"],
meaning: "The wheel turns whether you resist or breathe. Welcome change with open hands."
},
{
name: "Justice",
keywords: ["Truth, Balance, Clarity, Responsibility"],
meaning: "Look clearly at what is fair. Truth calls for courage, not harshness."
},
{
name: "The Hanged Man",
keywords: ["Pause, Surrender, Perspective, Release"],
meaning: "Do not force the door. A new perspective appears when you stop pushing."
},
{
name: "Death",
keywords: ["Ending, Renewal, Release, Transformation"],
meaning: "What disappears leaves room to breathe. Allow the old skin to shed."
},
{
name: "Temperance",
keywords: ["Harmony, Healing, Moderation, Flow"],
meaning: "Blend things slowly. The right balance is found through small, sincere adjustments."
},
{
name: "The Devil",
keywords: ["Attachment, Shadow, Desire, Awareness"],
meaning: "Name what binds you without shame. Seeing the chain is the first step to loosening it."
},
{
name: "The Tower",
keywords: ["Breakthrough, Truth, Awakening, Release"],
meaning: "What cannot hold up may fall. Let the revelation clear away false foundations."
},
{
name: "The Star",
keywords: ["Hope, Renewal, Faith, Stillness"],
meaning: "A softer light returns. Trust in the quiet renewal that is already beginning."
},
{
name: "The Moon",
keywords: ["Dreams, Illusion, Instinct, Depth"],
meaning: "Not everything is meant to be clear tonight. Walk gently through the uncertainty."
},
{
name: "The Sun",
keywords: ["Joy, Vitality, Clarity, Warmth"],
meaning: "Allow yourself to be seen without apologizing. Light reveals what fear once hid."
},
{
name: "Judgement",
keywords: ["Calling, Awakening, Return, Decision"],
meaning: "A deeper part of you is asking to be heard. Rise without carrying all your old names."
},
{
name: "The World",
keywords: ["Completion, Wholeness, Arrival, Integration"],
meaning: "A cycle closes with grace. Honor the entire path your spirit has traveled."
}
];
const card = document.getElementById("tarotCard");
const button = document.getElementById("revealTarotBtn");
const result = document.getElementById("tarotResult");
const nameEl = document.getElementById("tarotName");
const keywordsEl = document.getElementById("tarotKeywords");
const meaningEl = document.getElementById("tarotMeaning");
const frontTitle = document.getElementById("frontTitle");
const today = new Date().toISOString().slice(0, 10);
const storageKey = "dailyTarotCard";
function typeText(element, text, speed) {
element.textContent = "";
let index = 0;
function write() {
if (index < text.length) {
element.textContent += text.charAt(index);
index++;
setTimeout(write, speed);
}
}
write();
}
function showCard(cardData, instant) {
frontTitle.textContent = cardData.name;
nameEl.textContent = cardData.name;
keywordsEl.textContent =
cardData.keywords.join(" · ");
card.classList.add("revealed");
button.disabled = true;
button.textContent = "Card revealed";
setTimeout(function () {
result.classList.add("visible");
if (instant) {
meaningEl.textContent = cardData.meaning;
} else {
typeText(
meaningEl,
cardData.meaning,
28
);
}
}, instant ? 100 : 850);
}
function getSavedCard() {
try {
const saved =
JSON.parse(
localStorage.getItem(storageKey)
);
if (
saved &&
saved.date === today &&
typeof saved.index === "number"
) {
return saved.index;
}
} catch (e) {}
return null;
}
function saveCard(index) {
localStorage.setItem(
storageKey,
JSON.stringify({
date: today,
index: index
})
);
}
const savedIndex = getSavedCard();
if (
savedIndex !== null &&
tarotData[savedIndex]
) {
showCard(
tarotData[savedIndex],
true
);
}
button.addEventListener(
"click",
function () {
const existingIndex =
getSavedCard();
if (
existingIndex !== null &&
tarotData[existingIndex]
) {
showCard(
tarotData[existingIndex],
false
);
return;
}
const randomIndex =
Math.floor(
Math.random() *
tarotData.length
);
saveCard(randomIndex);
showCard(
tarotData[randomIndex],
false
);
}
);
})();
</script>
</div>
⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱⊰ ──── ❀ ──── ⊱
.gif)
No comments:
Post a Comment