THE LAST WATCH
by LunarPanda23324 lines19.6 KB
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>THE LAST WATCH</title>
<style>
*{box-sizing:border-box}
:root{--red:#c8323c;--green:#75e6a1;--bg:#080a0f}
body{margin:0;background:var(--bg);color:#eee;font-family:Arial,sans-serif}
button{font:inherit;cursor:pointer;color:white}
#app{height:100svh;min-height:480px;max-width:1100px;margin:auto;padding:7px;display:flex;flex-direction:column;gap:7px;overflow:hidden;background:radial-gradient(ellipse,#22242b,#07090d 75%)}
header{height:43px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:5px 10px;background:#0c0e13;border:1px solid #414650}
.logo{font-weight:900;letter-spacing:1px;font-size:clamp(15px,3vw,23px)}
.logo span{color:var(--red)}
.stats{display:flex;gap:10px;font-size:12px;white-space:nowrap}
#power.low{color:#ff4b55}
#view{position:relative;flex:1;min-height:0;overflow:hidden;border:2px solid #3a3d45;background:#101116}
#office{position:absolute;inset:0;background:linear-gradient(#14151b 0 65%,#090a0e 65%)}
.backwall{position:absolute;left:14%;right:14%;top:0;height:75%;background:linear-gradient(90deg,#17171d,#35323a 25%,#27252d 50%,#35323a 75%,#17171d);border-left:6px solid #08090c;border-right:6px solid #08090c}
.ceiling{position:absolute;top:0;left:14%;right:14%;height:9%;background:#08090c;border-bottom:4px solid #393941}
.lamp{position:absolute;top:4%;left:41%;width:18%;height:5%;background:#aaa8a0;box-shadow:0 10px 30px #d4d0b040}
.poster{position:absolute;top:17%;width:14%;height:18%;background:linear-gradient(140deg,#343840,#101217);border:4px solid #101116;display:grid;place-items:center;text-align:center;font-size:clamp(8px,1.7vw,14px);color:#d0d1d4;font-weight:bold}
.poster.p1{left:19%}.poster.p2{right:19%}
.clock{position:absolute;top:39%;left:43%;width:14%;height:15%;border:5px solid #111319;border-radius:50%;background:#181b20;display:grid;place-items:center;font-size:clamp(10px,2vw,16px)}
.floor{position:absolute;bottom:0;left:0;right:0;height:34%;background:repeating-linear-gradient(0deg,#15161a 0 20px,#08090b 21px 24px),linear-gradient(#222,#070707);clip-path:polygon(13% 0,87% 0,100% 100%,0 100%)}
.desk{position:absolute;z-index:5;bottom:5%;left:28%;width:44%;height:17%;background:linear-gradient(#454149 0 10%,#18181d 12% 100%);border:4px solid #08090b;box-shadow:0 10px 20px #000}
.desk:before{content:"";position:absolute;top:-11px;left:-5%;width:110%;height:13px;background:#55515a;border:2px solid #09090b}
.fan{position:absolute;z-index:6;bottom:23%;left:47%;width:6%;aspect-ratio:1;border:3px solid #777;border-radius:50%;background:repeating-conic-gradient(#777 0 15deg,#222 15deg 90deg)}
.side{position:absolute;z-index:4;top:9%;bottom:12%;width:14%;background:linear-gradient(90deg,#08090b,#34343a,#090a0c);border:4px solid #050608;overflow:hidden}
.side.left{left:0}.side.right{right:0}
.sideName{position:absolute;z-index:4;top:2%;left:0;right:0;text-align:center;font-size:clamp(8px,1.5vw,12px);color:#ddd}
.window{position:absolute;top:13%;left:7%;right:7%;height:39%;background:#020407;border:4px solid #08090b;overflow:hidden}
.glow{position:absolute;inset:0;background:radial-gradient(ellipse,#e8dfba,#9e9475 45%,#131411 100%);opacity:0;transition:opacity .15s}
.window.lit .glow{opacity:1}
.windowLabel{position:absolute;z-index:2;top:3px;left:0;right:0;text-align:center;font-size:9px;color:#ddd}
.door{position:absolute;top:56%;bottom:0;left:7%;right:7%;border:4px solid #08090b;background:repeating-linear-gradient(90deg,#1a1c21 0 12px,#34343a 13px 16px);transition:transform .2s;box-shadow:inset 0 0 15px #000}
.door:after{content:"";position:absolute;right:12%;top:48%;width:5px;height:20px;background:#c1a878}
.door.open{transform:translateY(-105%)}
.door.closed{transform:translateY(0)}
.windowFigure{position:absolute;z-index:2;bottom:0;left:28%;width:44%;height:85%;display:none}
.windowFigure.show{display:block}
.figHead{position:absolute;top:0;left:20%;width:60%;height:30%;border:2px solid #090909;border-radius:40% 40% 15% 15%;background:#38383a}
.figBody{position:absolute;top:28%;left:8%;width:84%;height:72%;border:3px solid #080809;background:#17181b}
.figEyes{position:absolute;z-index:2;top:12%;left:31%;width:10%;height:5%;background:#fff1ba;box-shadow:13px 0 #fff1ba,0 0 10px #fff1ba,13px 0 10px #fff1ba}
.red .figHead,.red .figBody{background:#632229}
.runner .figBody{transform:scaleX(.65)}
#camera{display:none;position:absolute;inset:0;background:#07090d;flex-direction:column;padding:7px;gap:7px}
#camera.visible{display:flex}
.camTop{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-shrink:0;font-size:12px;color:#9de7b9}
#room{position:relative;flex:1;min-height:0;overflow:hidden;border:2px solid #4b535c;background:#15171b}
.roomBack{position:absolute;top:0;left:0;right:0;height:70%;background:linear-gradient(90deg,#090d12,#45434a 18%,#292a30 50%,#45434a 82%,#090d12)}
.roomBack:before{content:"";position:absolute;top:15%;left:12%;right:12%;height:55%;border:7px solid #111319;background:repeating-linear-gradient(90deg,#272a30 0 4px,#17191e 5px 8px)}
.roomFloor{position:absolute;bottom:0;left:0;right:0;height:45%;background:repeating-linear-gradient(0deg,#17191d 0 22px,#07080a 23px 26px);clip-path:polygon(18% 0,82% 0,100% 100%,0 100%)}
.prop{position:absolute;z-index:2;bottom:21%;width:19%;height:30%;background:linear-gradient(90deg,#101114,#555057,#17181c);border:4px solid #08090b}
.prop.left{left:13%}.prop.right{right:13%}
.tableProp{position:absolute;z-index:2;bottom:25%;left:35%;width:30%;height:15%;background:#4a4039;border:4px solid #111}
.tableProp:after{content:"";position:absolute;top:-8px;left:-8%;width:116%;height:8px;background:#82766b}
.roomDoor{position:absolute;z-index:2;bottom:20%;left:41%;width:18%;height:48%;border:5px solid #08090b;background:repeating-linear-gradient(90deg,#202127 0 10px,#414148 11px 14px)}
.roomName{position:absolute;z-index:8;top:7px;left:7px;padding:6px 8px;background:#05070de8;border:1px solid #60656e;font-size:11px;direction:ltr}
.roomStatic{position:absolute;inset:0;z-index:7;pointer-events:none;background:repeating-linear-gradient(0deg,transparent 0 3px,#ffffff0a 4px)}
.monster{position:absolute;z-index:5;left:50%;bottom:12%;transform:translateX(-50%);width:25%;height:77%;filter:drop-shadow(0 0 10px #000)}
.mHead{position:absolute;top:0;left:15%;width:70%;height:25%;border:4px solid #070809;border-radius:40% 40% 20% 20%;background:#444247}
.mBody{position:absolute;top:23%;left:8%;width:84%;height:54%;border:4px solid #070809;border-radius:18% 18% 5% 5%;background:linear-gradient(90deg,#101114,#444046,#101114)}
.mArm{position:absolute;top:27%;height:54%;width:22%;border:3px solid #070809;background:#29292d}
.mArm.a{left:-5%;transform:rotate(8deg)}.mArm.b{right:-5%;transform:rotate(-8deg)}
.mLeg{position:absolute;bottom:0;height:27%;width:28%;background:#18191d;border:3px solid #070809}
.mLeg.a{left:15%}.mLeg.b{right:15%}
.mEyes{position:absolute;z-index:2;top:10%;left:31%;width:12%;height:4%;background:#fff0b6;box-shadow:15px 0 #fff0b6,0 0 12px #fff0b6,15px 0 12px #fff0b6}
.mMouth{position:absolute;z-index:3;top:17%;left:28%;width:44%;height:8%;background:#09090b;border-bottom:3px solid #a72b35}
.monster.red .mHead,.monster.red .mBody{background:linear-gradient(90deg,#2c0d12,#74252c,#2c0d12)}
.monster.shadow .mHead,.monster.shadow .mBody,.monster.shadow .mArm,.monster.shadow .mLeg{background:#050608}
.monster.runner{width:17%;height:85%}
.monster.runner .mBody{transform:scaleX(.7)}
.monster.long .mHead{height:20%}
.monster.long .mBody{top:18%;height:64%}
.camButtons{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;flex-shrink:0}
.camButtons button{min-width:0;padding:10px 2px;background:#191d24;border:1px solid #515761;font-size:clamp(9px,2vw,12px)}
.camButtons button.active{background:#245138;border-color:#78e7a3}
.controls{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:5px;flex-shrink:0}
.controls button{min-height:49px;padding:5px 2px;background:linear-gradient(#262a32,#11141a);border:1px solid #454b55;font-size:clamp(10px,2.3vw,14px)}
.controls button small{display:block;font-size:9px;color:#aab0b9;margin-top:3px}
.controls button.active{background:linear-gradient(#8c242b,#471217);border-color:#f05b62}
.controls .cam.active{background:linear-gradient(#2c6445,#14291d);border-color:#75e6a1}
#message{flex-shrink:0;min-height:25px;max-height:35px;overflow:hidden;text-align:center;font-size:12px;color:#d0d3d8;padding:5px}
#overlay,#scare{position:fixed;z-index:30;inset:0;background:#030408f5;display:none;align-items:center;justify-content:center;padding:20px;text-align:center}
#overlay.show,#scare.show{display:flex}
.card{max-width:450px;width:100%;padding:24px;border:1px solid #555;background:#101218;box-shadow:0 0 40px #000}
.card h1{font-size:clamp(28px,8vw,48px);margin:0 0 12px}
.card p{color:#bbc0c8;line-height:1.5}
.card button{padding:12px 25px;background:#a52a31;border:1px solid #f16b72}
#scare{z-index:40;background:#030204}
.scareShape{width:160px;height:230px;background:linear-gradient(90deg,#12080a,#7c1b26,#100609);clip-path:polygon(30% 0,70% 0,100% 30%,85% 100%,15% 100%,0 30%);position:relative}
.scareShape:before{content:"";position:absolute;top:20%;left:28%;width:13%;height:5%;background:white;box-shadow:50px 0 white,0 0 18px red,50px 0 18px red}
@media(max-width:600px){
#app{padding:5px;gap:5px}
header{height:39px;padding:4px 6px}
.stats{gap:6px;font-size:10px}
.backwall{left:14%;right:14%}
.poster{width:13%}
.poster.p1{left:17%}.poster.p2{right:17%}
.desk{left:25%;width:50%}
.controls button{min-height:45px}
.controls button small{font-size:8px}
}
@media(max-height:620px){
#app{min-height:0;padding:4px;gap:4px}
header{height:34px}
.controls button{min-height:38px}
.controls button small{display:none}
#message{min-height:20px;padding:3px}
}
</style>
</head>
<body>
<div id="app">
<header>
<div class="logo">THE LAST <span>WATCH</span></div>
<div class="stats">
<span>לילה <b id="night">1/5</b></span>
<span>שעה <b id="hour">12 AM</b></span>
<span>חשמל <b id="power">100%</b></span>
</div>
</header>
<div id="view">
<div id="office">
<div class="backwall"></div><div class="ceiling"></div><div class="lamp"></div>
<div class="poster p1">KEEP<br>WATCHING</div>
<div class="poster p2">STAFF<br>ONLY</div>
<div class="clock">12:00</div><div class="floor"></div>
<div class="side left">
<div class="sideName">LEFT</div>
<div class="window" id="leftWindow"><div class="glow"></div><div class="windowLabel">WINDOW</div>
<div class="windowFigure" id="leftFigure"><div class="figHead"></div><div class="figEyes"></div><div class="figBody"></div></div>
</div>
<div class="door closed" id="leftDoor"></div>
</div>
<div class="side right">
<div class="sideName">RIGHT</div>
<div class="window" id="rightWindow"><div class="glow"></div><div class="windowLabel">WINDOW</div>
<div class="windowFigure red" id="rightFigure"><div class="figHead"></div><div class="figEyes"></div><div class="figBody"></div></div>
</div>
<div class="door closed" id="rightDoor"></div>
</div>
<div class="fan"></div><div class="desk"></div>
</div>
<div id="camera">
<div class="camTop"><b>SECURITY CAMERAS</b><span id="camSignal">LIVE FEED</span></div>
<div id="room"></div>
<div class="camButtons" id="camButtons"></div>
</div>
</div>
<div class="controls">
<button id="leftLight">◉ אור שמאל<small>בדיקת חלון</small></button>
<button id="leftDoorBtn">▣ דלת שמאל<small>סגירה / פתיחה</small></button>
<button id="cameraBtn" class="cam">▤ מצלמות<small>פתח מסך</small></button>
<button id="rightDoorBtn">▣ דלת ימין<small>סגירה / פתיחה</small></button>
<button id="rightLight">◉ אור ימין<small>בדיקת חלון</small></button>
</div>
<div id="message">לחץ על התחל כדי להתחיל את המשמרת.</div>
</div>
<div id="overlay" class="show"><div class="card">
<h1>THE LAST WATCH</h1>
<p id="intro">שרוד חמישה לילות. השתמש במצלמות כדי לבדוק את החדרים, באורות כדי לבדוק את החלונות ובדלתות כדי להגן על עצמך. החשמל מוגבל.</p>
<button id="start">התחל משמרת</button>
</div></div>
<div id="scare"><div class="card">
<div class="scareShape"></div><h1 style="color:#d43842">CAUGHT</h1>
<p id="scareText">המשמרת הסתיימה.</p><button id="retry">נסה שוב</button>
</div></div>
<script>
(()=>{
const $=id=>document.getElementById(id);
const names=["CAM 01 — SHOWROOM","CAM 02 — STORAGE","CAM 03 — HALLWAY","CAM 04 — WORKSHOP"];
const types=["showroom","storage","hall","workshop"];
const defs=[
{id:"grin",name:"THE GRIN",cls:"",side:"left",rooms:[0,1,2],speed:1},
{id:"red",name:"THE RED ONE",cls:"red",side:"right",rooms:[1,3,2],speed:.85},
{id:"runner",name:"THE RUNNER",cls:"runner",side:"left",rooms:[2,3],speed:1.35},
{id:"long",name:"THE TALL ONE",cls:"long",side:"right",rooms:[0,3,1],speed:.7}
];
let s={night:1,elapsed:0,duration:210,power:100,running:false,gameover:false,
cameras:false,cam:0,doors:{left:true,right:true},lights:{left:false,right:false},
outage:false,outageTime:0,rare:false,monsters:[],timer:null};
function reset(n){
s.night=n;s.elapsed=0;s.power=100;s.running=false;s.gameover=false;
s.cameras=false;s.cam=0;s.doors={left:true,right:true};s.lights={left:false,right:false};
s.outage=false;s.outageTime=0;s.rare=false;
s.monsters=defs.map((d,i)=>({...d,active:i<2||(i===2&&n>=4)||(i===3&&n>=3),room:d.rooms[0],step:0,atDoor:false,wait:0}));
render();
}
function say(t){$("message").textContent=t}
function start(){
$("overlay").classList.remove("show");$("scare").classList.remove("show");
clearInterval(s.timer);s.running=true;render();say("המשמרת התחילה. הדלתות סגורות. חסוך בחשמל.");
s.timer=setInterval(tick,1000);
}
function tick(){
if(!s.running||s.gameover)return;
if(s.outage){if(++s.outageTime>=7)end("נגמר החשמל והדמויות נכנסו למשרד.");return}
s.elapsed++;
let drain=.12+s.night*.018+(s.cameras?.08:0)+(s.doors.left?.16:0)+(s.doors.right?.16:0)+(s.lights.left?.1:0)+(s.lights.right?.1:0);
s.power=Math.max(0,s.power-drain);
if(s.power<=0){s.outage=true;s.outageTime=0;s.doors={left:false,right:false};s.lights={left:false,right:false};s.cameras=false;say("החשמל נגמר! הדלתות נפתחו. הישאר ערני...");render();return}
if(!s.rare&&s.elapsed>20&&Math.random()<.0006){s.rare=true;setTimeout(()=>{if(s.running)end("הדמות המסתורית הופיעה במשרד.");},1200)}
for(const m of s.monsters){
if(!m.active)continue;
if(m.atDoor){
m.wait++;
if(s.doors[m.side]){if(m.wait>=3){m.atDoor=false;m.wait=0;m.room=m.rooms[0];say(m.name+" נסוג בחזרה למסדרון.");}}
else if(m.wait>=2){end(m.name+" נכנס למשרד!");return}
continue;
}
const chance=(.035+s.night*.018)*m.speed;
if(Math.random()<chance){
m.step++;
if(m.step>=2){
m.step=0;let i=m.rooms.indexOf(m.room);
if(i>=m.rooms.length-1){m.atDoor=true;m.wait=0;say("משהו הגיע לדלת "+(m.side==="left"?"השמאלית":"הימנית")+"! בדוק את החלון.");}
else m.room=m.rooms[i+1];
}
}
}
if(s.elapsed>=s.duration){
if(s.night>=5){win();return}
clearInterval(s.timer);s.running=false;
$("intro").textContent="שרדת את לילה "+s.night+"! הלילה הבא יהיה קשה יותר.";
$("start").textContent="התחל לילה "+(s.night+1);
$("start").onclick=()=>{reset(s.night+1);start()};
$("overlay").classList.add("show");say("6 AM — הלילה הושלם!");return;
}
render();
}
function end(reason){
if(s.gameover)return;s.gameover=true;s.running=false;clearInterval(s.timer);
$("scareText").textContent=reason;$("scare").classList.add("show");
}
function win(){
s.running=false;clearInterval(s.timer);
$("intro").textContent="ניצחת! שרדת את כל חמשת הלילות. אבל במצלמה האחרונה נראה צל שלא היה שם קודם...";
$("start").textContent="שחק שוב";$("start").onclick=()=>{reset(1);start()};
$("overlay").classList.add("show");
}
function door(side){
if(!s.running||s.outage)return;
s.doors[side]=!s.doors[side];
if(s.doors[side]){s.lights[side]=false;say("דלת "+(side==="left"?"שמאל":"ימין")+" נסגרה.")}
else say("דלת "+(side==="left"?"שמאל":"ימין")+" נפתחה.");
render();
}
function light(side){
if(!s.running||s.outage)return;
if(s.doors[side]){say("פתח את הדלת כדי לבדוק את החלון.");return}
s.lights[side]=!s.lights[side];
const m=s.monsters.find(x=>x.active&&x.atDoor&&x.side===side);
say(s.lights[side]?(m?"דמות בחלון! סגור את הדלת מיד!":"החלון ריק כרגע."):"האור כובה.");
render();
}
function monsterMarkup(m){
if(!m)return"";
return `<div class="monster ${m.cls}">
<div class="mHead"></div><div class="mEyes"></div><div class="mMouth"></div>
<div class="mBody"></div><div class="mArm a"></div><div class="mArm b"></div>
<div class="mLeg a"></div><div class="mLeg b"></div></div>`;
}
function renderRoom(){
const room=types[s.cam];
const m=s.monsters.find(x=>x.active&&!x.atDoor&&x.room===s.cam);
let props=room==="showroom"?'<div class="prop left"></div><div class="prop right"></div><div class="tableProp"></div>':
room==="storage"?'<div class="prop left"></div><div class="prop right"></div>':
room==="hall"?'<div class="roomDoor"></div>':'<div class="prop left"></div><div class="tableProp"></div><div class="roomDoor"></div>';
$("room").innerHTML=`<div class="roomBack"></div><div class="roomFloor"></div>${props}
${monsterMarkup(m)}<div class="roomName">${names[s.cam]}</div><div class="roomStatic"></div>`;
$("camSignal").textContent=m?"MOVEMENT DETECTED":"LIVE FEED // NO MOVEMENT";
$("camButtons").innerHTML=names.map((n,i)=>`<button data-cam="${i}" class="${s.cam===i?"active":""}">${n}</button>`).join("");
$("camButtons").querySelectorAll("button").forEach(b=>b.onclick=()=>{s.cam=Number(b.dataset.cam);renderRoom()});
}
function render(){
$("night").textContent=s.night+"/5";
$("hour").textContent=(s.elapsed===0?"12":Math.min(6,Math.floor(s.elapsed/s.duration*6)))+" AM";
$("power").textContent=Math.floor(s.power)+"%";
$("power").classList.toggle("low",s.power<25);
$("office").style.display=s.cameras?"none":"block";
$("camera").classList.toggle("visible",s.cameras);
$("cameraBtn").classList.toggle("active",s.cameras);
$("leftDoor").className="door "+(s.doors.left?"closed":"open");
$("rightDoor").className="door "+(s.doors.right?"closed":"open");
$("leftWindow").classList.toggle("lit",s.lights.left);
$("rightWindow").classList.toggle("lit",s.lights.right);
$("leftLight").classList.toggle("active",s.lights.left);
$("rightLight").classList.toggle("active",s.lights.right);
$("leftDoorBtn").classList.toggle("active",s.doors.left);
$("rightDoorBtn").classList.toggle("active",s.doors.right);
const lm=s.monsters.find(m=>m.active&&m.atDoor&&m.side==="left");
const rm=s.monsters.find(m=>m.active&&m.atDoor&&m.side==="right");
$("leftFigure").classList.toggle("show",!!lm);
$("rightFigure").classList.toggle("show",!!rm);
$("leftFigure").classList.toggle("runner",lm?.id==="runner");
$("rightFigure").classList.toggle("red",rm?.id==="red"||rm?.id==="long");
if(s.cameras)renderRoom();
}
$("leftDoorBtn").onclick=()=>door("left");
$("rightDoorBtn").onclick=()=>door("right");
$("leftLight").onclick=()=>light("left");
$("rightLight").onclick=()=>light("right");
$("cameraBtn").onclick=()=>{
if(!s.running||s.outage)return;
s.cameras=!s.cameras;render();
};
$("start").onclick=()=>{reset(1);start()};
$("retry").onclick=()=>{$("scare").classList.remove("show");reset(1);start()};
reset(1);
})();
</script>
</body>
</html>
Game Source: THE LAST WATCH
Creator: LunarPanda23
Libraries: none
Complexity: complex (324 lines, 19.6 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: the-last-watch-lunarpanda23-mvpgusrp" to link back to the original. Then publish at arcadelab.ai/publish.