Commit c74dd95b19

c74dd95b19bf973eadd03d4ea00d184ae6287bff

parent: 6b744e0e7b

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-27 06:16 UTC

Show each status line once; shake the grid when darkness eats a step

The message panel joined S.msg and roomMsg(), which are the same text
after a plain step, so the room line printed twice. Drop duplicates.

A step lost to shadow() now sets fx "dark": the grid dims and shakes
for 0.3s, restarting on consecutive lost steps.

Layout: unified · split

1mb/index.html +5 −3
@@ -39,7 +39,7 @@ linear-gradient(180deg,transparent,rgba(0,0,0,.12));mix-blend-mode:screen;opacit
3939.warded{box-shadow:inset 0 0 0 1px var(--wardGlow);background:radial-gradient(circle at 50% 50%,#ffffff08,transparent 72%)}
4040.haz{filter:brightness(1.14)}
4141.fog1{opacity:.9}.fog2{opacity:.72}.fog3{opacity:.55}
42#g.hit{transform:translateX(2px);box-shadow:inset 0 0 0 1px #000,0 0 24px #0008,0 0 14px color-mix(in srgb,var(--hazard) 70%,#000)}#g.win{box-shadow:inset 0 0 0 1px #000,0 0 24px #0008,0 0 14px var(--glow)}#g.shift{transform:scale(1.02)}#g.ward{animation:wardbreak .2s ease-out}#g.relic{animation:relicpulse .24s ease-out}
42#g.hit{transform:translateX(2px);box-shadow:inset 0 0 0 1px #000,0 0 24px #0008,0 0 14px color-mix(in srgb,var(--hazard) 70%,#000)}#g.win{box-shadow:inset 0 0 0 1px #000,0 0 24px #0008,0 0 14px var(--glow)}#g.shift{transform:scale(1.02)}#g.ward{animation:wardbreak .2s ease-out}#g.relic{animation:relicpulse .24s ease-out}#g.dark{animation:darkstep .3s ease-out}
4343#u.dead,#u.win,#u.camp{letter-spacing:.12em;text-transform:uppercase}
4444#s[data-floor="1"]{--bg0:#0a130d;--bg1:#020302;--panel:#08100bdd;--panelEdge:#29442e;--gridEdge:#213929;--accent:#9fe2ab;--accent2:#f0cc76;--fog:#dbf5df;--mist:#88c6911c;--glow:#9be8a055;--gridGlow:#9be8a020;--floor:#132217;--memory:#667f6a;--wall:#6c786f;--pit:#ad584a;--exit:#f3d487;--torch:#ffbf67;--shrine:#9df1df;--relic:#ffe28f;--hazard:#ff8b77;--shade:#a7c8ff;--watcher:#ffd298;--leech:#8ef0db;--beast:#ff81d9;--player:#fbfff8}
4545#s[data-floor="2"]{--bg0:#170d08;--bg1:#040202;--panel:#130b08e1;--panelEdge:#5c3520;--gridEdge:#4d2d1e;--accent:#ffb07a;--accent2:#ffd18f;--fog:#ffd9c0;--mist:#ff985415;--glow:#ff9d6260;--gridGlow:#ff9d6224;--floor:#24130d;--memory:#8a665b;--wall:#8f6d63;--pit:#dd6a55;--exit:#ffd48a;--torch:#ffaf59;--shrine:#ffd0a6;--relic:#ffe08e;--hazard:#ff7766;--shade:#d3c0ff;--watcher:#ffd0ad;--leech:#f1b68f;--beast:#ff7eb4;--player:#fff7f1}
@@ -57,6 +57,7 @@ linear-gradient(180deg,transparent,rgba(0,0,0,.12));mix-blend-mode:screen;opacit
5757@keyframes pulse{0%,100%{opacity:.84;transform:scale(1)}50%{opacity:1;transform:scale(1.08)}}
5858@keyframes step{0%{transform:scale(.82)}100%{transform:scale(1)}}
5959@keyframes wardbreak{0%{filter:brightness(1.35)}100%{filter:brightness(1)}}
60@keyframes darkstep{0%{filter:brightness(.3);transform:translateX(-3px)}35%{transform:translateX(3px)}70%{transform:translateX(-1px)}100%{filter:brightness(1);transform:none}}
6061@keyframes relicpulse{0%{transform:scale(1)}50%{transform:scale(1.035)}100%{transform:scale(1)}}
6162</style>
6263<div id=s><div id=u></div><div id=p><div id=g></div><div id=i></div></div><div id=l></div><div id=d><button data-k=ArrowUp class=pu>^</button><button data-k=ArrowLeft class=pl>&lt;</button><button data-k=. class=pw>*</button><button data-k=ArrowRight class=pr>&gt;</button><button data-k=ArrowDown class=pd>v</button></div><button id=r hidden>restart</button></div>
@@ -923,7 +924,7 @@ function step(dx,dy){
923924 const nx=S.x+dx,ny=S.y+dy,t=tile(nx,ny)
924925 if(t=="#")return setMsg(roomMsg())
925926 S.turn++
926 if(shadow()){setMsg("Darkness twists the room around you.");burnTorch();beastTurn();return}
927 if(shadow()){setMsg("Darkness twists the room around you.");S.fx="dark";burnTorch();beastTurn();return}
927928 let ex=R[S.r].ex[t]
928929 if(ex){
929930 if(ex[0]=="!"){delete R[S.r].ex[t];ex=ex.slice(1)}
@@ -1065,7 +1066,7 @@ function render(){
10651066 const th=floorTheme()
10661067 U.innerHTML=`floor ${S.level} | ${th.name}<small>${buildTitle()} | ${th.tag} | ${th.accent} | ${MODES[S.mode||"standard"].label} | seed ${S.seed.toString(36)}</small>`
10671068 I.textContent=sidePanel()+(DBG.show?`\n\ndebug\n${variantSummary()}\nsolve : ${R.e?escapeSolve(S.level,V.escape,V.beast,S.level>=3?8:6)?"ok":"fail":"n/a"}\nfloor : ${R.i&&R.v&&R.e?floorSolve(seed,S.level)||"fail":"n/a"}${DBG.out?`\ncheck : ${DBG.out}`:""}\nkeys : v V R j J k K T`:"")
1068 L.textContent=[S.msg,S.hint,roomMsg()].filter(Boolean).join("\n")
1069 L.textContent=[...new Set([S.msg,S.hint,roomMsg()])].filter(Boolean).join("\n")
10691070 X.onclick=()=>{reset(1);render()}
10701071 X.hidden=true
10711072 if(S.intro)G.dataset.intro=INTRO_TEXT
@@ -1074,6 +1075,7 @@ function render(){
10741075 G.className=S.fx=="hit"?"hit":S.fx=="win"?"win":S.fx=="shift"?"shift":""
10751076 if(S.fx=="ward")G.className="ward"
10761077 if(S.fx=="relic")G.className="relic"
1078 if(S.fx=="dark"){G.className="";void G.offsetWidth;G.className="dark"}
10771079 for(let y=0;y<H;y++)for(let x=0;x<W;x++){
10781080 const d=document.createElement("div")
10791081 d.className="t "+cls(x,y)