Untitled
unknown
plain_text
a month ago
27 kB
4
Indexable
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Landscape Pizza Prep Station</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
background-color: #11161b;
color: #fff;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
/* Sets up global 3D space perspective */
perspective: 1600px;
}
.game-container {
width: 1050px;
background: #222a33;
padding: 25px;
border-radius: 20px;
box-shadow: 0 30px 60px rgba(0,0,0,0.8);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 4px solid #e67e22;
padding-bottom: 15px;
margin-bottom: 20px;
}
.stats-hub {
display: flex;
gap: 15px;
}
.timer-box, .earnings, .highscore-box {
font-size: 22px;
font-weight: bold;
background: #000;
padding: 8px 15px;
border-radius: 8px;
}
.timer-box { color: #e74c3c; border: 2px solid #e74c3c; }
.earnings { color: #2ecc71; border: 2px solid #2ecc71; }
.highscore-box { color: #f1c40f; border: 2px solid #f1c40f; }
/* KIOSK TICKET SCREEN */
.kiosk-console {
background: #151a21;
border: 3px solid #333;
border-radius: 12px;
padding: 15px;
margin-bottom: 20px;
display: grid;
grid-template-columns: 3fr 1fr;
gap: 15px;
}
.console-screen {
background: #090d12;
border-radius: 8px;
padding: 15px;
display: flex;
gap: 12px;
min-height: 120px;
align-items: center;
box-shadow: inset 0 0 15px rgba(0,0,0,0.9);
}
.order-ticket {
width: 130px;
padding: 12px;
border-radius: 6px;
color: #fff;
font-weight: bold;
text-align: center;
border: 2px solid rgba(255,255,255,0.2);
}
.order-ticket.selected-highlight {
border-color: #adff2f !important;
box-shadow: 0 0 15px #adff2f;
transform: scale(1.05);
}
/* CONSOLE CONTROLS */
.control-btn {
background: #e67e22;
color: white;
border: none;
padding: 12px;
font-weight: bold;
border-radius: 6px;
cursor: pointer;
box-shadow: 0 4px 0 #a04000;
margin-bottom: 8px;
width: 100%;
}
.control-btn:active { transform: translateY(4px); box-shadow: none; }
.serve-btn { background: #27ae60; box-shadow: 0 4px 0 #1e8449; }
.blueprint-panel {
background: #090d12;
padding: 15px;
border-radius: 8px;
margin-bottom: 25px;
border-left: 5px solid #f39c12;
}
.recipe-tag {
background: #2c3e50;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
margin-right: 5px;
display: inline-block;
margin-top: 5px;
}
/* -------------------------------------------------------------
REAL LANDSCAPE 3D TABLE STRUCTURING (WITH DEPTH AND WALLS)
------------------------------------------------------------- */
.table-view-container {
width: 100%;
padding: 20px 0;
margin-bottom: 40px;
display: flex;
justify-content: center;
align-items: center;
/* Creates the perfect isometric landscape viewing window */
transform: rotateX(34deg) rotateY(-4deg);
transform-style: preserve-3d;
}
.landscape-3d-table {
position: relative;
width: 950px;
height: 240px;
transform-style: preserve-3d;
}
/* Top surface deck of the table where items sit */
.table-top-deck {
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #bdc3c7 0%, #95a5a6 100%);
border: 2px solid #bdc3c7;
border-radius: 12px;
padding: 15px;
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
box-shadow: inset 0 3px 8px rgba(255,255,255,0.6);
transform: translateZ(25px); /* Raised off the floor grid */
transform-style: preserve-3d;
z-index: 2;
}
/* Front face edge extrusion wall giving the table physical thickness */
.table-front-wall {
position: absolute;
width: 100%;
height: 25px;
background: linear-gradient(180deg, #7f8c8d, #34495e);
bottom: -25px;
left: 0;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
/* Tilts face forward down to connect cleanly with the top plate */
transform: rotateX(-90deg);
transform-origin: top center;
box-shadow: 0 15px 20px rgba(0,0,0,0.5);
}
/* Side structural wall profiles */
.table-left-wall {
position: absolute;
width: 240px;
height: 25px;
background: #7f8c8d;
left: 0;
top: 0;
transform: rotateY(90deg) rotateX(-90deg);
transform-origin: left top;
}
/* COUNTER-SUNK REALISTIC 3D INGREDIENT TUBS */
.landscape-sunken-tub {
background: linear-gradient(135deg, #11151a, #07090c);
border-radius: 8px;
padding: 12px 2px;
text-align: center;
cursor: pointer;
user-select: none;
position: relative;
box-sizing: border-box;
/* Deep cutout effect */
box-shadow: inset 0 8px 12px rgba(0,0,0,0.95), 0 1px 1px rgba(255,255,255,0.2);
transition: transform 0.1s ease, box-shadow 0.1s ease;
transform: translateZ(2px);
}
/* Interactive physics: push inside table deck when pressed */
.landscape-sunken-tub:hover {
transform: translateZ(5px);
background: linear-gradient(135deg, #182029, #0d1217);
}
.landscape-sunken-tub:active {
transform: translateZ(-6px);
box-shadow: inset 0 4px 6px rgba(0,0,0,0.95);
}
/* Color accent bands */
.rim-protein { border-top: 4px solid #e74c3c; }
.rim-veggie { border-top: 4px solid #2ecc71; }
.rim-sauce { border-top: 4px solid #f1c40f; }
.tub-graphic {
font-size: 34px;
display: block;
margin-bottom: 4px;
filter: drop-shadow(0 4px 4px rgba(0,0,0,0.6));
}
.tub-text {
font-size: 10px;
font-weight: bold;
color: #bdc3c7;
text-transform: uppercase;
letter-spacing: 0.3px;
}
/* LOWER CONVEYOR SYSTEMS */
.bottom-row {
display: grid;
grid-template-columns: 1fr 1.5fr;
gap: 25px;
}
.action-card {
background: #151a21;
padding: 15px;
border-radius: 12px;
text-align: center;
cursor: pointer;
border: 2px solid #333;
}
.conveyor-belt-3d {
background: #161616;
border: 4px solid #333;
border-radius: 12px;
height: 160px;
position: relative;
margin: 10px 0;
transform: rotateX(25deg);
box-shadow: 0 15px 35px rgba(0,0,0,0.7), inset 0 0 25px rgba(0,0,0,0.9);
display: flex;
align-items: center;
justify-content: center;
transform-style: preserve-3d;
}
.pizza-layer {
position: absolute;
font-size: 130px;
opacity: 0;
transform: scale(0.5);
transition: all 0.25s ease;
}
.pizza-layer.active {
opacity: 1;
transform: scale(1);
filter: drop-shadow(0 10px 8px rgba(0,0,0,0.7));
}
.scatter-container { position: absolute; width: 100%; height: 100%; opacity: 0; }
.scatter-container.active { opacity: 1; }
.scatter-item { position: absolute; font-size: 22px; filter: drop-shadow(0 3px 3px rgba(0,0,0,0.5)); }
.build-string-display {
background: #000;
color: #2ecc71;
padding: 10px;
font-family: monospace;
text-align: center;
border-radius: 6px;
margin-top: 10px;
}
.status-log {
background: #000;
color: #00ff00;
padding: 10px;
font-family: monospace;
margin-top: 15px;
border-radius: 6px;
}
.game-over-screen {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(17, 22, 27, 0.95); border-radius: 20px;
display: none; flex-direction: column; align-items: center; justify-content: center; z-index: 100;
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-over-screen" id="game-over-panel">
<h1 style="font-size: 45px; color: #e74c3c;">โฐ SHIFT ENDED</h1>
<p id="final-score" style="font-size: 22px;"></p>
<button class="control-btn" style="padding: 15px 40px; font-size: 18px; width:auto;" onclick="startShift()">Clock In Again</button>
</div>
<div class="header">
<h2>๐ Landscape 3D Kitchen Table Simulator</h2>
<div class="stats-hub">
<div class="timer-box" id="timer-txt">โฑ๏ธ 90s</div>
<div class="earnings" id="cash-txt">๐ฐ Cash: $0</div>
<div class="highscore-box" id="top-txt">๐ Best: $0</div>
</div>
</div>
<div class="kiosk-console">
<div>
<div style="font-size:11px; color:#f1c40f; font-family:monospace; margin-bottom:5px;">๐ฅ๏ธ ORDERS QUEUE SCREEN</div>
<div class="console-screen" id="ticket-screen"></div>
</div>
<div>
<button class="control-btn" onclick="cycleTickets()">NEXT TICKET โญ๏ธ</button>
<button class="control-btn" style="background:#34495e; box-shadow:0 4px 0 #1c2833;" onclick="claimTicket()">LOAD WORK ORDER</button>
<button class="control-btn serve-btn" onclick="shipPizza()">SERVE ORDER ๐ฆ</button>
</div>
</div>
<div class="blueprint-panel" id="blueprint-txt">
<span style="color: #7f8c8d;">Select and Load an open work order ticket to view specs...</span>
</div>
<div class="table-view-container">
<div class="landscape-3d-table">
<div class="table-top-deck">
<div class="landscape-sunken-tub rim-protein" onclick="addFood('Crust Base', '๐')">
<span class="tub-graphic">๐</span><span class="tub-text">Pizza Crust</span>
</div>
<div class="landscape-sunken-tub rim-protein" onclick="addFood('Pepperoni', '๐ด')">
<span class="tub-graphic">๐ด</span><span class="tub-text">Pepperoni</span>
</div>
<div class="landscape-sunken-tub rim-protein" onclick="addFood('Chicken Strips', '๐')">
<span class="tub-graphic">๐</span><span class="tub-text">Chicken</span>
</div>
<div class="landscape-sunken-tub rim-protein" onclick="addFood('Crispy Bacon', '๐ฅ')">
<span class="tub-graphic">๐ฅ</span><span class="tub-text">Bacon</span>
</div>
<div class="landscape-sunken-tub rim-veggie" onclick="addFood('Lettuce Shreads', '๐ฅฌ')">
<span class="tub-graphic">๐ฅฌ</span><span class="tub-text">Lettuce</span>
</div>
<div class="landscape-sunken-tub rim-veggie" onclick="addFood('Diced Tomatoes', '๐
')">
<span class="tub-graphic">๐
</span><span class="tub-text">Tomatoes</span>
</div>
<div class="landscape-sunken-tub rim-veggie" onclick="addFood('Pickled Gherkins', '๐ฅ')">
<span class="tub-graphic">๐ฅ</span><span class="tub-text">Gherkins</span>
</div>
<div class="landscape-sunken-tub rim-veggie" onclick="addFood('Chopped Onions', '๐ง
')">
<span class="tub-graphic">๐ง
</span><span class="tub-text">Onions</span>
</div>
<div class="landscape-sunken-tub rim-veggie" onclick="addFood('Shredded Cheese', '๐ง')">
<span class="tub-graphic">๐ง</span><span class="tub-text">Cheese</span>
</div>
<div class="landscape-sunken-tub rim-sauce" onclick="addFood('Yogurt Dressing', '๐ค')">
<span class="tub-graphic">๐ค</span><span class="tub-text">Yogurt</span>
</div>
<div class="landscape-sunken-tub rim-sauce" onclick="addFood('Tomato Sauce', '๐ฅซ')">
<span class="tub-graphic">๐ฅซ</span><span class="tub-text">Marinara</span>
</div>
<div class="landscape-sunken-tub rim-sauce" onclick="addFood('Boise Sauce', '๐งก')">
<span class="tub-graphic">๐งก</span><span class="tub-text">Boise Sauce</span>
</div>
</div>
<div class="table-front-wall"></div>
<div class="table-left-wall"></div>
</div>
</div>
<div class="bottom-row">
<div>
<h3 style="color:#f1c40f; margin:0 0 10px 0; font-size:14px; text-transform:uppercase;">Packaging & Cleaning</h3>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:15px;">
<div class="action-card" style="border-top: 4px solid #3498db;" onclick="addFood('Delivery Box', '๐ฆ')">
<div style="font-size:32px">๐ฆ</div><div class="tub-text" style="color:white; margin-top:5px;">Pizza Box</div>
</div>
<div class="action-card" style="border-top: 4px solid #e74c3c; background:#7b241c;" onclick="clearBuild()">
<div style="font-size:32px">๐๏ธ</div><div class="tub-text" style="color:white; margin-top:5px;">Clear Assembly</div>
</div>
</div>
</div>
<div>
<h3 style="color:#f1c40f; margin:0 0 10px 0; font-size:14px; text-transform:uppercase;">Conveyor Assembly Belt</h3>
<div class="conveyor-belt-3d">
<div id="layer-box" class="pizza-layer">๐ฆ</div>
<div id="layer-crust" class="pizza-layer">๐</div>
<div id="scat-pep" class="scatter-container"></div>
<div id="scat-chicken" class="scatter-container"></div>
<div id="scat-bacon" class="scatter-container"></div>
<div id="scat-lettuce" class="scatter-container"></div>
<div id="scat-tomato" class="scatter-container"></div>
<div id="scat-gherkin" class="scatter-container"></div>
<div id="scat-onion" class="scatter-container"></div>
<div id="scat-cheese" class="scatter-container"></div>
<div id="scat-yogurt" class="scatter-container"></div>
<div id="scat-marinara" class="scatter-container"></div>
<div id="scat-boise" class="scatter-container"></div>
</div>
<div class="build-string-display" id="build-string">Tray Empty</div>
</div>
</div>
<div class="status-log" id="log-txt">System: Ready...</div>
</div>
<script>
const menu = {
"Classic Pizza": { items: ["Crust Base", "Yogurt Dressing", "Lettuce Shreads", "Diced Tomatoes", "Pickled Gherkins", "Chopped Onions", "Pepperoni", "Tomato Sauce"], color: "#c0392b" },
"Cheese Pizza": { items: ["Crust Base", "Pepperoni", "Shredded Cheese", "Tomato Sauce"], color: "#f1c40f" },
"Bacon Deluxe": { items: ["Crust Base", "Yogurt Dressing", "Lettuce Shreads", "Diced Tomatoes", "Pickled Gherkins", "Chopped Onions", "Pepperoni", "Shredded Cheese", "Crispy Bacon"], color: "#2980b9" },
"Chicken Feast": { items: ["Crust Base", "Yogurt Dressing", "Lettuce Shreads", "Chicken Strips"], color: "#e67e22" },
"Boise Special": { items: ["Crust Base", "Yogurt Dressing", "Lettuce Shreads", "Diced Tomatoes", "Pickled Gherkins", "Chopped Onions", "Pepperoni", "Tomato Sauce", "Boise Sauce"], color: "#27ae60" }
};
let score = 0; let highscore = parseInt(localStorage.getItem("p_high")) || 0;
let orders = []; let activeIndex = 0; let workingTicket = null;
let tray = []; let clock = 90; let clockId, spawnId, audioBox;
function buildScatterItems() {
const rules = [
{ id: "scat-pep", icon: "๐ด", amt: 7 }, { id: "scat-chicken", icon: "๐", amt: 6 },
{ id: "scat-bacon", icon: "๐ฅ", amt: 6 }, { id: "scat-lettuce", icon: "๐ฅฌ", amt: 8 },
{ id: "scat-tomato", icon: "๐
", amt: 5 }, { id: "scat-gherkin", icon: "๐ฅ", amt: 6 },
{ id: "scat-onion", icon: "๐ง
", amt: 6 }, { id: "scat-cheese", icon: "๐ง", amt: 8 },
{ id: "scat-yogurt", icon: "๐ค", amt: 5 }, { id: "scat-marinara", icon: "๐ฅซ", amt: 5 },
{ id: "scat-boise", icon: "๐งก", amt: 5 }
];
rules.forEach(rule => {
const box = document.getElementById(rule.id); box.innerHTML = "";
for(let i=0; i<rule.amt; i++) {
let node = document.createElement("span"); node.className = "scatter-item"; node.innerText = rule.icon;
let deg = Math.random() * Math.PI * 2; let dist = 15 + (Math.random() * 40);
node.style.left = `${120 + Math.cos(deg) * dist}px`;
node.style.top = `${60 + Math.sin(deg) * dist}px`;
box.appendChild(node);
}
});
}
function sound(f, t, d) {
try {
if(!audioBox) audioBox = new (window.AudioContext || window.webkitAudioContext)();
let o = audioBox.createOscillator(); let g = audioBox.createGain();
o.type = t; o.frequency.setValueAtTime(f, audioBox.currentTime);
g.gain.setValueAtTime(0.06, audioBox.currentTime);
g.gain.exponentialRampToValueAtTime(0.00001, audioBox.currentTime + d);
o.connect(g); g.connect(audioBox.destination); o.start(); o.stop(audioBox.currentTime + d);
} catch(e){}
}
function startShift() {
clearInterval(clockId); clearTimeout(spawnId);
score = 0; clock = 90; orders = []; activeIndex = 0; workingTicket = null; tray = [];
buildScatterItems(); updateScoreBoard(); refreshTrayVisuals();
document.getElementById("blueprint-txt").innerHTML = `<span style="color: #7f8c8d;">Select and Load an open work order ticket to view specs...</span>`;
document.getElementById("game-over-panel").style.display = "none";
drawMonitor();
clockId = setInterval(() => {
clock--; document.getElementById("timer-txt").innerText = `โฑ๏ธ ${clock}s`;
if(clock <= 0) stopShift();
}, 1000);
triggerOrderSpawning();
}
function triggerOrderSpawning() {
spawnId = setTimeout(() => {
if (orders.length < 4) {
let choices = Object.keys(menu);
orders.push(choices[Math.floor(Math.random() * choices.length)]);
sound(550, "sine", 0.08); drawMonitor();
}
triggerOrderSpawning();
}, 4000 + Math.random() * 4000);
}
function stopShift() {
clearInterval(clockId); clearTimeout(spawnId);
if(score > highscore) { highscore = score; localStorage.setItem("p_high", highscore); }
document.getElementById("final-score").innerText = `Shift complete. Secured payout: $${score}`;
document.getElementById("game-over-panel").style.display = "flex";
}
function drawMonitor() {
const display = document.getElementById("ticket-screen"); display.innerHTML = "";
if(orders.length === 0) { display.innerHTML = `<div style="color:#444; width:100%; text-align:center;">[ QUEUE EMPTY ]</div>`; return; }
orders.forEach((name, i) => {
let card = document.createElement("div"); card.className = "order-ticket";
if(i === activeIndex) card.className += " selected-highlight";
card.style.backgroundColor = menu[name].color;
card.innerHTML = `TIK #${i+1}<br><br>${name}`; display.appendChild(card);
});
}
function cycleTickets() {
if(orders.length === 0) return; sound(400, "triangle", 0.05);
activeIndex = (activeIndex + 1) % orders.length; drawMonitor();
}
function claimTicket() {
if(orders.length === 0) return; sound(480, "triangle", 0.05);
workingTicket = { name: orders[activeIndex], pos: activeIndex };
let ingredientsHTML = menu[workingTicket.name].items.map(i => `<span class="recipe-tag">${i}</span>`).join("");
document.getElementById("blueprint-txt").innerHTML = `<strong>๐ RECIPE SCHEMATIC: ${workingTicket.name}</strong><br>${ingredientsHTML}<span class="recipe-tag" style="background:#3498db;">Delivery Box</span>`;
}
function addFood(name, ico) {
sound(420, "sine", 0.05);
tray.push({n: name, i: ico}); refreshTrayVisuals();
}
function clearBuild() { sound(150, "sine", 0.2); tray = []; refreshTrayVisuals(); }
function refreshTrayVisuals() {
const label = document.getElementById("build-string");
document.getElementById("layer-box").className = "pizza-layer";
document.getElementById("layer-crust").className = "pizza-layer";
const scatterIds = ["scat-pep", "scat-chicken", "scat-bacon", "scat-lettuce", "scat-tomato", "scat-gherkin", "scat-onion", "scat-cheese", "scat-yogurt", "scat-marinara", "scat-boise"];
scatterIds.forEach(id => document.getElementById(id).className = "scatter-container");
if(tray.length === 0) { label.innerText = "Tray Empty"; return; }
label.innerText = tray.map(item => item.i).join(" + ");
tray.forEach(item => {
if(item.n === "Delivery Box") document.getElementById("layer-box").className = "pizza-layer active";
if(item.n === "Crust Base") document.getElementById("layer-crust").className = "pizza-layer active";
if(item.n === "Pepperoni") document.getElementById("scat-pep").className = "scatter-container active";
if(item.n === "Chicken Strips") document.getElementById("scat-chicken").className = "scatter-container active";
if(item.n === "Crispy Bacon") document.getElementById("scat-bacon").className = "scatter-container active";
if(item.n === "Lettuce Shreads") document.getElementById("scat-lettuce").className = "scatter-container active";
if(item.n === "Diced Tomatoes") document.getElementById("scat-tomato").className = "scatter-container active";
if(item.n === "Pickled Gherkins") document.getElementById("scat-gherkin").className = "scatter-container active";
if(item.n === "Chopped Onions") document.getElementById("scat-onion").className = "scatter-container active";
if(item.n === "Shredded Cheese") document.getElementById("scat-cheese").className = "scatter-container active";
if(item.n === "Yogurt Dressing") document.getElementById("scat-yogurt").className = "scatter-container active";
if(item.n === "Tomato Sauce") document.getElementById("scat-marinara").className = "scatter-container active";
if(item.n === "Boise Sauce") document.getElementById("scat-boise").className = "scatter-container active";
});
}
function shipPizza() {
const logger = document.getElementById("log-txt");
if(!workingTicket) { sound(180, "sawtooth", 0.2); logger.innerText = "โ No working sheet active!"; return; }
let hasBox = tray.find(i => i.n === "Delivery Box");
let foodList = tray.filter(i => i.n !== "Delivery Box").map(i => i.n);
if(!hasBox) { sound(180, "sawtooth", 0.2); logger.innerText = "โ Needs a delivery pizza packaging box!"; return; }
let targetList = menu[workingTicket.name].items;
const count = (arr) => arr.reduce((acc, v) => { acc[v] = (acc[v] || 0) + 1; return acc; }, {});
let currentMap = count(foodList); let targetMap = count(targetList);
let match = Object.keys(currentMap).length === Object.keys(targetMap).length;
if(match) {
for(let key in targetMap) {
if(currentMap[key] !== targetMap[key]) { match = false; break; }
}
}
if(match) {
score += 5; clock = Math.min(clock + 20, 90);
sound(600, "sine", 0.1); setTimeout(() => sound(1200, "sine", 0.12), 80);
logger.innerText = `๐ Shipped order for ${workingTicket.name}. +$5`;
orders.splice(workingTicket.pos, 1); workingTicket = null; activeIndex = 0;
updateScoreBoard(); clearBuild(); drawMonitor();
document.getElementById("blueprint-txt").innerHTML = `<span style="color: #7f8c8d;">Ticket finished. Choose another order...</span>`;
} else {
sound(180, "sawtooth", 0.2); logger.innerText = "โ Ingredients pattern mismatched!";
}
}
function updateScoreBoard() {
if(score > highscore) highscore = score;
document.getElementById("cash-txt").innerText = `๐ฐ Cash: $${score}`;
document.getElementById("top-txt").innerText = `๐ Best: $${highscore}`;
}
startShift();
</script>
</body>
</html>Editor is loading...
Leave a Comment