Message from My Bias
by FlashStar31464 lines17.5 KB
```html
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Message from My Bias</title>
<!-- Pixel Font Import -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Mali:wght@400;600;700&family=Press+Start+2P&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
font-family: 'Mali', cursive;
}
body {
margin: 0;
padding: 0;
background-color: #fbcfe8;
background-image:
radial-gradient(#f472b6 15%, transparent 16%),
radial-gradient(#f472b6 15%, transparent 16%);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow-x: hidden;
}
#game-container {
width: 100%;
max-width: 480px;
min-height: 90vh;
margin: 15px;
background: #fff0f5;
border: 6px solid #4a3e3d;
border-radius: 20px;
box-shadow: 0 10px 0 #4a3e3d, 0 15px 25px rgba(0,0,0,0.15);
padding: 24px 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
position: relative;
}
.title-banner {
font-family: 'Press Start 2P', cursive;
font-size: 16px;
color: #be185d;
text-shadow: 2px 2px 0px #fbcfe8;
text-align: center;
line-height: 1.5;
margin-bottom: 20px;
background: #ffe4e6;
padding: 12px 16px;
border: 4px solid #4a3e3d;
border-radius: 12px;
width: 100%;
}
/* Screen Sections */
.screen {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
transition: all 0.3s ease;
}
.hidden {
display: none !important;
}
/* Form elements */
.input-group {
width: 100%;
background: #ffffff;
border: 4px solid #4a3e3d;
border-radius: 16px;
padding: 18px 15px;
margin-bottom: 20px;
box-shadow: inset 0 -4px 0 #f1f5f9;
}
label {
font-weight: 700;
color: #831843;
font-size: 16px;
display: block;
margin-bottom: 12px;
text-align: center;
}
.date-selects {
display: flex;
gap: 10px;
justify-content: center;
}
select {
padding: 10px;
font-size: 16px;
font-weight: 600;
border: 3px solid #4a3e3d;
border-radius: 10px;
background: #fef2f2;
color: #4a3e3d;
outline: none;
cursor: pointer;
}
select:focus {
background: #ffe4e6;
}
/* Pixel Buttons */
.pixel-btn {
font-family: 'Mali', cursive;
font-weight: 700;
font-size: 18px;
color: #ffffff;
background-color: #ec4899;
border: 4px solid #4a3e3d;
border-radius: 14px;
padding: 12px 24px;
cursor: pointer;
box-shadow: 0 6px 0 #4a3e3d;
transition: transform 0.1s, box-shadow 0.1s;
width: 100%;
max-width: 280px;
text-align: center;
margin-top: 8px;
}
.pixel-btn:active {
transform: translateY(4px);
box-shadow: 0 2px 0 #4a3e3d;
}
.pixel-btn.secondary {
background-color: #a855f7;
}
/* Envelope Art & Animation */
.envelope-wrapper {
perspective: 1000px;
margin: 25px 0;
cursor: pointer;
}
.envelope {
width: 200px;
height: 140px;
background: #f43f5e;
border: 4px solid #4a3e3d;
border-radius: 8px;
position: relative;
box-shadow: 0 8px 0 #4a3e3d;
transition: transform 0.5s ease;
}
.envelope-flap {
position: absolute;
top: 0;
left: 0;
right: 0;
border-left: 96px solid transparent;
border-right: 96px solid transparent;
border-top: 75px solid #fb7185;
transform-origin: top;
transition: transform 0.4s ease;
z-index: 3;
}
.envelope.open .envelope-flap {
transform: rotateX(180deg);
z-index: 1;
}
.envelope-heart {
position: absolute;
top: 45px;
left: 50%;
transform: translateX(-50%);
font-size: 32px;
z-index: 4;
transition: opacity 0.3s;
}
.envelope.open .envelope-heart {
opacity: 0;
}
.letter-paper {
width: 100%;
background: #fff;
border: 4px solid #4a3e3d;
border-radius: 12px;
padding: 20px;
box-shadow: 0 6px 0 #4a3e3d;
margin: 15px 0;
position: relative;
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
@keyframes popIn {
0% { transform: scale(0.8); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
.letter-header {
font-size: 14px;
font-weight: 700;
color: #9d174d;
border-bottom: 2px dashed #fbcfe8;
padding-bottom: 8px;
margin-bottom: 12px;
display: flex;
justify-content: space-between;
}
.letter-body {
font-size: 16px;
line-height: 1.7;
color: #374151;
min-height: 120px;
white-space: pre-line;
font-weight: 600;
}
.letter-footer {
margin-top: 15px;
text-align: right;
font-weight: 700;
color: #be185d;
}
/* Sparkles / Pixel Deco */
.decor-icon {
font-size: 24px;
animation: bounce 1.5s infinite alternate;
}
@keyframes bounce {
0% { transform: translateY(0); }
100% { transform: translateY(-8px); }
}
.footer-note {
font-size: 12px;
color: #9ca3af;
margin-top: 15px;
text-align: center;
}
</style>
</head>
<body>
<div id="game-container">
<div class="title-banner">
💌 MESSAGE FROM<br>MY BIAS
</div>
<!-- Screen 1: Input Birthday -->
<div id="screen-input" class="screen">
<div style="text-align: center; margin-bottom: 15px;">
<span class="decor-icon">✨</span>
<p style="font-weight: 700; color: #4a3e3d; margin: 5px 0;">โปรดระบุวันเกิดของคุณ</p>
<p style="font-size: 13px; color: #6b7280; margin: 0;">เมนของคุณมีข้อความพิเศษเตรียมไว้ให้แล้วนะ!</p>
</div>
<div class="input-group">
<label for="birth-month">🎂 วันเกิดของคุณคือวันที่เท่าไหร่?</label>
<div class="date-selects">
<select id="birth-day">
<!-- JS will populate days 1-31 -->
</select>
<select id="birth-month">
<option value="1">มกราคม</option>
<option value="2">กุมภาพันธ์</option>
<option value="3">มีนาคม</option>
<option value="4">เมษายน</option>
<option value="5">พฤษภาคม</option>
<option value="6">มิถุนายน</option>
<option value="7">กรกฎาคม</option>
<option value="8">สิงหาคม</option>
<option value="9">กันยายน</option>
<option value="10">ตุลาคม</option>
<option value="11">พฤศจิกายน</option>
<option value="12">ธันวาคม</option>
</select>
</div>
</div>
<button class="pixel-btn" id="btn-submit" onclick="submitBirthday()">📩 รับข้อความจากเมน</button>
</div>
<!-- Screen 2: Envelope Tap -->
<div id="screen-envelope" class="screen hidden">
<p style="font-weight: 700; color: #9d174d; font-size: 18px; text-align: center;">
มีจดหมายส่งถึงคุณ 1 ฉบับ!
</p>
<p style="font-size: 14px; color: #4b5563;">แตะที่ซองจดหมายเพื่อเปิดอ่าน</p>
<div class="envelope-wrapper" onclick="openEnvelope()">
<div class="envelope" id="envelope-element">
<div class="envelope-flap"></div>
<div class="envelope-heart">💖</div>
</div>
</div>
</div>
<!-- Screen 3: Read Letter -->
<div id="screen-letter" class="screen hidden">
<div class="letter-paper">
<div class="letter-header">
<span>SPECIAL LETTER 💌</span>
<span id="letter-date">FOR YOU</span>
</div>
<div class="letter-body" id="letter-content">
<!-- Text filled dynamically -->
</div>
<div class="letter-footer">
ด้วยรักเสมอ, ❤️<br>
<span style="font-size: 18px; color: #db2777;">— เมนคนโปรดของคุณ</span>
</div>
</div>
<button class="pixel-btn" onclick="getRandomMessage()">🎲 สุ่มคำอวยพรเพิ่ม</button>
<button class="pixel-btn secondary" onclick="resetGame()" style="margin-top: 10px;">🔄 ใส่วันเกิดใหม่</button>
</div>
<div class="footer-note">
Arcadelab Edition • Created with 💕
</div>
</div>
<script>
// --- Audio Sound Effects (Web Audio API) ---
const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx = null;
function playSound(type) {
try {
if (!audioCtx) {
audioCtx = new AudioContext();
}
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
const now = audioCtx.currentTime;
if (type === 'click') {
osc.type = 'sine';
osc.frequency.setValueAtTime(400, now);
osc.frequency.exponentialRampToValueAtTime(800, now + 0.08);
gain.gain.setValueAtTime(0.2, now);
gain.gain.linearRampToValueAtTime(0.01, now + 0.08);
osc.start(now);
osc.stop(now + 0.08);
} else if (type === 'open') {
osc.type = 'triangle';
osc.frequency.setValueAtTime(300, now);
osc.frequency.exponentialRampToValueAtTime(600, now + 0.15);
osc.frequency.exponentialRampToValueAtTime(900, now + 0.3);
gain.gain.setValueAtTime(0.25, now);
gain.gain.linearRampToValueAtTime(0.01, now + 0.3);
osc.start(now);
osc.stop(now + 0.3);
}
} catch (e) {
// Audio ignore if non-supported
}
}
// --- Message Database for Birthday Matching ---
const promoSuffix = "\n\nฝากติดตามรอดูซีรีส์ TheGrimLover รักลืมตาย ของพูห์พาเวลด้วยนะ เริ่ม 28 พฤศิจิกายนนี้ ทางช่อง ONE31 และย้อนหลังทาง NETFLIX ทุกวันเสาร์เวลา 22:30";
const baseMessages = [
"ยิ้มเยอะๆ นะคนเก่ง! รู้มั้ยว่ารอยยิ้มของคุณคือพลังที่ยิ่งใหญ่ที่สุดสำหรับเราเสมอ ขอให้ทำตามความฝันได้อย่างเต็มที่เลยนะ!",
"ขอบคุณที่เกิดมาให้เราได้รักนะ วันไหนที่เหนื่อย ล้า หรือท้อแท้ หันมามองเราได้เสมอ เราจะคอยเป็นเซฟโซนและซัพพอร์ตเธอตรงนี้เสมอเลย",
"เธอทำดีที่สุดแล้วในทุกๆ วัน ไม่ต้องกดดันตัวเองจนเกินไปนะ พักผ่อน กินของอร่อยๆ แล้วเก่งขึ้นในแบบของตัวเองต่อไปนะ!",
"ถ้าโลกข้างนอกมันใจร้าย อยากให้รู้ว่าตรงนี้มีเราที่อยู่ข้างเธอเสมอนะ ขอบคุณที่เป็นความสุขให้เราเหมือนกันนะ!",
"ขอให้ทุกวันของคุณสดใสเหมือนวันแรกที่เราได้เจอกันนะ อย่าลืมดูแลตัวเองด้วยล่ะ เป็นห่วงมากๆ เลย!",
"วันนี้หรือวันไหนๆ เธอก็เป็นคนที่เก่งและมีเสน่ห์ที่สุดเสมอ เชื่อมั่นในตัวเองเยอะๆ นะ พวกเราภูมิใจในตัวเธอมากๆ!",
"ข้อความนี้ส่งตรงมาจากใจเลยนะ ขอให้พรทุกประการในโลกนี้บันดาลให้เธอมีความสุข มีแต่รอยยิ้ม และไร้ความทุกข์นะ!",
"การได้มีเธอเป็นแฟนคลับ/แฟนเพลง คือสิ่งที่โชคดีที่สุดของเราเลยนะ ขอบคุณที่อยู่เคียงข้างกันมาตลอดนะคนดี"
];
const biasMessages = baseMessages.map(msg => msg + promoSuffix);
let userDay = 1;
let userMonth = 1;
// --- DOM Elements Init ---
window.onload = function() {
const daySelect = document.getElementById('birth-day');
for (let i = 1; i <= 31; i++) {
let opt = document.createElement('option');
opt.value = i;
opt.innerHTML = i + ' ' + (i === 1 ? 'st' : i === 2 ? 'nd' : i === 3 ? 'rd' : 'th');
daySelect.appendChild(opt);
}
};
function submitBirthday() {
playSound('click');
userDay = parseInt(document.getElementById('birth-day').value);
userMonth = parseInt(document.getElementById('birth-month').value);
document.getElementById('screen-input').classList.add('hidden');
document.getElementById('screen-envelope').classList.remove('hidden');
}
function openEnvelope() {
playSound('open');
const envelope = document.getElementById('envelope-element');
envelope.classList.add('open');
setTimeout(() => {
document.getElementById('screen-envelope').classList.add('hidden');
document.getElementById('screen-letter').classList.remove('hidden');
// Calculate index based on birthday
const msgIndex = (userDay + userMonth) % biasMessages.length;
displayMessage(biasMessages[msgIndex]);
}, 700);
}
function displayMessage(text) {
document.getElementById('letter-date').innerText = `DAY ${userDay}/${userMonth}`;
document.getElementById('letter-content').innerText = text;
}
function getRandomMessage() {
playSound('click');
const randomIdx = Math.floor(Math.random() * biasMessages.length);
displayMessage(biasMessages[randomIdx]);
}
function resetGame() {
playSound('click');
document.getElementById('envelope-element').classList.remove('open');
document.getElementById('screen-letter').classList.add('hidden');
document.getElementById('screen-input').classList.remove('hidden');
}
</script>
</body>
</html>
```Game Source: Message from My Bias
Creator: FlashStar31
Libraries: none
Complexity: complex (464 lines, 17.5 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: message-from-my-bias-flashstar31" to link back to the original. Then publish at arcadelab.ai/publish.