#s13 *,#s13 *::before,#s13 *::after{box-sizing:border-box}
#s13 img{max-width:100%}
#s13 button{font-family:inherit}
/* Layout: one viewport. A 1500×2000 “world” (the facade) scaled to fit, with door/window as real 3D layers; controls under it. Walk-in opens a white gallery overlay. Single deliberate theme: street at dusk outside, white cube inside. */
#s13{
–street:#121314; –cap:#8b8f92; –capstrong:#e3e4e1; –key:#5AA9FF; –deny:#E5484D; –gallery:#F3F2EE; –galleryInk:#1a1b1c; –galleryMuted:#6e7174;
–f-mono:”DM Mono”, ui-monospace, Menlo, monospace; –f-st:”Big Shoulders Stencil Display”,”Arial Narrow”,Impact,sans-serif; –f-se:”Instrument Serif”,Georgia,serif; –f-body:Archivo,”Helvetica Neue”,Arial,sans-serif;
color-scheme:dark;
}
#s13 [hidden]{display:none!important}
#s13{position:fixed;inset:0;z-index:100000;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;line-height:normal;text-align:left;background:radial-gradient(120% 80% at 50% 15%,#1e2021 0%,var(–street) 62%);color:var(–capstrong);margin:0;padding-inline:16px;padding-block:0;font-family:var(–f-mono);overflow-x:hidden}
.stage{min-height:100%;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding-block:14px}
.frame{position:relative;width:min(100%, calc((100vh – 175px) * .75));min-width:260px;aspect-ratio:3/4;overflow:hidden;background:#0c0d0e;box-shadow:0 40px 80px -30px rgba(0,0,0,.8)}
.world{position:absolute;left:0;top:0;width:1500px;height:2000px;transform-origin:0 0;transform-style:preserve-3d;perspective:2600px;perspective-origin:1095px 1300px;transition:transform 1.6s cubic-bezier(.55,.02,.2,1)}
.world > canvas,.world > .layer{position:absolute;left:0;top:0}
#cBack,#cBase{width:1500px;height:2000px}
#tv{position:absolute;left:351px;top:1066px;width:470px;height:264px}
#doorLight{position:absolute;left:900px;top:900px;width:420px;height:1100px;background:radial-gradient(60% 50% at 30% 60%,rgba(255,255,255,.55),rgba(255,255,255,0) 70%);opacity:0;transition:opacity 1.2s;pointer-events:none}
.dooropen #doorLight{opacity:1}
/* door */
#door{position:absolute;left:958px;top:956px;width:272px;height:946px;transform-style:preserve-3d;transform-origin:right center;transition:transform 1.8s cubic-bezier(.5,.02,.2,1)}
#door canvas{position:absolute;inset:0;width:272px;height:946px;backface-visibility:hidden}
#door .edge{position:absolute;left:0;top:0;width:16px;height:946px;background:linear-gradient(90deg,#0b0b0c,#1d1e1f 40%,#0e0f10);transform-origin:left center;transform:rotateY(90deg)}
#door .dback{position:absolute;inset:0;background:linear-gradient(90deg,#d9d7d0,#c8c6bf);transform:rotateY(180deg);backface-visibility:hidden}
.dooropen #door{transform:rotateY(-96deg)}
.shake #door{animation:shake .4s}
@keyframes shake{20%{transform:translateX(-4px)}40%{transform:translateX(4px)}60%{transform:translateX(-3px)}80%{transform:translateX(2px)}}
.keypad{position:absolute;left:10px;top:336px;width:22px;display:grid;grid-template-columns:repeat(3,4px);gap:4px 3px;justify-content:center}
.keypad i{width:4px;height:4px;border-radius:50%;background:#202327;transition:background .25s, box-shadow .25s}
.armed .keypad i{background:var(–key);box-shadow:0 0 6px var(–key)}
.denied .keypad i{background:var(–deny);box-shadow:0 0 6px var(–deny)}
.unlocked .keypad i{background:#4ADE80;box-shadow:0 0 6px #4ADE80}
/* window panel */
#win{position:absolute;left:247px;top:970px;width:678px;height:478px;transform-style:preserve-3d;transform-origin:center bottom;transition:transform 1.6s cubic-bezier(.6,.02,.25,1.05)}
#win canvas{position:absolute;inset:0;width:678px;height:478px;backface-visibility:hidden}
#win canvas.wback{transform:rotateX(180deg)}
#win .wedge{position:absolute;left:0;top:0;width:678px;height:16px;background:linear-gradient(#2a2b2c,#0e0f10);transform-origin:center top;transform:rotateX(-90deg)}
.windown #win{transform:rotateX(-86deg)}
.hasp{position:absolute;width:30px;height:86px;border-radius:5px;background:linear-gradient(90deg,#0c0c0d,#26282a 45%,#121314);box-shadow:2px 4px 6px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.12);transform-origin:center 12px;transition:transform 1s cubic-bezier(.5,.02,.2,1)}
.hasp::after{content:””;position:absolute;left:50%;top:9px;width:8px;height:8px;margin-left:-4px;border-radius:50%;background:radial-gradient(circle at 35% 35%,#8d9194,#2b2d2f)}
.windown .hasp{transform:rotateX(165deg)}
/* devices */
#dev{position:absolute;left:0;top:0;width:1500px;height:2000px;pointer-events:none}
#dev .hit{pointer-events:auto;cursor:pointer}
#dusk{position:absolute;inset:0;background:rgba(4,6,14,.45);opacity:0;transition:opacity .6s;pointer-events:none}
.lit #dusk{opacity:1}
#cone{opacity:0;transition:opacity .6s}
.lit #cone{opacity:1}
.lampface{transition:fill .4s}
.lit .lampface{fill:#FFFEF6}
.lampglow{opacity:0;transition:opacity .5s}
.lit .lampglow{opacity:1}
#led{animation:blink 1.6s infinite}
@keyframes blink{0%,60%{opacity:1}61%,100%{opacity:.15}}
/* hit areas */
.hitbox{position:absolute;background:transparent;border:0;padding:0;cursor:pointer}
.hitbox:focus-visible{outline:4px solid var(–key);outline-offset:4px}
#hitDoor{left:950px;top:946px;width:290px;height:966px}
#hitWin{left:247px;top:970px;width:678px;height:478px}
.windown #hitWin{top:1380px;height:200px}
.dooropen #hitDoor{left:958px;width:272px}
/* overlays in frame (not in 3D) */
.grain{position:absolute;inset:0;pointer-events:none;mix-blend-mode:overlay;opacity:.22;background-size:256px 256px}
.vig{position:absolute;inset:0;pointer-events:none;background:radial-gradient(90% 75% at 50% 45%,transparent 60%,rgba(0,0,0,.5))}
.white{position:absolute;inset:0;background:#fff;opacity:0;pointer-events:none;transition:opacity .7s}
.loading{position:absolute;inset:0;display:grid;place-items:center;font-size:.72rem;letter-spacing:.2em;color:var(–cap);background:#0c0d0e;transition:opacity .6s}
.loading.done{opacity:0;pointer-events:none}
/* controls */
.bar{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;max-width:760px}
.b{font:500 .72rem var(–f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(–capstrong);background:#1c1e20;border:1px solid #3a3d40;padding:.6rem .85rem;cursor:pointer}
.b:hover{border-color:var(–capstrong)}
.b.go{background:#F2F0EA;color:#121314;border-color:#F2F0EA}
.b[hidden]{display:none}
.b:focus-visible{outline:2px solid var(–key);outline-offset:2px}
.cap{display:flex;gap:16px;flex-wrap:wrap;justify-content:center;font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:var(–cap)}
.cap b{color:var(–capstrong);font-weight:500}
#msg{min-height:1.2em;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(–capstrong);text-align:center}
/* ===== inside ===== */
#inside{position:fixed;inset:0;z-index:30;background:var(–gallery);color:var(–galleryInk);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:14px 16px;opacity:0;transition:opacity .9s}
#inside.on{opacity:1}
.room{position:relative;width:min(100%, calc(100vh – 150px));aspect-ratio:1/1;overflow:hidden;background:#e9e8e3;cursor:grab;touch-action:pan-y;user-select:none;-webkit-user-select:none}
.room.dragging{cursor:grabbing}
.cube{position:absolute;inset:0;transform-style:preserve-3d;transition:transform .8s cubic-bezier(.5,.05,.2,1)}
.cube.live{transition:none}
.face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:hidden;background:linear-gradient(90deg,#d9d8d2 0%,#f4f3ef 14%,#f7f6f2 50%,#f4f3ef 86%,#d6d5cf 100%)}
.face .ceil{position:absolute;left:0;right:0;top:0;height:11%;background:linear-gradient(#e2e1dc,#eceae5);border-bottom:1px solid #d3d2cc}
.face .ceil .track{position:absolute;left:8%;right:8%;top:38%;height:5px;background:#2a2b2c}
.face .ceil .spot{position:absolute;top:30%;width:18px;height:26px;margin-left:-9px;background:linear-gradient(#3a3b3c,#141516);border-radius:3px 3px 8px 8px}
.face .ceil .spot::after{content:””;position:absolute;left:50%;top:100%;width:260px;height:300px;margin-left:-130px;background:radial-gradient(50% 40% at 50% 0%,rgba(255,250,235,.55),transparent 70%);pointer-events:none}
.face .floor{position:absolute;left:0;right:0;bottom:0;height:20.25%;background:linear-gradient(#bdbbb5,#a3a19b);border-top:2px solid #cfcdc7}
.face .floor::after{content:””;position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,.08),transparent 20%,transparent 80%,rgba(0,0,0,.08))}
.wa{position:absolute;left:0;right:0;top:11%;height:68.75%}
.art{position:absolute;padding:0;border:0;background:#fff;cursor:pointer;box-shadow:0 1px 0 rgba(0,0,0,.25),6px 14px 18px -6px rgba(0,0,0,.35),0 0 0 6px #151617;transition:transform .25s}
.art.oak{box-shadow:0 1px 0 rgba(0,0,0,.25),6px 14px 18px -6px rgba(0,0,0,.35),0 0 0 6px #b48a5a}
.art:hover{transform:translateY(-2px)}
.art .mat{position:absolute;inset:7%;overflow:hidden;box-shadow:inset 0 0 0 1px rgba(0,0,0,.08)}
.art svg{width:100%;height:100%;display:block}
.placard{position:absolute;font:500 clamp(5px,.95vmin,9px)/1.35 var(–f-mono);color:var(–galleryMuted);white-space:nowrap;pointer-events:none}
.placard b{color:var(–galleryInk);font-weight:500;display:block}
.vserif{position:absolute;font-family:var(–f-se);font-style:italic;font-size:clamp(9px,2.2vmin,22px);color:#1a1b1c}
.vinyl{position:absolute;line-height:.9;font-family:var(–f-st);font-weight:900;color:#1a1b1c;letter-spacing:.04em}
.ihot{position:absolute;background:transparent;border:0;padding:0;cursor:pointer}
.ihot:focus-visible,.art:focus-visible{outline:3px solid var(–key);outline-offset:4px}
#tv2{position:absolute;display:block;background:#000;box-shadow:0 0 0 5px #0b0b0c,8px 16px 22px -8px rgba(0,0,0,.45)}
.dooropening{position:absolute;background:linear-gradient(#2b2e33,#16181b 60%,#3a3c3f);box-shadow:inset 0 0 0 8px #1b1c1d}
.dooropening::after{content:””;position:absolute;left:0;right:0;bottom:0;height:22%;background:linear-gradient(#5a5c5e,#2f3133)}
.bench{position:absolute;background:#c9a06e;box-shadow:0 10px 12px -6px rgba(0,0,0,.35)}
.ibar{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;align-items:center}
.ib{font:500 .72rem var(–f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(–galleryInk);background:transparent;border:1px solid var(–galleryInk);padding:.55rem .8rem;cursor:pointer}
.ib.solid{background:var(–galleryInk);color:var(–gallery)}
.ib:focus-visible{outline:2px solid var(–key);outline-offset:2px}
.wallname{font:500 .72rem var(–f-mono);letter-spacing:.18em;text-transform:uppercase;min-width:9rem;text-align:center}
.card{position:fixed;left:50%;bottom:calc(16px + env(safe-area-inset-bottom,0px));transform:translateX(-50%);width:min(420px,calc(100% – 32px));background:#fff;color:var(–galleryInk);border:1px solid #d6d5cf;box-shadow:0 20px 40px -20px rgba(0,0,0,.35);display:grid;grid-template-columns:90px minmax(0,1fr);gap:14px;padding:14px;z-index:40}
.card .th{aspect-ratio:3/4;box-shadow:0 0 0 4px #151617}
.card .th svg{width:100%;height:100%;display:block}
.card h3{margin:0;font:500 .95rem var(–f-mono)}
.card p{margin:.2rem 0;color:var(–galleryMuted);font-size:.78rem}
.card .row{display:flex;gap:8px;flex-wrap:wrap;margin-top:.5rem}
.card a{font:500 .72rem var(–f-mono);letter-spacing:.1em;text-transform:uppercase;background:var(–galleryInk);color:#fff;padding:.5rem .7rem;text-decoration:none}
.card button{font:500 .72rem var(–f-mono);letter-spacing:.1em;text-transform:uppercase;background:transparent;border:1px solid var(–galleryInk);padding:.45rem .7rem;cursor:pointer;color:var(–galleryInk)}
/* coming soon overlay */
#soon{position:fixed;inset:0;z-index:35;background:var(–gallery);color:var(–galleryInk);display:grid;place-items:center;padding:24px 16px;opacity:0;transition:opacity .7s}
#soon.on{opacity:1}
.soonbox{max-width:620px;display:grid;gap:18px}
.soonbox h1{margin:0;font-family:var(–f-st);font-weight:900;font-size:clamp(3.4rem,14vw,7.5rem);line-height:.86;letter-spacing:.01em}
.soonbox h1 i{font-family:var(–f-se);font-weight:400;font-size:.62em;letter-spacing:0;display:block}
.soonbox p{font:400 1.08rem/1.65 var(–f-body);margin:0;max-width:52ch;color:#2c2d2e}
.soonbox p a{color:inherit}
.soonbox .eyebrow{font:500 .7rem var(–f-mono);letter-spacing:.16em;text-transform:uppercase;color:var(–galleryMuted)}
.soonbox .links{display:flex;gap:8px;flex-wrap:wrap}
.soonbox .links a,.soonbox .links button{font:500 .72rem var(–f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(–galleryInk);border:1px solid var(–galleryInk);padding:.65rem .9rem;text-decoration:none;background:transparent;cursor:pointer}
.soonbox .links a.solid{background:var(–galleryInk);color:var(–gallery)}
#hitWall{left:247px;top:507px;width:1001px;height:398px}
.top .soonlink{color:var(–cap)}
.top sup,.pgnav sup{font-size:.55em;letter-spacing:.1em;margin-left:.25em;color:#F2C431}
.pgnav sup{color:#B3261E}
.nero-hero{aspect-ratio:1001/398;max-width:100%;margin:0 0 1.4rem;box-shadow:0 18px 30px -16px rgba(0,0,0,.45)}
.nero-hero canvas{width:100%;height:100%;display:block}
.cap-note{font:400 .78rem var(–f-mono);color:var(–galleryMuted);margin:-.8rem 0 1.4rem}
/* top nav + blog pages */
.top{width:min(100%,900px);display:flex;align-items:center;gap:6px 18px;flex-wrap:wrap;justify-content:center;font-size:.7rem;letter-spacing:.16em;text-transform:uppercase}
.top a{color:var(–cap);text-decoration:none;padding:.35rem 0;border-bottom:1px solid transparent}
.top a:hover,.top a:focus-visible{color:var(–capstrong);border-bottom-color:var(–capstrong);outline:none}
.top .logo i{font-family:var(–f-se);font-weight:400;font-size:.95rem;letter-spacing:0;color:var(–cap);margin-left:.3rem}
.top .logo{font-family:var(–f-st);font-weight:900;font-size:1.45rem;letter-spacing:.02em;line-height:1;color:var(–capstrong);text-transform:none;margin-right:auto}
@media (max-width:620px){.top .logo{width:100%;text-align:center;margin-right:0}}
#page{position:fixed;inset:0;z-index:50;background:var(–gallery);color:var(–galleryInk);overflow-y:auto;padding-inline:16px;padding-block:0}
.pg{max-width:680px;margin:0 auto;padding-block:28px 64px}
.pgnav{display:flex;gap:6px 18px;flex-wrap:wrap;align-items:center;font:500 .7rem var(–f-mono);letter-spacing:.14em;text-transform:uppercase;border-bottom:1px solid #d3d2cc;padding-bottom:14px;margin-bottom:36px}
.pgnav a{color:var(–galleryMuted);text-decoration:none}
.pgnav a:hover,.pgnav a[aria-current=”page”]{color:var(–galleryInk)}
.pgnav .logo i{font-family:var(–f-se);font-weight:400;font-size:.95rem;color:var(–galleryMuted);margin-left:.3rem}
.pgnav .logo{font-family:var(–f-st);font-weight:900;font-size:1.45rem;line-height:1;text-transform:none;letter-spacing:.02em;letter-spacing:.03em;color:var(–galleryInk);text-transform:none;margin-right:auto}
.eyebrow{font:500 .7rem var(–f-mono);letter-spacing:.16em;text-transform:uppercase;color:var(–galleryMuted)}
.pg h1{font-family:var(–f-st);font-weight:900;font-weight:400;font-size:clamp(2rem,6vw,3.2rem);line-height:1.02;margin:.4rem 0 1.4rem;text-wrap:balance}
.pg p{font:400 1.06rem/1.7 var(–f-body);margin:0 0 1.1rem;color:#2c2d2e;max-width:62ch}
.pg .hero{aspect-ratio:16/9;max-width:100%;margin:0 0 1.8rem;overflow:hidden;background:#151617;display:grid;place-items:center}
.pg .hero svg{height:86%;width:auto;box-shadow:0 0 0 6px #fff,0 18px 30px -12px rgba(0,0,0,.5)}
.posts{list-style:none;margin:0;padding:0;border-top:1px solid #d3d2cc}
.posts a{display:grid;grid-template-columns:5.5rem minmax(0,1fr) auto;gap:14px;align-items:baseline;padding:18px 0;border-bottom:1px solid #d3d2cc;text-decoration:none;color:inherit}
.posts a:hover h2{text-decoration:underline}
.posts h2{font:400 1.6rem/1.1 var(–f-se);font-style:italic;margin:0}
.posts p{margin:.25rem 0 0;font-size:.85rem;color:var(–galleryMuted)}
.posts .yr{font:500 .85rem var(–f-mono);color:var(–galleryMuted)}
.posts .arr{font:500 .9rem var(–f-mono)}
@media (max-width:520px){.posts a{grid-template-columns:3.6rem minmax(0,1fr)}.posts .arr{display:none}}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin:1.6rem 0;padding:16px 0;border-block:1px solid #d3d2cc}
.facts div{display:grid;gap:3px;font:400 .85rem var(–f-mono)}
.facts span{font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(–galleryMuted)}
.links{display:flex;gap:8px;flex-wrap:wrap;margin-top:1.4rem}
.links a,.links button{font:500 .72rem var(–f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(–galleryInk);border:1px solid var(–galleryInk);padding:.6rem .85rem;text-decoration:none;background:transparent;cursor:pointer}
.links a.solid{background:var(–galleryInk);color:var(–gallery)}
.backlink{display:inline-block;margin-top:2rem;font:500 .72rem var(–f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(–galleryInk)}
#hitNote{left:4px;top:1188px;width:88px;height:96px}
@media (prefers-reduced-motion: reduce){#s13 *{transition-duration:.01s!important;animation:none!important}}
35S13ST Philadelphia
Nero One
About
Projects
ShopSOON
Book
IG
COMING soon.
The gallery and shop are being built out now. First up on the wall: Nero One, live on Tuesday 10.13.
(()=>{
const W=1500,H=2000,$=s=>document.querySelector(s),$$=s=>[…document.querySelectorAll(s)];
const reduce=matchMedia(“(prefers-reduced-motion: reduce)”).matches;
const SHOP=”https://3513st.myshopify.com/”;
function mulberry(a){return()=>{a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
function Noise(seed){const r=mulberry(seed),q=[…Array(256).keys()],p=new Uint8Array(512);for(let i=255;i>0;i–){const j=(r()*(i+1))|0;[q[i],q[j]]=[q[j],q[i]]}for(let i=0;ip[(p[i&255]+j)&255]/255;
const vn=(x,y)=>{const xi=Math.floor(x),yi=Math.floor(y),xf=x-xi,yf=y-yi,u=xf*xf*(3-2*xf),v=yf*yf*(3-2*yf),a=h(xi,yi),b=h(xi+1,yi),c=h(xi,yi+1),d=h(xi+1,yi+1);return a+(b-a)*u+(c-a)*v+(a-b-c+d)*u*v};
return(x,y,o=3)=>{let s=0,am=1,f=1,t=0;for(let i=0;i<o;i++){s+=vn(x*f,y*f)*am;t+=am;am*=.5;f*=2.03}return s/t}}
function cv(w,h){const c=document.createElement("canvas");c.width=w;c.height=h;return c}
function field(w,h,fn){const c=cv(w,h),x=c.getContext("2d"),im=x.createImageData(w,h),d=im.data;let i=0;for(let y=0;y<h;y++)for(let X=0;X{ctx.beginPath();ctx.moveTo(x+r,y);ctx.arcTo(x+w,y,x+w,y+h,r);ctx.arcTo(x+w,y+h,x,y+h,r);ctx.arcTo(x,y+h,x,y,r);ctx.arcTo(x,y,x+w,y,r);ctx.closePath()};
/* ———- shared textures (fixed seeds so the building stays the same) ———- */
let T={};
function buildTextures(){
// fine grain tile
const gr=mulberry(3);T.grain=field(256,256,()=>{const v=110+gr()*40|0;return[v,v,v,255]});
$(“#grain”).style.backgroundImage=`url(${T.grain.toDataURL()})`;
// gloss-black plywood brush texture (half res then scaled)
const nb=Noise(5),hw=642,hh=780;
const half=field(hw,hh,(x,y)=>{const X=x*2,Y=y*2;const v=nb(X*.03,Y*.0016,3)*.65+nb(X*.11,Y*.005,2)*.35;const roller=Math.sin(Y*.021+nb(X*.01,Y*.004)*6)*.5+.5;const l=15+(v-.5)*18+roller*2.2;return[l,l+1,l+2.5,255]});
T.black=cv(1283,1560);const b=T.black.getContext(“2d”);b.imageSmoothingQuality=”high”;b.drawImage(half,0,0,1283,1560);
b.globalAlpha=.06;b.globalCompositeOperation=”overlay”;b.fillStyle=b.createPattern(T.grain,”repeat”);b.fillRect(0,0,1283,1560);b.globalAlpha=1;b.globalCompositeOperation=”source-over”;
// plaster
const np=Noise(8),nq=Noise(12);
T.plaster=field(1385,440,(x,y)=>{const n=np(x*.02,y*.02,3),f=nq(x*.15,y*.15,2);const l=66+(n-.5)*22+(f-.5)*8;return[l,l+3,l+1,255]});
T.peel=field(1385,940,(x,y)=>{const inBand=y1288&&y1100?(x-1100)/285:x440?.04:0);const n=nq(x*.024,y*.04,4);
if(n>th){const k=Math.min(1,(n-th)*9);const c=178+k*30+(nq(x*.4,y*.4,1)-.5)*30;return[c,c*.93,c*.77,255]}
const ns=nq((x-3)*.024,(y-4)*.04,4);if(ns>th)return[16,18,17,170];return[0,0,0,0]});
// stone
const ns=Noise(21),sr=mulberry(22);
T.stone=field(115,2000,(x,y)=>{const n=ns(x*.03,y*.01,4),f=ns(x*.3,y*.3,1);let r=208+(n-.5)*26+(f-.5)*10,g=195+(n-.5)*24+(f-.5)*9,bb=158+(n-.5)*20+(f-.5)*8;if(sr()<.012){r-=45;g-=45;bb-=40}if(x{const a=((x>>1)+(y>>1))%2?1:0;const v=a?118:96;return[v,v,v,255]});
// plywood raw (window back)
const nw=Noise(31);
T.ply=field(678,478,(x,y)=>{const n=nw(x*.004,y*.05,4),g=Math.sin(y*.09+n*14)*.5+.5;const l=.82+g*.12+(n-.5)*.15;return[196*l,160*l,112*l,255]});
}
/* ———- facade painter ———- */
function board(ctx,x,y,w,h,{lift=.018,shadow=true,bevel=true}={}){
if(shadow){ctx.save();ctx.shadowColor=”rgba(0,0,0,.6)”;ctx.shadowBlur=12;ctx.shadowOffsetX=3;ctx.shadowOffsetY=5;ctx.fillStyle=”#121314″;ctx.fillRect(x,y,w,h);ctx.restore()}
ctx.drawImage(T.black,Math.max(0,x-112),Math.max(0,y-440),w,h,x,y,w,h);
ctx.fillStyle=`rgba(255,255,255,${lift})`;ctx.fillRect(x,y,w,h);
if(bevel){ctx.fillStyle=”rgba(255,255,255,.075)”;ctx.fillRect(x,y,w,2);ctx.fillRect(x,y,2,h);ctx.fillStyle=”rgba(0,0,0,.55)”;ctx.fillRect(x,y+h-3,w,3);ctx.fillRect(x+w-3,y,3,h)}
}
function inset(ctx,x,y,w,h){ctx.fillStyle=”rgba(0,0,0,.6)”;ctx.fillRect(x,y,w,4);ctx.fillRect(x,y,4,h);ctx.fillStyle=”rgba(255,255,255,.05)”;ctx.fillRect(x,y+h-2,w,2);ctx.fillRect(x+w-2,y,2,h)}
function sheen(ctx,x,y,rx,ry,a){ctx.save();ctx.translate(x,y);ctx.scale(1,ry/rx);const g=ctx.createRadialGradient(0,0,0,0,0,rx);g.addColorStop(0,`rgba(255,255,255,${a})`);g.addColorStop(1,”rgba(255,255,255,0)”);ctx.fillStyle=g;ctx.globalCompositeOperation=”screen”;ctx.fillRect(-rx,-rx,rx*2,rx*2);ctx.restore()}
function streak(ctx,x,y,w,h,a){const g=ctx.createLinearGradient(x,0,x+w,0);g.addColorStop(0,”rgba(255,255,255,0)”);g.addColorStop(.5,`rgba(255,255,255,${a})`);g.addColorStop(1,”rgba(255,255,255,0)”);ctx.fillStyle=g;ctx.fillRect(x,y,w,h)}
function scuffs(ctx,rand,x,y,w,h,n){for(let i=0;i<n;i++){const px=x+rand()*w,py=y+rand()*h,l=3+rand()*20,a=(rand()-.5)*1.4;ctx.strokeStyle=rand(){ctx.fillStyle=c;ctx.fillRect(0,y,1385,h)};
mould(34,12,”#2c2f2d”);mould(46,4,”#6a6e6a”);mould(176,10,”#272a28″);mould(186,3,”#5d615d”);
ctx.fillStyle=”rgba(0,0,0,.18)”;ctx.fillRect(300,50,935,128);
[[326,62],[784,62]].forEach(([x,y])=>{ctx.fillStyle=”rgba(0,0,0,.25)”;ctx.fillRect(x,y,428,104);ctx.fillStyle=”rgba(255,255,255,.06)”;ctx.fillRect(x+8,y+8,412,88);inset(ctx,x,y,428,104);inset(ctx,x+8,y+8,412,88)});
ctx.strokeStyle=”#a7aba8″;ctx.lineWidth=2.2;ctx.beginPath();ctx.moveTo(603,46);ctx.lineTo(606,118);ctx.lineTo(613,128);ctx.stroke();
ctx.strokeStyle=”#202221″;ctx.lineWidth=11;ctx.lineCap=”round”;ctx.beginPath();ctx.moveTo(40,-4);ctx.lineTo(54,30);ctx.lineTo(92,46);ctx.stroke();
rr(70,30,46,34,7,ctx);ctx.fillStyle=”#262827″;ctx.fill();
ctx.fillStyle=”#874633″;ctx.fillRect(1335,8,20,42);
// right wall strip next to transom
ctx.drawImage(T.plaster,1000,0,100,440,1284,440,101,490);
ctx.drawImage(T.peel,0,0);
// stone pilaster
ctx.drawImage(T.stone,1385,0);
ctx.fillStyle=”rgba(60,50,30,.12)”;for(let y=230;y<1880;y+=236)ctx.fillRect(1385,y,115,2);
ctx.fillStyle="#3a3a33";ctx.beginPath();ctx.arc(1467,522,4,0,7);ctx.fill();
g=ctx.createLinearGradient(0,1878,0,2000);g.addColorStop(0,"#b6aa99");g.addColorStop(1,"#a1968a");ctx.fillStyle=g;ctx.fillRect(1385,1878,115,122);
const sr=mulberry(41);for(let i=0;i<700;i++){ctx.fillStyle=sr()<.5?"rgba(60,55,50,.35)":"rgba(240,235,225,.35)";ctx.fillRect(1385+sr()*115,1880+sr()*120,1.5,1.5)}
ctx.fillStyle="#7d7366";ctx.fillRect(1385,1878,115,3);
// left neighbor strip
ctx.fillStyle="#2a2c2c";ctx.fillRect(0,440,120,1560);ctx.drawImage(T.black,0,0,120,1560,0,440,120,1560);ctx.fillStyle="rgba(70,74,72,.35)";ctx.fillRect(0,440,120,1560);
ctx.fillStyle="#9a7a50";ctx.fillRect(0,600,9,150);
// intercom
g=ctx.createLinearGradient(0,1294,58,1406);g.addColorStop(0,"#9a9d9c");g.addColorStop(1,"#6b6e6e");ctx.fillStyle=g;ctx.fillRect(0,1294,58,112);ctx.strokeStyle="#3f4242";ctx.lineWidth=3;ctx.strokeRect(0,1294,58,112);
ctx.fillStyle="#565959";for(let y=1306;y{ctx.beginPath();ctx.moveTo(a,b);ctx.lineTo(c,d);ctx.stroke()});
// transom
board(ctx,245,505,1005,402,{lift:.01});
ctx.strokeStyle=”rgba(0,0,0,.45)”;ctx.lineWidth=2;[730,860,990,1118].forEach(x=>{ctx.beginPath();ctx.moveTo(x,507);ctx.lineTo(x,905);ctx.stroke()});ctx.beginPath();ctx.moveTo(247,690);ctx.lineTo(1248,690);ctx.stroke();
sheen(ctx,1010,700,280,190,.07);sheen(ctx,470,610,210,110,.05);
g=ctx.createLinearGradient(0,505,0,640);g.addColorStop(0,”rgba(0,0,0,.65)”);g.addColorStop(1,”rgba(0,0,0,0)”);ctx.fillStyle=g;ctx.fillRect(245,505,1005,135);
// tape
ctx.save();ctx.fillStyle=”#0a0a0b”;ctx.beginPath();ctx.moveTo(536,506);ctx.lineTo(654,506);ctx.lineTo(648,530);ctx.quadraticCurveTo(612,552,576,538);ctx.quadraticCurveTo(552,548,539,533);ctx.closePath();ctx.shadowColor=”rgba(0,0,0,.6)”;ctx.shadowBlur=8;ctx.shadowOffsetY=4;ctx.fill();ctx.restore();
ctx.strokeStyle=”rgba(150,154,158,.55)”;ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(548,513);ctx.quadraticCurveTo(600,530,642,515);ctx.stroke();
// right trim board
board(ctx,1246,490,38,442,{lift:.03});streak(ctx,1251,495,8,430,.06);
// lower assembly
board(ctx,213,898,720,1092,{lift:.012});
board(ctx,213,898,720,72,{lift:.03});
board(ctx,247,970,678,478,{lift:.008,shadow:false});inset(ctx,247,970,678,478);sheen(ctx,640,1190,310,220,.06);
board(ctx,213,1448,720,36,{lift:.035});
[[282,1444,26,14],[584,1452,30,16],[875,1444,26,14]].forEach(([x,y,w,h])=>{g=ctx.createLinearGradient(x,y,x,y+h);g.addColorStop(0,”#3b3d3f”);g.addColorStop(1,”#141516″);ctx.fillStyle=g;ctx.fillRect(x,y,w,h);ctx.fillStyle=”rgba(255,255,255,.15)”;ctx.fillRect(x,y,w,1)});
board(ctx,255,1484,668,476,{lift:.008,shadow:false});inset(ctx,255,1484,668,476);sheen(ctx,560,1710,290,210,.05);
board(ctx,213,1960,720,30,{lift:.04});
// door frame + casing
board(ctx,930,922,378,1070,{lift:.02});
board(ctx,1240,930,62,1060,{lift:.03});streak(ctx,1248,935,10,1050,.06);
ctx.fillStyle=”#0c0d0e”;ctx.fillRect(950,946,290,966);
// door slab (copied out to door layer later)
board(ctx,958,956,272,946,{lift:.016,shadow:false});
streak(ctx,1172,962,40,930,.07);streak(ctx,988,962,26,930,.04);sheen(ctx,1110,1250,140,280,.06);
// peephole
g=ctx.createRadialGradient(1079,1184,1,1081,1186,9);g.addColorStop(0,”#e6e8e9″);g.addColorStop(1,”#55595b”);ctx.fillStyle=g;ctx.beginPath();ctx.arc(1081,1186,8,0,7);ctx.fill();ctx.fillStyle=”#141618″;ctx.beginPath();ctx.arc(1081,1186,3.4,0,7);ctx.fill();
// smart lock
ctx.save();ctx.shadowColor=”rgba(0,0,0,.7)”;ctx.shadowBlur=8;ctx.shadowOffsetX=2;ctx.shadowOffsetY=4;rr(961,1266,38,100,6,ctx);g=ctx.createLinearGradient(961,0,999,0);g.addColorStop(0,”#1c1e21″);g.addColorStop(.5,”#0a0b0c”);g.addColorStop(1,”#141518″);ctx.fillStyle=g;ctx.fill();ctx.restore();
rr(961,1266,38,100,6,ctx);ctx.strokeStyle=”#34373b”;ctx.lineWidth=1.5;ctx.stroke();
g=ctx.createLinearGradient(961,1266,999,1310);g.addColorStop(0,”rgba(255,255,255,.18)”);g.addColorStop(.4,”rgba(255,255,255,0)”);ctx.fillStyle=g;rr(963,1268,34,40,5,ctx);ctx.fill();
ctx.fillStyle=”#1d2024″;rr(968,1274,24,12,3,ctx);ctx.fill();ctx.fillStyle=”#3b414a”;ctx.beginPath();ctx.arc(980,1280,3.2,0,7);ctx.fill();
ctx.fillStyle=”#16181b”;rr(970,1340,20,18,4,ctx);ctx.fill();ctx.strokeStyle=”#2f3236″;ctx.lineWidth=1;ctx.beginPath();ctx.arc(980,1349,6,0,7);ctx.stroke();ctx.beginPath();ctx.arc(980,1349,3.5,0,7);ctx.stroke();
// knob
ctx.save();ctx.shadowColor=”rgba(0,0,0,.7)”;ctx.shadowBlur=8;ctx.shadowOffsetX=3;ctx.shadowOffsetY=5;ctx.fillStyle=”#2a2c2d”;ctx.beginPath();ctx.arc(987,1433,18,0,7);ctx.fill();ctx.restore();
g=ctx.createRadialGradient(982,1427,2,987,1433,15);g.addColorStop(0,”#ffffff”);g.addColorStop(.35,”#c3c6c8″);g.addColorStop(.8,”#6c7073″);g.addColorStop(1,”#3b3e40″);ctx.fillStyle=g;ctx.beginPath();ctx.arc(987,1433,14,0,7);ctx.fill();
ctx.fillStyle=”#2e3133″;rr(985.5,1425,3,11,1.5,ctx);ctx.fill();
// mail slot
ctx.save();ctx.shadowColor=”rgba(0,0,0,.6)”;ctx.shadowBlur=6;ctx.shadowOffsetY=3;g=ctx.createLinearGradient(0,1596,0,1642);g.addColorStop(0,”#4a4c4e”);g.addColorStop(.5,”#2a2c2e”);g.addColorStop(1,”#1a1b1c”);ctx.fillStyle=g;ctx.fillRect(1014,1596,164,46);ctx.restore();
ctx.strokeStyle=”rgba(255,255,255,.05)”;ctx.lineWidth=1;for(let y=1598;y{ctx.fillStyle=”#6b6e70″;ctx.beginPath();ctx.arc(x,y,2.4,0,7);ctx.fill()});
// drips + dings on door
ctx.strokeStyle=”#09090a”;ctx.lineWidth=5;ctx.lineCap=”round”;[[1180,1856,28],[1100,1868,14],[1022,1798,18],[1205,1500,12]].forEach(([x,y,l])=>{ctx.beginPath();ctx.moveTo(x,y);ctx.quadraticCurveTo(x+3,y+l/2,x,y+l);ctx.stroke()});
const rs=mulberry(77);scuffs(ctx,rs,965,1000,260,880,46);
scuffs(ctx,rs,255,980,660,460,26);scuffs(ctx,rs,260,1490,650,460,34);scuffs(ctx,rs,250,520,990,380,22);scuffs(ctx,rs,120,460,120,1500,24);scuffs(ctx,rs,1290,940,95,1040,20);
// dust/grime at the bottom
g=ctx.createLinearGradient(0,1840,0,1990);g.addColorStop(0,”rgba(150,140,120,0)”);g.addColorStop(1,”rgba(150,140,120,.14)”);ctx.fillStyle=g;ctx.fillRect(112,1840,1283,150);
// threshold
board(ctx,950,1902,290,88,{lift:.05,shadow:false});
g=ctx.createLinearGradient(0,1902,0,1916);g.addColorStop(0,”#8a8c8d”);g.addColorStop(1,”#3d3f40″);ctx.fillStyle=g;ctx.fillRect(950,1902,290,14);
// ground
g=ctx.createLinearGradient(0,1988,0,2000);g.addColorStop(0,”#5b5c59″);g.addColorStop(1,”#3a3b39″);ctx.fillStyle=g;ctx.fillRect(0,1988,W,12);
}
function paintAwning(ctx){
// cast shadow
ctx.save();ctx.filter=”blur(16px)”;ctx.fillStyle=”rgba(0,0,0,.55)”;ctx.beginPath();ctx.moveTo(100,450);ctx.lineTo(1440,494);ctx.lineTo(1438,575);ctx.lineTo(98,520);ctx.closePath();ctx.fill();ctx.restore();
const poly=()=>{ctx.beginPath();ctx.moveTo(292,150);ctx.lineTo(1225,150);ctx.lineTo(1432,468);ctx.lineTo(108,428);ctx.closePath()};
ctx.save();poly();ctx.clip();
let g=ctx.createLinearGradient(0,150,0,470);g.addColorStop(0,”#505355″);g.addColorStop(.5,”#5e6163″);g.addColorStop(1,”#4d5052″);ctx.fillStyle=g;ctx.fillRect(100,150,1340,330);
ctx.globalAlpha=.16;ctx.globalCompositeOperation=”overlay”;ctx.fillStyle=ctx.createPattern(T.weave,”repeat”);ctx.fillRect(100,150,1340,330);
ctx.fillStyle=ctx.createPattern(T.grain,”repeat”);ctx.globalAlpha=.35;ctx.fillRect(100,150,1340,330);
ctx.globalCompositeOperation=”source-over”;ctx.globalAlpha=1;
g=ctx.createLinearGradient(100,0,1440,0);g.addColorStop(0,”rgba(0,0,0,.28)”);g.addColorStop(.22,”rgba(0,0,0,0)”);g.addColorStop(.8,”rgba(255,255,255,.035)”);g.addColorStop(1,”rgba(0,0,0,.25)”);ctx.fillStyle=g;ctx.fillRect(100,150,1340,330);
const ds=mulberry(55);for(let i=0;i<26;i++){const x=200+ds()*1150;g=ctx.createLinearGradient(0,150,0,470);g.addColorStop(0,"rgba(0,0,0,0)");g.addColorStop(1,`rgba(${ds()[parseInt(h.slice(1,3),16),parseInt(h.slice(3,5),16),parseInt(h.slice(5,7),16)];
const mix=(a,b,t)=>{const A=hx(a),B=hx(b);return`rgb(${A.map((v,i)=>Math.round(v+(B[i]-v)*t)).join(“,”)})`};
function halftone(g,x,y,w,h,col,step,fn){g.fillStyle=col;let row=0;for(let yy=y;yy<y+h+step;yy+=step,row++)for(let xx=x+(row%2?step/2:0);xx.4){g.beginPath();g.arc(xx,yy,r,0,7);g.fill()}}}
function leaf(g,x,y,len,wid,ang,col){g.save();g.translate(x,y);g.rotate(ang);const gr=g.createLinearGradient(0,-wid,0,wid);gr.addColorStop(0,mix(col,”#ffffff”,.18));gr.addColorStop(.5,col);gr.addColorStop(1,mix(col,”#000000″,.3));g.fillStyle=gr;
g.beginPath();g.moveTo(0,0);g.bezierCurveTo(len*.3,-wid,len*.75,-wid*.9,len,0);g.bezierCurveTo(len*.75,wid*.9,len*.3,wid,0,0);g.fill();
g.strokeStyle=mix(col,”#ffffff”,.35);g.globalAlpha=.6;g.lineWidth=Math.max(1.5,wid*.06);g.beginPath();g.moveTo(len*.04,0);g.quadraticCurveTo(len*.5,-wid*.08,len*.96,0);g.stroke();
g.lineWidth=Math.max(1,wid*.03);for(let i=1;i<6;i++){const t=i/6;g.beginPath();g.moveTo(len*t,0);g.lineTo(len*(t+.1),-wid*.62*Math.sin(t*Math.PI));g.moveTo(len*t,0);g.lineTo(len*(t+.1),wid*.62*Math.sin(t*Math.PI));g.stroke()}g.restore()}
function flower(g,x,y,r,col,mid){g.save();g.translate(x,y);for(let k=0;k<2;k++){const n=k?6:9,rr=r*(k?.62:1);for(let i=0;i<n;i++){g.save();g.rotate(i/n*Math.PI*2+k*.3);const gr=g.createLinearGradient(0,0,0,-rr);gr.addColorStop(0,mix(col,"#000000",.25));gr.addColorStop(1,mix(col,"#ffffff",.25));g.fillStyle=gr;g.beginPath();g.ellipse(0,-rr*.55,rr*.28,rr*.55,0,0,7);g.fill();g.restore()}}
g.fillStyle=mid;g.beginPath();g.arc(0,0,r*.22,0,7);g.fill();g.fillStyle="rgba(0,0,0,.25)";for(let i=0;i<10;i++){const a=i*2.4,d=r*.12;g.beginPath();g.arc(Math.cos(a)*d,Math.sin(a)*d,r*.025,0,7);g.fill()}g.restore()}
function bristle(g,pts,w,col,R){g.strokeStyle=col;g.lineCap="round";g.globalAlpha=.92;g.lineWidth=w*.72;g.beginPath();g.moveTo(…pts[0]);g.bezierCurveTo(…pts[1],…pts[2],…pts[3]);g.stroke();
const n=Math.max(10,(w/3)|0);for(let i=0;i<n;i++){const off=(i/(n-1)-.5)*w;g.globalAlpha=.18+R()*.5;g.strokeStyle=R()<.25?mix(col,"#ffffff",.3):R()<.3?mix(col,"#000000",.3):col;g.lineWidth=1+R()*3.2;g.beginPath();g.moveTo(pts[0][0],pts[0][1]+off);g.bezierCurveTo(pts[1][0],pts[1][1]+off*(.8+R()*.4),pts[2][0],pts[2][1]+off*(.8+R()*.4),pts[3][0],pts[3][1]+off*.5);g.stroke()}g.globalAlpha=1}
const SKINS=[
{skin:"#5A3221",light:"#8A5638",dark:"#2E170E",hair:"#141012",lip:"#3F1A12",rim:"#F2C431"},
{skin:"#8A5A3C",light:"#B9845C",dark:"#4E2E1D",hair:"#1A1412",lip:"#5A2A1C",rim:"#7FD1E8"},
{skin:"#3E2318",light:"#6A4029",dark:"#1C0E08",hair:"#0B0909",lip:"#2E130C",rim:"#FF6A4D"}];
function profile(g,ox,oy,H,flip,p,opt={}){const gold=opt.gold||"#E2B23C";g.save();g.translate(ox,oy);g.scale(flip?-H:H,H);g.lineCap="round";g.lineJoin="round";
// garment + shoulders
if(opt.garment){g.fillStyle=opt.garment;g.beginPath();g.moveTo(-.42,1.05);g.bezierCurveTo(-.36,.92,-.18,.86,-.08,.86);g.lineTo(.16,.9);g.bezierCurveTo(.3,.92,.4,.98,.44,1.05);g.closePath();g.fill();
g.strokeStyle=mix(opt.garment,"#000000",.3);g.lineWidth=.008;for(let i=0;i<4;i++){g.beginPath();g.moveTo(-.25+i*.12,1.05);g.quadraticCurveTo(-.2+i*.12,.97,-.12+i*.1,.92);g.stroke()}}
const face=new Path2D();face.moveTo(.05,.12);face.bezierCurveTo(.13,.14,.16,.24,.165,.31);face.bezierCurveTo(.17,.34,.17,.36,.185,.40);face.lineTo(.235,.465);
face.bezierCurveTo(.242,.48,.222,.495,.196,.49);face.bezierCurveTo(.19,.51,.2,.525,.212,.545);face.bezierCurveTo(.2,.56,.19,.565,.185,.57);face.bezierCurveTo(.2,.585,.206,.6,.19,.615);
face.bezierCurveTo(.18,.63,.18,.645,.186,.66);face.bezierCurveTo(.19,.7,.16,.722,.11,.722);face.bezierCurveTo(.09,.74,.09,.8,.1,.88);face.lineTo(.16,.92);face.lineTo(-.1,.9);
face.bezierCurveTo(-.08,.8,-.07,.74,-.06,.7);face.bezierCurveTo(-.14,.6,-.12,.35,.05,.12);face.closePath();
g.save();g.shadowColor=p.rim;g.shadowBlur=18;g.fillStyle=p.skin;g.fill(face);g.restore();
g.save();g.clip(face);
let gr=g.createRadialGradient(.17,.32,.01,.12,.4,.38);gr.addColorStop(0,p.light);gr.addColorStop(1,"rgba(0,0,0,0)");g.fillStyle=gr;g.fillRect(-.3,0,.6,1);
gr=g.createLinearGradient(-.12,0,.1,0);gr.addColorStop(0,p.dark);gr.addColorStop(1,"rgba(0,0,0,0)");g.fillStyle=gr;g.fillRect(-.3,.3,.42,.7);
gr=g.createLinearGradient(0,.62,0,.8);gr.addColorStop(0,"rgba(0,0,0,0)");gr.addColorStop(1,p.dark);g.globalAlpha=.7;g.fillStyle=gr;g.fillRect(-.3,.62,.6,.3);g.globalAlpha=1;
gr=g.createRadialGradient(.125,.47,0,.125,.47,.07);gr.addColorStop(0,mix(p.light,"#ffffff",.25));gr.addColorStop(1,"rgba(255,255,255,0)");g.globalAlpha=.6;g.fillStyle=gr;g.fillRect(0,.35,.25,.25);g.globalAlpha=1;
g.strokeStyle=mix(p.light,"#ffffff",.35);g.globalAlpha=.55;g.lineWidth=.01;g.beginPath();g.moveTo(.172,.37);g.lineTo(.214,.448);g.stroke();g.beginPath();g.moveTo(.1,.17);g.quadraticCurveTo(.15,.22,.155,.29);g.stroke();g.globalAlpha=1;
g.fillStyle=p.lip;g.beginPath();g.moveTo(.19,.545);g.quadraticCurveTo(.205,.54,.212,.545);g.quadraticCurveTo(.2,.56,.185,.568);g.fill();g.beginPath();g.moveTo(.186,.572);g.quadraticCurveTo(.207,.588,.19,.613);g.quadraticCurveTo(.18,.6,.186,.572);g.fill();
g.fillStyle="rgba(255,255,255,.25)";g.beginPath();g.ellipse(.198,.592,.008,.004,0,0,7);g.fill();
g.strokeStyle=p.rim;g.lineWidth=.014;g.stroke(face);g.restore();
// hair
const hair=new Path2D();hair.moveTo(.085,.15);hair.bezierCurveTo(.11,-.08,-.22,-.12,-.36,.1);hair.bezierCurveTo(-.47,.32,-.36,.6,-.07,.63);hair.bezierCurveTo(-.03,.5,-.02,.3,.085,.15);
gr=g.createRadialGradient(-.05,.05,.02,-.15,.25,.4);gr.addColorStop(0,mix(p.hair,"#ffffff",.12));gr.addColorStop(1,p.hair);g.fillStyle=gr;g.fill(hair);
g.save();g.clip(hair);const hr=mulberry(5);g.lineWidth=.0045;for(let i=0;i<900;i++){const cx=-.45+hr()*.6,cy=-.1+hr()*.75;g.strokeStyle=hr()<.6?"rgba(255,255,255,.07)":"rgba(0,0,0,.35)";g.beginPath();g.arc(cx,cy,.006+hr()*.007,hr()*6,hr()*6+3.6);g.stroke()}
g.strokeStyle=p.rim;g.globalAlpha=.7;g.lineWidth=.012;g.stroke(hair);g.restore();g.globalAlpha=1;
if(opt.flowers){flower(g,-.33,.2,.075,opt.flowers[0],"#F2C431");flower(g,-.22,.06,.055,opt.flowers[1],"#F2C431");flower(g,-.38,.36,.05,opt.flowers[0],"#F2C431")}
// ear, earring, brow, eye
g.fillStyle=p.skin;g.beginPath();g.ellipse(-.03,.45,.036,.058,-.1,0,7);g.fill();g.fillStyle=p.dark;g.globalAlpha=.6;g.beginPath();g.ellipse(-.026,.452,.018,.034,-.1,0,7);g.fill();g.globalAlpha=1;
gr=g.createLinearGradient(-.08,.5,.02,.6);gr.addColorStop(0,"#FFF1B8");gr.addColorStop(.5,gold);gr.addColorStop(1,"#8A6416");g.strokeStyle=gr;g.lineWidth=.014;g.beginPath();g.arc(-.03,.548,.046,0,7);g.stroke();
g.strokeStyle=p.hair;g.lineWidth=.011;g.beginPath();g.moveTo(.112,.346);g.quadraticCurveTo(.14,.334,.164,.346);g.stroke();
g.strokeStyle=p.dark;g.lineWidth=.008;g.beginPath();g.moveTo(.108,.382);g.quadraticCurveTo(.132,.4,.156,.384);g.stroke();
for(let i=0;i<5;i++){g.beginPath();const lx=.11+i*.011;g.moveTo(lx,.391);g.lineTo(lx-.005,.407);g.stroke()}
g.restore()}
function figure(g,x,y,h,dress,wrap="#E9C46A"){g.save();g.translate(x,y);g.scale(h,h);g.lineCap="round";
g.fillStyle="rgba(0,0,0,.18)";g.beginPath();g.ellipse(.36,.99,.5,.022,0,0,7);g.fill();
g.fillStyle="#3A2218";g.beginPath();g.moveTo(-.04,.86);g.lineTo(-.075,.99);g.lineTo(-.035,.99);g.lineTo(-.005,.86);g.fill();g.beginPath();g.moveTo(.04,.86);g.lineTo(.1,.98);g.lineTo(.145,.98);g.lineTo(.07,.86);g.fill();
const d=new Path2D();d.moveTo(-.035,.25);d.bezierCurveTo(-.07,.42,-.15,.7,-.2,.89);d.quadraticCurveTo(.02,.93,.23,.87);d.bezierCurveTo(.17,.66,.09,.4,.045,.25);d.closePath();
let gr=g.createLinearGradient(-.2,0,.23,0);gr.addColorStop(0,mix(dress,"#000000",.35));gr.addColorStop(.45,dress);gr.addColorStop(.7,mix(dress,"#ffffff",.15));gr.addColorStop(1,mix(dress,"#000000",.25));g.fillStyle=gr;g.fill(d);
g.save();g.clip(d);g.strokeStyle=mix(dress,"#000000",.35);g.lineWidth=.012;for(let i=0;i<5;i++){g.beginPath();g.moveTo(.0+i*.01,.32);g.quadraticCurveTo(-.06+i*.06,.62,-.14+i*.08,.92);g.stroke()}
g.strokeStyle=mix(dress,"#ffffff",.25);g.lineWidth=.006;for(let i=0;iMath.max(0,1-u*1.6)*(.4+v*.6));
let gr=g.createRadialGradient(x+w*.36,y+h*.42,h*.05,x+w*.36,y+h*.46,h*.42);gr.addColorStop(0,mix(b2,”#ffffff”,.3));gr.addColorStop(1,b2);g.fillStyle=gr;g.beginPath();g.arc(x+w*.36,y+h*.46,h*.42,0,7);g.fill();
g.strokeStyle=mix(b2,”#ffffff”,.4);g.lineWidth=2;g.beginPath();g.arc(x+w*.36,y+h*.46,h*.47,0,7);g.stroke();
for(let i=0;iMath.max(0,v-.55)*1.6);
profile(g,x+w*.33,y+h*.04,h*.98,false,p,{garment:lf,flowers:[b2,”#F4EFE6″]});
if(win){const{x:X,y:Y,w:W,h:Hh}=win;g.fillStyle=b1;g.fillRect(X,Y,W,Hh);halftone(g,X,Y,W,Hh,mix(b1,”#000000″,.35),11,(u,v)=>.3+.7*v);
gr=g.createRadialGradient(X+W*.5,Y+Hh*.1,10,X+W*.5,Y+Hh*.1,Hh*.6);gr.addColorStop(0,mix(b2,”#ffffff”,.3));gr.addColorStop(1,b2);g.fillStyle=gr;g.beginPath();g.arc(X+W*.5,Y+Hh*.05,Hh*.5,0,Math.PI);g.fill();
for(let i=0;iu*.9);halftone(g,x+w*.5,y,w*.5,h,”#A23624″,10,(u,v)=>(1-u)*.9);
let gr=g.createRadialGradient(x+w*.5,y+h*.46,4,x+w*.5,y+h*.5,h*.3);gr.addColorStop(0,”#FFE7A1″);gr.addColorStop(1,”#F2B42A”);g.fillStyle=gr;g.beginPath();g.arc(x+w*.5,y+h*.5,h*.28,0,7);g.fill();
profile(g,x+w*.29,y+h*.04,h*.98,false,a,{garment:”#2E7D5B”});profile(g,x+w*.71,y+h*.04,h*.98,true,b,{garment:”#F2B6C6″});
if(win){const{x:X,y:Y,w:W,h:Hh}=win;gr=g.createLinearGradient(0,Y,0,Y+Hh);gr.addColorStop(0,”#1F2F6B”);gr.addColorStop(1,”#0F1838″);g.fillStyle=gr;g.fillRect(X,Y,W,Hh);
for(let i=0;iv*.8);
gr=g.createRadialGradient(x+w*.72,y+h*.38,10,x+w*.72,y+h*.42,h*.32);gr.addColorStop(0,”#2A2A2C”);gr.addColorStop(1,”#121214″);g.fillStyle=gr;g.beginPath();g.arc(x+w*.72,y+h*.42,h*.32,0,7);g.fill();
g.fillStyle=”#C8302A”;g.beginPath();g.arc(x+w*.72,y+h*.42,h*.32,Math.PI*.15,Math.PI*1.15);g.fill();
g.strokeStyle=”#1B1B1D”;g.lineWidth=2;g.beginPath();g.moveTo(x+w*.06,y+h*.88);g.lineTo(x+w*.94,y+h*.88);g.stroke();
figure(g,x+w*.24,y+h*.04,h*.86,”#C8302A”,”#E9C46A”);figure(g,x+w*.38,y+h*.16,h*.74,”#A8261F”,”#F4EFE6″);figure(g,x+w*.5,y+h*.26,h*.64,”#D84A33″,”#1B1B1D”);
if(win){const{x:X,y:Y,w:W,h:Hh}=win;for(let i=0;i.5+.5*Math.sin(u*6+v*3));
bristle(g,[[x-30,y+h*.78],[x+w*.3,y-h*.15],[x+w*.55,y+h*1.15],[x+w*.88,y+h*.2]],h*.3,c3,R);
bristle(g,[[x+w*.08,y+h*.12],[x+w*.4,y+h*.62],[x+w*.62,y-h*.2],[x+w+30,y+h*.66]],h*.2,c1,R);
bristle(g,[[x+w*.18,y+h*.98],[x+w*.36,y+h*.28],[x+w*.68,y+h*.92],[x+w*.92,y+h*.08]],h*.12,c2,R);
g.fillStyle=c3;for(let i=0;i<180;i++){g.globalAlpha=.55;g.beginPath();g.arc(x+R()*w,y+R()*h,R()*3.5,0,7);g.fill()}g.globalAlpha=1;
g.fillStyle=c1;for(let i=0;i<8;i++){const dx=x+w*(.2+R()*.6);g.fillRect(dx,y+h*(.5+R()*.3),3,40+R()*70)}
if(win){const{x:X,y:Y,w:W,h:Hh}=win;g.fillStyle=bg;g.fillRect(X,Y,W,Hh);bristle(g,[[X-20,Y+Hh*.2],[X+W*.3,Y+Hh*.9],[X+W*.6,Y-Hh*.1],[X+W+20,Y+Hh*.7]],Hh*.26,c1,R);
bristle(g,[[X+W*.1,Y+Hh*.95],[X+W*.4,Y+Hh*.3],[X+W*.7,Y+Hh*1.05],[X+W*.95,Y+Hh*.25]],Hh*.14,c3,R);g.fillStyle=c2;for(let i=0;i{c.fillStyle=”#EFE8DA”;c.fillRect(0,0,w,h);figure(c,w*.5,h*.06,h*.5,”#C8302A”);c.fillStyle=”#121314″;c.textAlign=”left”;const sz=fitText(c,”WOMAN IN RED”,s=>`900 ${s}px ${F.st}`,w*.84);c.fillText(“WOMAN IN RED”,w*.08,h*.7);
c.font=`italic ${w*.11}px ${F.se}`;c.fillText(“new works on paper”,w*.08,h*.8);c.font=`500 ${w*.052}px ${F.mo}`;c.fillText(“FILTHY · 35S13ST · FALL 2026″,w*.08,h*.92)},
face:(c,w,h)=>{c.fillStyle=”#0E4E5A”;c.fillRect(0,0,w,h);c.fillStyle=”#E7643C”;c.beginPath();c.arc(w*.48,h*.33,w*.34,0,7);c.fill();profile(c,w*.48,h*.02,h*.58,false,SKINS[0]);
c.fillStyle=”#F2E6D3″;c.fillRect(0,h*.62,w,h*.38);c.fillStyle=”#121314″;c.textAlign=”left”;c.font=`italic ${w*.2}px ${F.se}`;c.fillText(“Portraits”,w*.08,h*.78);c.font=`500 ${w*.052}px ${F.mo}`;c.fillText(“35S13ST · MURAL SERIES”,w*.08,h*.91)},
studio:(c,w,h)=>{c.fillStyle=”#F4F3EF”;c.fillRect(0,0,w,h);c.fillStyle=”#121314″;c.textAlign=”left”;const sz=fitText(c,”STUDIO”,s=>`900 ${s}px ${F.st}`,w*.84);c.fillText(“OPEN”,w*.08,h*.32);c.fillText(“STUDIO”,w*.08,h*.32+sz*.86);
c.fillRect(w*.08,h*.66,w*.84,3);c.font=`italic ${w*.12}px ${F.se}`;c.fillText(“by appointment”,w*.08,h*.79);c.font=`500 ${w*.052}px ${F.mo}`;c.fillText(“35 S. 13TH ST · PHILADELPHIA”,w*.08,h*.91)},
opencall:(c,w,h)=>{c.fillStyle=”#121314″;c.fillRect(0,0,w,h);c.fillStyle=”#F2C431″;c.textAlign=”left”;const sz=fitText(c,”OPEN”,s=>`900 ${s}px ${F.st}`,w*.84);c.fillText(“OPEN”,w*.08,h*.3);c.fillText(“CALL”,w*.08,h*.3+sz*.9);
c.strokeStyle=”#F2C431″;c.lineWidth=2;c.font=`900 ${w*.32}px ${F.st}`;c.strokeText(“2027″,w*.08,h*.82);c.fillStyle=”#F4F3EF”;c.font=`italic ${w*.1}px ${F.se}`;c.fillText(“paid commissions”,w*.08,h*.92)},
tv:(c,w,h)=>{c.fillStyle=”#24399E”;c.fillRect(0,0,w,h);c.fillStyle=”#F4F3EF”;c.textAlign=”left”;fitText(c,”35S13ST”,s=>`900 ${s}px ${F.st}`,w*.84);c.fillText(“35S13ST”,w*.08,h*.3);
c.font=`italic ${w*.15}px ${F.se}`;c.fillText(“now showing”,w*.08,h*.48);c.strokeStyle=”#F4F3EF”;c.lineWidth=3;c.strokeRect(w*.08,h*.56,w*.84,h*.26);c.fillStyle=”#F2C431″;c.beginPath();c.moveTo(w*.44,h*.62);c.lineTo(w*.58,h*.69);c.lineTo(w*.44,h*.76);c.fill();
c.fillStyle=”#F4F3EF”;c.font=`500 ${w*.055}px ${F.mo}`;c.fillText(“DROP THE WINDOW →”,w*.08,h*.92)}
};
function poster(g,R,x,y,w,h,rot,key){const t=cv(w+20,h+20),c=t.getContext(“2d”);c.translate(10,10);
c.beginPath();c.moveTo(0,0);for(let i=1;i<=10;i++)c.lineTo(w*i/10,(R()-.5)*4);for(let i=1;i=0;i–)c.lineTo(w*i/10,h+(R()-.5)*(R()<.3?14:4));c.closePath();c.save();c.clip();
POSTERS[key](c,w,h);
c.globalCompositeOperation="multiply";c.globalAlpha=.45;c.fillStyle=c.createPattern(T.grain,"repeat");c.fillRect(0,0,w,h);c.globalAlpha=1;
c.strokeStyle="rgba(90,80,60,.25)";c.lineWidth=1;for(let i=0;i<9;i++){c.beginPath();const sx=R()*w;c.moveTo(sx,0);c.bezierCurveTo(sx+(R()-.5)*40,h*.3,sx+(R()-.5)*40,h*.7,sx+(R()-.5)*30,h);c.stroke()}
c.globalCompositeOperation="screen";const gl=c.createLinearGradient(0,0,w,h);gl.addColorStop(0,"rgba(255,255,255,.12)");gl.addColorStop(.5,"rgba(255,255,255,0)");gl.addColorStop(1,"rgba(255,255,255,.06)");c.fillStyle=gl;c.fillRect(0,0,w,h);
c.restore();
if(R()<.3){c.globalCompositeOperation="destination-out";c.beginPath();const tx=R()*w*.6;c.moveTo(tx,h+4);c.lineTo(tx+w*.1,h*.84);c.lineTo(tx+w*.22,h*.91);c.lineTo(tx+w*.36,h+4);c.fill();c.globalCompositeOperation="source-over"}
g.save();g.translate(x,y);g.rotate(rot);g.shadowColor="rgba(0,0,0,.45)";g.shadowBlur=3;g.shadowOffsetY=1;g.drawImage(t,-10,-10);g.restore()}
let muralShot=null;
const WALLSEQ=["nero","advertise","portrait","pair","red","gesture"];
const WALL_LABEL={nero:"Nero One · live install Tue 10.13",advertise:"Advertise here",portrait:"Mural · Portrait",pair:"Mural · Two Faces",red:"Mural · Woman in Red",gesture:"Mural · Gesture"};
const TRANSOM={x:247,y:507,w:1001,h:398},WIN={x:247,y:970,w:678,h:478};
function grime(g,x,y,w,h,seed,n=3500){g.save();g.globalCompositeOperation="destination-out";const wr=mulberry(seed);for(let i=0;i<n;i++){g.fillStyle=`rgba(0,0,0,${.2+wr()*.5})`;g.fillRect(x+wr()*w,y+wr()*h,1+wr()*1.8,1+wr()*1.8)}g.restore()}
function paintTexture(g,r,sx,sy){g.save();g.globalCompositeOperation="multiply";g.globalAlpha=.24;g.drawImage(T.black,sx,sy,r.w,r.h,r.x,r.y,r.w,r.h);g.restore()}
/* — Nero One tribute wall: bold, high-contrast black-and-white stencil — */
function sprayHalo(g,x,y,r,col,a=.55){const gr=g.createRadialGradient(x,y,r*.15,x,y,r);gr.addColorStop(0,col);gr.addColorStop(.7,col);gr.addColorStop(1,"rgba(0,0,0,0)");g.save();g.globalAlpha=a;g.fillStyle=gr;g.beginPath();g.arc(x,y,r,0,7);g.fill();
const R=mulberry(r|0);g.fillStyle=col;for(let i=0;i{g.beginPath();g.arc(.02,.08,.064,0,7);g.fill();
g.beginPath();g.moveTo(-.105,.19);g.quadraticCurveTo(.0,.15,.115,.18);g.lineTo(.09,.5);g.lineTo(-.075,.5);g.closePath();g.fill();
g.beginPath();g.moveTo(-.09,.48);g.lineTo(.1,.48);g.lineTo(.145,.69);g.lineTo(.02,.69);g.lineTo(.0,.6);g.lineTo(-.02,.69);g.lineTo(-.14,.69);g.closePath();g.fill();
const limb=(pts,w)=>{g.lineWidth=w;g.beginPath();g.moveTo(…pts[0]);for(let i=1;i<pts.length;i++)g.lineTo(…pts[i]);g.stroke()};
limb([[.1,.21],[.16,.07],[.13,-.1]],.05);limb([[-.085,.21],[-.13,.07],[.05,-.13]],.046);
limb([[-.07,.66],[-.1,.81],[-.065,.97]],.075);limb([[.08,.66],[.12,.8],[.15,.95]],.072);
g.beginPath();g.ellipse(-.045,.985,.06,.022,0,0,7);g.fill();g.beginPath();g.ellipse(.175,.96,.058,.022,.3,0,7);g.fill();
g.lineWidth=.03;g.beginPath();g.moveTo(.02,.14);g.lineTo(.02,.18);g.stroke()};
// overspray first, then the crisp cut
g.save();g.shadowColor=ink;g.shadowBlur=14/H*H;g.fillStyle=ink;g.strokeStyle=ink;g.globalAlpha=.35;g.filter="blur(3px)";body();g.restore();
g.fillStyle=ink;g.strokeStyle=ink;body();
// ball
g.fillStyle=ink;g.beginPath();g.arc(.105,-.19,.07,0,7);g.fill();
// stencil cuts (white highlights / bridges)
g.strokeStyle=cut;g.lineWidth=.009;g.beginPath();g.arc(.105,-.19,.07,0,7);g.stroke();
g.beginPath();g.moveTo(.035,-.19);g.lineTo(.175,-.19);g.moveTo(.105,-.26);g.lineTo(.105,-.12);g.stroke();
g.beginPath();g.arc(.05,-.19,.05,-1,1);g.stroke();g.beginPath();g.arc(.16,-.19,.05,Math.PI-1,Math.PI+1);g.stroke();
g.lineWidth=.012;g.beginPath();g.moveTo(-.085,.205);g.quadraticCurveTo(-.03,.3,-.055,.48);g.moveTo(.1,.2);g.quadraticCurveTo(.06,.3,.075,.48);g.stroke();
g.lineWidth=.016;g.beginPath();g.moveTo(-.13,.66);g.lineTo(-.02,.66);g.moveTo(.02,.66);g.lineTo(.135,.66);g.stroke();
g.lineWidth=.008;g.beginPath();g.arc(.045,.075,.05,-.9,.7);g.stroke();
g.lineWidth=.01;g.beginPath();g.moveTo(.14,.08);g.lineTo(.135,-.06);g.moveTo(-.1,.72);g.lineTo(-.095,.8);g.stroke();
g.fillStyle=cut;g.font=`900 .14px ${F.st}`;g.textAlign="center";g.fillText("13",.01,.38);
g.restore()}
function neroTransom(g,r){const{x,y,w,h}=r;
let gr=g.createLinearGradient(0,y,0,y+h);gr.addColorStop(0,"#EEEBE3");gr.addColorStop(1,"#E2DDD1");g.fillStyle=gr;g.fillRect(x,y,w,h);
const R=mulberry(1313);g.fillStyle="rgba(20,20,22,.05)";for(let i=0;i`900 ${s}px ${F.st}`,w*.36);if(sz>h*.27){sz=h*.27;g.font=`900 ${sz}px ${F.st}`}
g.fillText(“YOU”,x+w*.045,y+h*.08+sz*.82);g.fillText(“BELONG”,x+w*.045,y+h*.08+sz*1.66);g.fillText(“HERE.”,x+w*.045,y+h*.08+sz*2.5);
g.fillRect(x+w*.048,y+h*.86,w*.33,3);
g.font=`500 14px ${F.mo}`;g.fillText(“NERO ONE × 35S13ST · LIVE INSTALL TUE 10.13”,x+w*.048,y+h*.94);
g.save();g.translate(x+w*.6,y+h*.88);g.rotate(-.08);g.font=`64px “Sedgwick Ave Display”,”Permanent Marker”,cursive`;g.fillStyle=”#E11D2E”;g.fillText(“Nero”,0,0);g.font=`500 13px ${F.mo}`;g.fillStyle=”#0E0E10″;g.fillText(“@NERO_ONE”,8,22);g.restore();
}
function neroWindow(g,r){const{x,y,w,h}=r;g.fillStyle=”#0F1011″;g.fillRect(x,y,w,h);
const R=mulberry(77);g.fillStyle=”rgba(255,255,255,.04)”;for(let i=0;i`900 ${s}px ${F.st}`,w*.52);g.fillText(“NERO ONE”,x+w*.06,y+h*.38);
g.font=`italic ${h*.11}px ${F.se}`;g.fillText(“live on this wall”,x+w*.065,y+h*.55);
g.fillRect(x+w*.065,y+h*.62,w*.46,2);g.font=`500 15px ${F.mo}`;g.fillText(“TUESDAY 10.13 · 35 S. 13TH ST”,x+w*.065,y+h*.7);g.fillText(“THE SIXERS SEASON, IN STENCIL”,x+w*.065,y+h*.76);
g.fillStyle=”#E11D2E”;g.fillText(“TAP THE WALL ABOVE FOR THE STORY ↑”,x+w*.065,y+h*.88)}
/* — Advertise Here wall — */
function advTransom(g,r){const{x,y,w,h}=r;g.save();g.shadowColor=”rgba(0,0,0,.5)”;g.shadowBlur=14;g.shadowOffsetY=6;g.fillStyle=”#F4F3EF”;g.fillRect(x+18,y+16,w-36,h-32);g.restore();
const R=mulberry(404);g.fillStyle=”rgba(0,0,0,.035)”;for(let i=0;i`900 ${s}px ${F.st}`,w*.6);g.fillText(“ADVERTISE”,x+w*.06,y+h*.52);
g.font=`italic ${sz*.62}px ${F.se}`;g.fillText(“here.”,x+w*.67,y+h*.52);
g.fillRect(x+w*.06,y+h*.63,w*.86,3);g.font=`500 18px ${F.mo}`;g.fillText(“THIS WALL · 35 S. 13TH ST · CENTER CITY PHILADELPHIA”,x+w*.06,y+h*.74);g.fillText(“DM @35S13ST”,x+w*.06,y+h*.84);
g.fillStyle=”#8a8d8f”;[[x+34,y+32],[x+w-34,y+32],[x+34,y+h-32],[x+w-34,y+h-32]].forEach(([a,b])=>{g.beginPath();g.arc(a,b,6,0,7);g.fill()})}
function advWindow(g,r){const{x,y,w,h}=r;g.fillStyle=”#0F1011″;g.fillRect(x,y,w,h);
g.fillStyle=”#F4F3EF”;g.textAlign=”left”;g.textBaseline=”alphabetic”;g.font=`italic ${h*.16}px ${F.se}`;g.fillText(“Your work”,x+w*.07,y+h*.3);g.fillText(“on this wall.”,x+w*.07,y+h*.46);
g.fillRect(x+w*.07,y+h*.55,w*.6,2);g.font=`500 15px ${F.mo}`;g.fillText(“MURALS · WHEATPASTE · BRAND TAKEOVERS”,x+w*.07,y+h*.64);g.fillText(“RATES ON REQUEST · DM @35S13ST”,x+w*.07,y+h*.71)}
/* — coming soon signs (door + shop) — */
function soonSign(g,x,y,w,h,top,rot){g.save();g.translate(x,y);g.rotate(rot);g.shadowColor=”rgba(0,0,0,.55)”;g.shadowBlur=10;g.shadowOffsetX=3;g.shadowOffsetY=6;g.fillStyle=”#F4F3EF”;g.fillRect(0,0,w,h);g.shadowColor=”transparent”;
const gg=g.createLinearGradient(0,0,w,h);gg.addColorStop(0,”rgba(255,255,255,.3)”);gg.addColorStop(1,”rgba(0,0,0,.07)”);g.fillStyle=gg;g.fillRect(0,0,w,h);
g.fillStyle=”#121314″;g.textAlign=”left”;g.textBaseline=”alphabetic”;g.font=`500 ${w*.062}px ${F.mo}`;g.fillText(top,w*.09,h*.2);
const sz=fitText(g,”COMING”,s=>`900 ${s}px ${F.st}`,w*.82);g.fillText(“COMING”,w*.09,h*.2+sz*.92);g.font=`italic ${sz*.72}px ${F.se}`;g.fillText(“soon.”,w*.09,h*.2+sz*1.58);
g.fillStyle=”rgba(232,226,200,.75)”;[[-12,-8,.5],[w-48,-10,-.45]].forEach(([tx,ty,tr])=>{g.save();g.translate(tx+30,ty+10);g.rotate(tr);g.fillRect(-30,-9,60,18);g.restore()});
g.restore()}
function graffiti(idx){muralShot=null;const key=WALLSEQ[((idx%WALLSEQ.length)+WALLSEQ.length)%WALLSEQ.length];
const R=mulberry(idx*7919+11),G=cv(W,H),g=G.getContext(“2d”);
g.save();g.beginPath();g.rect(TRANSOM.x,TRANSOM.y,TRANSOM.w,TRANSOM.h);g.rect(WIN.x,WIN.y,WIN.w,WIN.h);g.clip();
if(key===”nero”){neroTransom(g,TRANSOM);neroWindow(g,WIN)}
else if(key===”advertise”){g.restore();g.save();g.beginPath();g.rect(TRANSOM.x,TRANSOM.y,TRANSOM.w,TRANSOM.h);g.rect(WIN.x,WIN.y,WIN.w,WIN.h);g.clip();advTransom(g,TRANSOM);advWindow(g,WIN)}
else{MURALS[key](g,TRANSOM.x,TRANSOM.y,TRANSOM.w,TRANSOM.h,R,WIN);g.fillStyle=”rgba(244,243,239,.85)”;g.font=`500 13px ${F.mo}`;g.textAlign=”right”;g.shadowColor=”rgba(0,0,0,.5)”;g.shadowBlur=3;g.fillText(“35S13ST · 2026”,1236,894);g.fillText(“35S13ST · 2026″,913,1438);g.shadowBlur=0}
g.restore();
paintTexture(g,TRANSOM,135,67);paintTexture(g,WIN,135,530);
if(key!==”advertise”)grime(g,TRANSOM.x,TRANSOM.y,TRANSOM.w,TRANSOM.h,idx+9,key===”nero”?2200:3200);
// coming soon: one on the door, one for the shop
soonSign(g,1020,1000,190,150,”35S13ST · THE GALLERY”,-.025);
soonSign(g,300,1560,280,210,”THE SHOP”,.02);
muralShot=cv(1001,398);muralShot.getContext(“2d”).drawImage(G,247,507,1001,398,0,0,1001,398);
return{G,name:WALL_LABEL[key],key,clean:key===”advertise”};
}
function adSign(g,x,y,rot){const w=300,h=180;g.save();g.translate(x,y);g.rotate(rot);
g.shadowColor=”rgba(0,0,0,.6)”;g.shadowBlur=12;g.shadowOffsetX=4;g.shadowOffsetY=7;g.fillStyle=”#F4F3EF”;g.fillRect(0,0,w,h);g.shadowColor=”transparent”;
const gg=g.createLinearGradient(0,0,w,h);gg.addColorStop(0,”rgba(255,255,255,.35)”);gg.addColorStop(.5,”rgba(255,255,255,0)”);gg.addColorStop(1,”rgba(0,0,0,.07)”);g.fillStyle=gg;g.fillRect(0,0,w,h);
g.strokeStyle=”rgba(0,0,0,.05)”;g.lineWidth=1;for(let i=6;i{g.beginPath();g.arc(a,b,4,0,7);g.fill()});
g.restore()}
function drawNote(ctx,text){ctx.save();ctx.translate(46,1236);ctx.rotate(-.025);ctx.shadowColor=”rgba(0,0,0,.55)”;ctx.shadowBlur=7;ctx.shadowOffsetY=3;ctx.fillStyle=”#F0E01E”;ctx.fillRect(-38,-42,76,84);ctx.shadowColor=”transparent”;
const gg=ctx.createLinearGradient(0,-42,0,42);gg.addColorStop(0,”rgba(255,255,255,.18)”);gg.addColorStop(1,”rgba(0,0,0,.06)”);ctx.fillStyle=gg;ctx.fillRect(-38,-42,76,84);
ctx.fillStyle=”rgba(0,0,0,.08)”;ctx.fillRect(-38,-42,76,10);
if(text){ctx.fillStyle=”#1d1c10″;ctx.font=’15px “Permanent Marker”, cursive’;ctx.textAlign=”center”;text.forEach((l,i)=>ctx.fillText(l,0,-20+i*17))}
else{ctx.strokeStyle=”rgba(50,48,12,.75)”;ctx.lineWidth=1.2;for(let i=0;i<7;i++){ctx.beginPath();ctx.moveTo(-30,-26+i*10);for(let k=0;k<6;k++)ctx.quadraticCurveTo(-26+k*10,-29+i*10+(k%2?3:-2),-22+k*10,-26+i*10);ctx.stroke()}}
ctx.restore()}
/* ———- interior behind openings ———- */
function paintBack(ctx,artImgs){
ctx.clearRect(0,0,W,H);
// doorway: white gallery glimpse
let g=ctx.createLinearGradient(950,0,1240,0);g.addColorStop(0,"#d9d8d3");g.addColorStop(.25,"#f6f5f1");g.addColorStop(.8,"#f8f7f3");g.addColorStop(1,"#d3d2cd");ctx.fillStyle=g;ctx.fillRect(950,946,290,966);
g=ctx.createLinearGradient(0,946,0,1080);g.addColorStop(0,"#e3e2dd");g.addColorStop(1,"rgba(243,242,238,0)");ctx.fillStyle=g;ctx.fillRect(950,946,290,140);
g=ctx.createLinearGradient(0,1640,0,1912);g.addColorStop(0,"#c3c1bb");g.addColorStop(1,"#9f9d97");ctx.fillStyle=g;ctx.fillRect(950,1640,290,272);
ctx.fillStyle="#d0cec8";ctx.fillRect(950,1638,290,3);
if(artImgs[0]){ctx.save();ctx.shadowColor="rgba(0,0,0,.35)";ctx.shadowBlur=14;ctx.shadowOffsetX=5;ctx.shadowOffsetY=9;ctx.fillStyle="#151617";ctx.fillRect(1030,1240,130,170);ctx.restore();ctx.fillStyle="#fff";ctx.fillRect(1035,1245,120,160);ctx.drawImage(artImgs[0],1044,1254,102,142)}
g=ctx.createRadialGradient(1095,1180,10,1095,1180,220);g.addColorStop(0,"rgba(255,252,240,.6)");g.addColorStop(1,"rgba(255,252,240,0)");ctx.fillStyle=g;ctx.fillRect(950,946,290,600);
// window niche
ctx.fillStyle="#0a0b0c";ctx.fillRect(247,970,678,478);
ctx.fillStyle="#16181a";ctx.beginPath();ctx.moveTo(247,970);ctx.lineTo(925,970);ctx.lineTo(885,1010);ctx.lineTo(287,1010);ctx.fill();
ctx.fillStyle="#121315";ctx.beginPath();ctx.moveTo(247,970);ctx.lineTo(287,1010);ctx.lineTo(287,1408);ctx.lineTo(247,1448);ctx.fill();ctx.beginPath();ctx.moveTo(925,970);ctx.lineTo(885,1010);ctx.lineTo(885,1408);ctx.lineTo(925,1448);ctx.fill();
ctx.fillStyle="#1c1e20";ctx.beginPath();ctx.moveTo(247,1448);ctx.lineTo(287,1408);ctx.lineTo(885,1408);ctx.lineTo(925,1448);ctx.fill();
g=ctx.createRadialGradient(586,1198,40,586,1198,380);g.addColorStop(0,"rgba(120,160,230,.35)");g.addColorStop(1,"rgba(120,160,230,0)");ctx.fillStyle=g;ctx.fillRect(247,970,678,478);
// TV bezel + mount
ctx.fillStyle="#2a2c2e";ctx.fillRect(580,1336,12,40);ctx.fillRect(520,1372,132,10);
ctx.save();ctx.shadowColor="rgba(0,0,0,.8)";ctx.shadowBlur=20;ctx.shadowOffsetY=8;ctx.fillStyle="#050506";rr(343,1058,486,280,6,ctx);ctx.fill();ctx.restore();
ctx.strokeStyle="#2f3234";ctx.lineWidth=1.5;rr(343,1058,486,280,6,ctx);ctx.stroke();
}
/* ———- TV loop ———- */
const PIECES=[
{id:"p1",t:"Woman in Red I",a:"filthy",s:"9 × 12 in",m:"Paint and marker on cotton paper",p:185,seed:3,pal:["#C8302A","#F1E6D6","#1B1B1D","#EDB915"],fig:1},
{id:"p2",t:"Woman in Red II",a:"filthy",s:"9 × 12 in",m:"Paint and marker on cotton paper",p:125,seed:7,pal:["#C8302A","#E9E2D3","#1B1B1D","#2944C4"],fig:1},
{id:"p4",t:"Broad St Blue",a:"Dom",s:"18 × 24 in",m:"Acrylic and spray on panel",p:650,seed:19,pal:["#2944C4","#D8DAD5","#141619","#F2A33A"],fig:0},
{id:"p6",t:"Sunday Corner",a:"Cameron",s:"16 × 20 in",m:"Oil on canvas",p:480,seed:29,pal:["#7A4FB0","#F2E9DC","#2A1F17","#EDB915"],fig:1}
];
function artSVG(pc){
const r=mulberry(pc.seed*97),[c1,c2,c3,c4]=pc.pal;let s=“;
for(let i=0;i<5;i++)s+=“;
if(pc.fig){const x=30+r()*30;s+=“}
else s+=“;
for(let i=0;i<3;i++){const x=10+r()*70,y=20+r()*50;s+=“}
return s+“;
}
const imgs=PIECES.map(p=>{const im=new Image();im.src=”data:image/svg+xml;charset=utf-8,”+encodeURIComponent(artSVG(p));return im});
const tv=$(“#tv”),tc=tv.getContext(“2d”);let tvOn=false,tv2c=null;
let neroShot=null;
function makeNeroShot(){const c=cv(1001,398),g=c.getContext(“2d”);neroTransom(g,{x:0,y:0,w:1001,h:398});return c}
function drawTV(ts){
const w=470,h=264,slide=Math.floor(ts/4200),k=(ts%4200)/4200;const i=slide%3;
tc.fillStyle=”#000″;tc.fillRect(0,0,w,h);
if(i===0){tc.fillStyle=”#121314″;tc.fillRect(0,0,w,h);tc.fillStyle=”#F2F0EA”;tc.textAlign=”left”;tc.font=’900 92px “Big Shoulders Stencil Display”, Impact’;tc.fillText(“COMING”,24,124);tc.font=’italic 54px “Instrument Serif”, Georgia’;tc.fillText(“soon.”,26,176);
tc.fillStyle=”rgba(242,240,234,.7)”;tc.font=’500 12px “DM Mono”, monospace’;tc.fillText(“35S13ST · GALLERY + SHOP · @35S13ST”,26,214)}
else if(i===1&&neroShot){const z=reduce?1:1.1+k*.08,mw=w*z*1.15,mh=mw*398/1001;tc.drawImage(neroShot,(w-mw)/2-(reduce?0:k*30-15),(h-mh)/2-10,mw,mh);tc.fillStyle=”rgba(0,0,0,.6)”;tc.fillRect(0,h-48,w,48);tc.fillStyle=”#fff”;tc.textAlign=”left”;tc.font=’italic 22px “Instrument Serif”, Georgia’;tc.fillText(“Nero One, live”,20,h-18);tc.font=’500 11px “DM Mono”, monospace’;tc.fillText(“TUE 10.13 · @NERO_ONE”,250,h-20)}
else if(muralShot){const z=reduce?1:1.12+k*.1,mw=w*z*1.4,mh=mw*398/1001;tc.drawImage(muralShot,(w-mw)/2-(reduce?0:k*60-30),(h-mh)/2,mw,mh);tc.fillStyle=”rgba(0,0,0,.55)”;tc.fillRect(0,h-48,w,48);tc.fillStyle=”#fff”;tc.textAlign=”left”;tc.font=’italic 22px “Instrument Serif”, Georgia’;tc.fillText(“On the wall today”,20,h-18);tc.font=’500 11px “DM Mono”, monospace’;tc.fillText(current?current.name.toUpperCase().slice(0,30):””,230,h-20)}
tc.fillStyle=”rgba(0,0,0,.45)”;tc.fillRect(12,12,104,22);tc.fillStyle=”#ff3b30″;tc.beginPath();tc.arc(24,23,4,0,7);tc.fill();tc.fillStyle=”#fff”;tc.textAlign=”left”;tc.font=’500 11px “DM Mono”, monospace’;tc.fillText(“35S13ST TV”,34,27);
tc.fillStyle=”rgba(255,255,255,.035)”;for(let y=0;y{c.beginPath();c.arc(x,y,6,0,7);c.fill()});
c.fillStyle=”#3a3c3e”;c.fillRect(300,440,78,18);c.font=’600 22px “Permanent Marker”, cursive’;c.fillStyle=”rgba(30,20,10,.55)”;c.save();c.translate(80,240);c.rotate(-.04);c.fillText(“COMING SOON ↑ — 13ST”,0,0);c.restore()}
/* ———- scale ———- */
let k=1;
function fit(){k=frame.clientWidth/W;if(!walking)world.style.transform=`scale(${k})`}
new ResizeObserver(fit).observe(frame);
/* ———- interactions ———- */
const msg=$(“#msg”);let mt;const say=t=>{msg.textContent=t;clearTimeout(mt);mt=setTimeout(()=>msg.textContent=””,3200)};
let doorOpen=false,winDown=false,walking=false;
// camera follows the visitor
const head=$(“#head”),lens=$(“#lens”);let target={x:0,y:0},cur={x:0,y:0};
function aim(cx,cy){const b=frame.getBoundingClientRect();const ox=b.left+845*k,oy=b.top+640*k;const dx=cx-ox,dy=cy-oy,d=Math.hypot(dx,dy)||1;target.x=Math.max(-1,Math.min(1,dx/Math.max(240,d)))*Math.min(1,d/180);target.y=Math.max(-1,Math.min(1,dy/Math.max(240,d)))*Math.min(1,d/180)}
addEventListener(“pointermove”,e=>aim(e.clientX,e.clientY));addEventListener(“pointerdown”,e=>aim(e.clientX,e.clientY));
(function track(){cur.x+=(target.x-cur.x)*.08;cur.y+=(target.y-cur.y)*.08;head.setAttribute(“transform”,`rotate(${(cur.x*24).toFixed(2)} 845 614)`);lens.setAttribute(“transform”,`translate(${(cur.x*6).toFixed(2)} ${(cur.y*7+2).toFixed(2)})`);requestAnimationFrame(track)})();
// floodlight
const toggleLight=()=>{const on=frame.classList.toggle(“lit”);$(“#bLight”).textContent=on?”Light off”:”Floodlight”;say(on?”Floodlight on. The camera sees you.”:”Floodlight off”)};
$(“#hitLamp”).addEventListener(“click”,toggleLight);$(“#hitLamp”).addEventListener(“keydown”,e=>{if(e.key===”Enter”||e.key===” “){e.preventDefault();toggleLight()}});$(“#bLight”).onclick=toggleLight;
// door
const doorEl=$(“#door”);
$(“#hitDoor”).addEventListener(“pointerenter”,()=>{if(!doorOpen)doorEl.classList.add(“armed”)});$(“#hitDoor”).addEventListener(“pointerleave”,()=>doorEl.classList.remove(“armed”));
function openDoor(){if(doorOpen){walkIn();return}doorEl.classList.add(“unlocked”);say(“Unlocked. Gallery coming soon.”);setTimeout(()=>{frame.classList.add(“dooropen”);doorOpen=true;$(“#bDoor”).textContent=”Close the door”;$(“#bWalk”).hidden=false;$(“#hitDoor”).setAttribute(“aria-label”,”Walk in: coming soon”)},500)}
function closeDoor(){frame.classList.remove(“dooropen”);doorOpen=false;setTimeout(()=>doorEl.classList.remove(“unlocked”),1200);$(“#bDoor”).textContent=”Unlock the door”;$(“#bWalk”).hidden=true;$(“#hitDoor”).setAttribute(“aria-label”,”Try the door”)}
$(“#hitDoor”).onclick=openDoor;$(“#bDoor”).onclick=()=>doorOpen?closeDoor():openDoor();$(“#bWalk”).onclick=walkIn;
// window
function toggleWin(){winDown=!winDown;frame.classList.toggle(“windown”,winDown);$(“#bWin”).textContent=winDown?”Raise the window”:”Drop the window”;$(“#hitWin”).setAttribute(“aria-label”,winDown?”Raise the window”:”Drop the window”);if(winDown){tvOn=true;say(“Coming soon on 35S13ST TV”)}else setTimeout(()=>{if(!winDown)tvOn=false},1600)}
$(“#hitWin”).onclick=toggleWin;$(“#bWin”).onclick=toggleWin;
// repaint
$(“#bPaint”).onclick=()=>{seed=(seed+1)%WALLSEQ.length;compose();say(current.key===”nero”?”Nero One wall”:current.key===”advertise”?”Fresh paint. Advertise here.”:”Fresh paint”)};
$(“#hitWall”).onclick=()=>{if(current.key===”nero”)location.hash=”nero”;else if(current.key===”advertise”){say(“Advertise here: DM @35S13ST”);window.open&&0}else say(current.name)};
/* ———- walk in ———- */
function walkIn(){if(walking)return;if(!doorOpen){openDoor();setTimeout(walkIn,2000);return}walking=true;
const fw=frame.clientWidth,fh=frame.clientHeight,k2=k*7,Dx=1095,Dy=1330;
world.style.transform=`translate(${fw/2-k2*Dx}px,${fh/2-k2*Dy}px) scale(${k2})`;
setTimeout(()=>$(“#white”).style.opacity=1,reduce?0:900);
setTimeout(()=>{const so=$(“#soon”);so.hidden=false;requestAnimationFrame(()=>so.classList.add(“on”));$(“#soonPeek”).focus({preventScroll:true})},reduce?50:1600);
}
function stepOut(){const ins=$(“#inside”);ins.classList.remove(“on”);$(“#card”).hidden=true;setTimeout(()=>{ins.hidden=true;tv2c=null;walking=false;fit();setTimeout(()=>$(“#white”).style.opacity=0,300)},700)}
$(“#iOut”).onclick=stepOut;
function peekInside(){const so=$(“#soon”);so.classList.remove(“on”);setTimeout(()=>so.hidden=true,500);const ins=$(“#inside”);ins.hidden=false;requestAnimationFrame(()=>ins.classList.add(“on”));buildInside();ilayout()}
function soonOut(){const so=$(“#soon”);so.classList.remove(“on”);setTimeout(()=>{so.hidden=true;walking=false;fit();setTimeout(()=>$(“#white”).style.opacity=0,300)},600)}
$(“#soonPeek”).onclick=peekInside;$(“#soonOut”).onclick=soonOut;
/* ———- inside ———- */
let built=false,view=0,angle=0,IH=0;const NAMES=[“Main wall”,”TV wall”,”Front door”,”Back wall”];
const room=$(“#room”),icube=$(“#icube”),ifaces=$$(“#icube .face”);
function hang(wall,pc,l,t,w,oak){const el=document.createElement(“button”);el.type=”button”;el.className=”art”+(oak?” oak”:””);el.style.cssText=`left:${l}%;top:${t}%;width:${w}%;aspect-ratio:3/4`;el.innerHTML=`
`;el.setAttribute(“aria-label”,`${pc.t} by ${pc.a}, $${pc.p}`);el.onclick=()=>showCard(pc);wall.appendChild(el);
const pl=document.createElement(“div”);pl.className=”placard”;pl.style.cssText=`left:${l}%;top:${t+w*1.94+3}%`;pl.innerHTML=`${pc.t}${pc.a} · $${pc.p}`;wall.appendChild(pl)}
function buildInside(){if(built){tv2c=$(“#tv2”).getContext(“2d”);return}built=true;
const w0=$(“#w0”),w1=$(“#w1”),w2=$(“#w2”),w3=$(“#w3”);
w0.insertAdjacentHTML(“beforeend”,`
`);
hang(w0,PIECES[2],14,28,22,false);hang(w0,PIECES[0],48,34,14,true);hang(w0,PIECES[1],68,34,14,true);
w1.insertAdjacentHTML(“beforeend”,`
`);
w2.insertAdjacentHTML(“beforeend”,`
`);
w3.insertAdjacentHTML(“beforeend”,`
`);
hang(w3,PIECES[3],38,18,24,false);
$(“#exitHot”).onclick=stepOut;tv2c=$(“#tv2”).getContext(“2d”);
$$(“#iPrev,#iNext”).forEach(b=>b.onclick=()=>igo(view+(b.id===”iNext”?1:-1)));
}
function ilayout(){const w=room.clientWidth;IH=w/2;room.style.perspective=IH+”px”;ifaces.forEach(f=>f.style.transform=`rotateY(${-f.dataset.k*90}deg) translateZ(${-IH}px)`);iset()}
function iset(){icube.style.transform=`translateZ(${IH}px) rotateY(${angle}deg)`;$(“#iName”).textContent=NAMES[view]}
function igo(n){const c=Math.round(angle/90);let d=((n-((c%4)+4)%4)+4)%4;if(d===3)d=-1;angle=(c+d)*90;view=((n%4)+4)%4;iset()}
new ResizeObserver(()=>{if(!$(“#inside”).hidden)ilayout()}).observe(room);
room.addEventListener(“keydown”,e=>{if(e.key===”ArrowRight”){e.preventDefault();igo(view+1)}if(e.key===”ArrowLeft”){e.preventDefault();igo(view-1)}});
let drag=null;
room.addEventListener(“pointerdown”,e=>{if(e.target.closest(“button”))return;drag={x:e.clientX,a:angle,m:false};room.setPointerCapture(e.pointerId)});
room.addEventListener(“pointermove”,e=>{if(!drag)return;const dx=e.clientX-drag.x;if(Math.abs(dx)>4){drag.m=true;room.classList.add(“dragging”);icube.classList.add(“live”)}if(drag.m){angle=drag.a-dx/room.clientWidth*120;iset()}});
const endD=()=>{if(!drag)return;icube.classList.remove(“live”);room.classList.remove(“dragging”);if(drag.m){const n=Math.round(angle/90);angle=n*90;view=((n%4)+4)%4;iset()}drag=null};
room.addEventListener(“pointerup”,endD);room.addEventListener(“pointercancel”,endD);
function showCard(pc){const c=$(“#card”);c.innerHTML=`
`;c.hidden=false;$(“#cardX”).onclick=()=>c.hidden=true}
document.addEventListener(“keydown”,e=>{if(e.key===”Escape”)$(“#card”).hidden=true});
/* ———- pages (about + project posts) ———- */
const LINKS={ig:”https://www.instagram.com/35s13st/”,peer:”https://www.peerspace.com/pages/listings/6a6bd2738826ed6e1099e93d#type=media”,shop:SHOP};
const POSTS=[
{slug:”woman-in-red”,yr:”2026″,t:”Woman in Red”,sub:”filthy · one-of-one works on paper”,art:0,
body:[“A run of one-of-one 9×12 works on heavyweight cotton paper by filthy. Paint and marker, a sketchbook edge, and the same woman in red returning across the series.”,”Each piece stands on its own. Hung in twos and threes, they read as one wall, so we release them in small stacks.”]},
{slug:”call-for-artists”,yr:”2026″,t:”Call for Artists”,sub:”Open call · originals, sculpture, murals”,art:3,
body:[“We opened a paid call to Philadelphia artists for original works, sculptural pieces of any size, and concepts for murals, video and photo projects.”,”Commissions are paid in three parts: to start, once work is underway, and on delivery. Commissioned work includes digital usage rights. Members on our Instagram hear about the next call first.”]},
{slug:”print-drop-filthy”,yr:”2025″,t:”Print Drop: @filthyf3lloff”,sub:”Limited edition · small batch”,art:1,
body:[“Our first artist print drop. A limited, small-batch edition made with filthy and released through the shop.”,”It set the model we still use: one artist, one release, made to last on your wall.”]},
{slug:”murals-installs”,yr:”2022–25″,t:”Murals, Prints & Installations”,sub:”Center City studio work”,art:2,
body:[“Since 2022 the studio at 35 S. 13th St has made murals, prints, installations and community projects with Philadelphia artists.”,”The full 2025 portfolio has photos and specs for this period.”],link:[“2025 portfolio (PDF)”,”https://drive.google.com/file/d/1KCEAJSBYneyEhCTCuFCx50cJawHXtcOc/view”%5D}
];
const pageEl=$(“#page”);
const pnav=cur=>`35S13ST PhiladelphiaStorefrontAboutProjectsNero OneShopSOONBookIG`;
function aboutPage(){return `
35S13ST
35S13ST is a Black-owned street art studio at 35 S. 13th St in Center City, Philadelphia. Since 2022 we’ve worked with Philly artists on prints, original work, murals and installations.
The gallery and shop are coming soon. Until then this site is the front door, and the space can be booked or rented for shoots and small sessions.
Members on our Instagram get first look at new pieces and paid artist opportunities before anyone else.
`}
function projectsPage(){return `
`}
function postPage(p){const i=POSTS.indexOf(p),nx=POSTS[(i+1)%POSTS.length];return `
${p.t}
${p.body.map(t=>`
${t}
`).join(“”)}
`}
const NERO_IG=”https://www.instagram.com/nero_one/”;
function neroPage(){return `
Nero One
Preview in his style. The real piece goes up Tuesday.
Nero One (Rob Nero) is a South Philly stencil artist. He came up in graffiti, tagging walls with lines like “You Belong Here,” then moved into stencils. His work is bold, high-contrast black and white, built around the city’s athletes and the people who show up for them.
His 2018 Nick Foles mural, painted after the Eagles won the Super Bowl, is where it took off. Since then he’s run pop-ups where fans bring their own shirts and bags and he sprays his stencils straight onto them.
This season he’s taking it to the Sixers, with new work for the 2026–27 run. He’s starting with our wall at 35 S. 13th St.
`}
function shopPage(){return `
Coming soon.
Original work and small editions from the artists on our wall. We’re building it out now.
Follow along on IG to hear when it opens.
`}
function route(){const h=location.hash.slice(1);let html=null;
if(h===”nero”)html=neroPage();else if(h===”shop”)html=shopPage();else
if(h===”about”)html=aboutPage();else if(h===”projects”)html=projectsPage();else if(h.startsWith(“project-“)){const p=POSTS.find(x=>”project-“+x.slug===h);if(p)html=postPage(p)}
if(!html){pageEl.hidden=true;document.body.style.overflow=””;return}
pageEl.innerHTML=html;pageEl.hidden=false;pageEl.scrollTop=0;document.body.style.overflow=”hidden”;
const nc=$(“#neroCanvas”);if(nc&&T.black){nc.getContext(“2d”).drawImage(neroShot||makeNeroShot(),0,0)}
const cm=$(“#copyMail”);if(cm)cm.onclick=()=>{try{navigator.clipboard.writeText(“3513ST@gmail.com”).then(()=>cm.textContent=”Copied”,()=>cm.textContent=”3513ST@gmail.com”)}catch(_){cm.textContent=”3513ST@gmail.com”}}}
addEventListener(“hashchange”,route);route();
$(“#hitNote”).onclick=()=>say(current&¤t.clean?”Post-it: “Will just painted this :)””:”An old post-it. Can’t make it out.”);
/* ———- boot ———- */
const fontsReady=Promise.race([Promise.all([’40px “Sedgwick Ave Display”‘,’40px “Permanent Marker”‘,’900 40px “Big Shoulders Stencil Display”‘,’italic 40px “Instrument Serif”‘,’40px “Instrument Serif”‘,’500 12px “DM Mono”‘,’12px Archivo’].map(f=>document.fonts.load(f))),new Promise(r=>setTimeout(r,2500))]);
Promise.all([fontsReady,…imgs.map(im=>im.decode?im.decode().catch(()=>{}):Promise.resolve())]).then(()=>{
buildTextures();compose();windowBack();paintBack($(“#cBack”).getContext(“2d”),imgs);fit();route();$(“#loading”).classList.add(“done”);requestAnimationFrame(loop);
});
})();