Download index.html from Death242/showcase: direct link, hf CLI and curl.
- Browser
- Download file 99.8 kB
-
https://huggingface.co/spaces/Death242/showcase/resolve/main/index.html
- Command line
-
hf download hf://spaces/Death242/showcase/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Death242/showcase/resolve/main/index.html
99.8 kB
| <html lang="en"> | |
| <head> | |
| <script>(()=>{const S={"homebase": "https://homebase-family.onrender.com", "noor": "https://death242-noor.static.hf.space", "void": "https://death242-void.static.hf.space", "scout": "https://scout-15t6.onrender.com", "unwritten": "https://unwritten-dulm.onrender.com", "cookify": "https://cookify-6auu.onrender.com", "crosswind": "https://death242-crosswind.static.hf.space", "platter": "https://platter-87b0.onrender.com", "alibi": "https://alibi-d9tn.onrender.com", "tripmate": "https://tripmate-yecg.onrender.com", "cramly": "https://cramly-twz5.onrender.com", "womanten": "https://womanten.onrender.com", "whatif": "https://whatif-kkq1.onrender.com", "nonsense": "https://death242-totally-normal-website.static.hf.space"},f=window.fetch.bind(window);window.fetch=(u,o)=>{const s=String(u);if(s.includes('/api/status')){const out={};return Promise.all(Object.entries(S).map(([k,url])=>{const c=new AbortController(),t=setTimeout(()=>c.abort(),9000);return f(url,{mode:'no-cors',signal:c.signal}).then(()=>{out[k]=true}).catch(()=>{out[k]=false}).finally(()=>clearTimeout(t));})).then(()=>new Response(JSON.stringify({status:out,checked:Date.now()/1000}),{headers:{'Content-Type':'application/json'}}));}if(s.includes('/api/projects'))return f('/static/projects.json',o);return f(u,o);};})();</script> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 64 64%27%3E%3Crect width=%2764%27 height=%2764%27 rx=%2716%27 fill=%27%23111113%27/%3E%3Cpath d=%27M14 34 32 18l18 16v14H14z%27 fill=%27none%27 stroke=%27%23fff%27 stroke-width=%273.5%27 stroke-linejoin=%27round%27/%3E%3C/svg%3E"> | |
| <meta name="theme-color" content="#0a0a0a"> | |
| <meta property="og:title" content="Everything I've built"> | |
| <meta property="og:description" content="Ten projects with live links, how each works, and how I made it."> | |
| <meta property="og:type" content="website"> | |
| <meta property="og:image" content="/static/og.png"> | |
| <meta name="twitter:card" content="summary_large_image"> | |
| <title>Everything I've built</title> | |
| <meta name="description" content="Ten projects with live links, how each one works, how I made it, and the reveal."> | |
| <style> | |
| :root { --bg: #0a0a0a; --card: #111111; --card2: #171717; --line: #252525; --ink: #ededed; --muted: #8e8e8e; --rim: rgba(255,255,255,.09); } | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| html { scroll-behavior: smooth; } | |
| body { background: var(--bg); color: var(--ink); font-family: Inter, "Segoe UI", system-ui, -apple-system, Roboto, sans-serif; -webkit-font-smoothing: antialiased; line-height: 1.55; } | |
| a { color: inherit; text-decoration: none; } | |
| .wrap { width: min(1160px, 100% - 40px); margin: 0 auto; } | |
| .silver { background: linear-gradient(180deg, #fff 10%, #9b9ba4 100%); -webkit-background-clip: text; background-clip: text; color: transparent; } | |
| nav { position: sticky; top: 0; z-index: 20; backdrop-filter: blur(16px); background: rgba(10,10,11,.82); border-bottom: 1px solid var(--line); } | |
| nav .wrap { display: flex; align-items: center; justify-content: space-between; height: 58px; } | |
| nav b { font-weight: 600; letter-spacing: -.02em; } nav div a { margin-left: 22px; color: var(--muted); font-size: 14px; transition: color .2s; } nav div a:hover { color: #fff; } | |
| .hero { position: relative; padding: 13vh 0 9vh; text-align: center; overflow: hidden; } | |
| .hero::before { content: ""; position: absolute; left: 50%; top: -20%; width: 100vmax; height: 70vmax; transform: translateX(-50%); background: radial-gradient(ellipse at 50% 0%, rgba(255,255,255,.07), transparent 62%); pointer-events: none; } | |
| .kick { letter-spacing: .5em; font-size: 12px; color: var(--muted); text-transform: uppercase; margin-bottom: 20px; } | |
| h1 { font-size: clamp(46px, 10.5vw, 148px); font-weight: 300; letter-spacing: -.05em; line-height: .96; } | |
| .lead { margin: 24px auto 0; max-width: 52ch; color: var(--muted); font-size: clamp(16px, 2vw, 20px); } | |
| .cta { margin-top: 34px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } | |
| .btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; border-radius: 99px; font-weight: 600; font-size: 14.5px; border: 1px solid var(--rim); background: var(--card2); transition: transform .2s, background .2s; cursor: pointer; color: var(--ink); } | |
| .btn:hover { transform: translateY(-2px); background: #1e1e1e; } .btn.solid { background: #ececf0; color: #0a0a0b; border-color: #ececf0; } .btn.solid:hover { background: #fff; } | |
| .stats { margin-top: 54px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } | |
| .stat { padding: 16px 28px; border: 1px solid var(--line); border-radius: 18px; background: var(--card); min-width: 150px; } | |
| .stat b { display: block; font-size: 32px; font-weight: 300; letter-spacing: -.03em; } .stat span { color: var(--muted); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; } | |
| section { padding: 8vh 0; } | |
| h2 { font-size: clamp(30px, 5vw, 54px); letter-spacing: -.045em; line-height: 1.05; font-weight: 300; } | |
| .sub { color: var(--muted); margin-top: 10px; max-width: 60ch; } | |
| .reveal-frame { margin-top: 28px; aspect-ratio: 16 / 9; width: 100%; border-radius: 22px; overflow: hidden; border: 1px solid var(--line); background: #000; box-shadow: 0 40px 100px rgba(0,0,0,.7); } | |
| .reveal-frame iframe { width: 100%; height: 100%; border: 0; display: block; } | |
| .reveal-actions { margin-top: 14px; } | |
| .chips { margin: 26px 0 22px; display: flex; gap: 8px; flex-wrap: wrap; } | |
| .chip { padding: 8px 18px; border-radius: 99px; border: 1px solid var(--line); background: transparent; color: var(--muted); font: inherit; font-size: 14px; cursor: pointer; transition: all .2s; } | |
| .chip:hover { color: #fff; } .chip.on { background: #ececf0; color: #0a0a0b; border-color: #ececf0; font-weight: 600; } | |
| .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 16px; } | |
| .card { position: relative; border: 1px solid var(--line); border-radius: 24px; padding: 24px; background: var(--card); display: flex; flex-direction: column; gap: 14px; transition: transform .25s, border-color .25s, background .25s; } | |
| .card:hover { transform: translateY(-3px); border-color: #3a3a3a; background: var(--card2); } | |
| .top { display: flex; gap: 16px; align-items: center; } | |
| .tile { flex: none; width: 58px; height: 58px; border-radius: 27%; display: grid; place-items: center; font-size: 29px; background: linear-gradient(160deg, #222222, #0d0d0d 72%); box-shadow: inset 0 1px 0 rgba(255,255,255,.17), inset 0 0 0 1px rgba(255,255,255,.04), 0 14px 30px rgba(0,0,0,.6); } | |
| .card h3 { font-size: 22px; font-weight: 500; letter-spacing: -.03em; line-height: 1.1; } .card .tag { color: var(--muted); font-size: 13.5px; margin-top: 3px; } | |
| .card p.about { color: #c4c4c4; font-size: 14.5px; } | |
| .stack { display: flex; gap: 6px; flex-wrap: wrap; } .stack span { font-size: 12px; padding: 4px 10px; border-radius: 99px; background: #1b1b1b; border: 1px solid var(--line); color: var(--muted); } | |
| .stack span.ai { color: #0a0a0b; background: #ececf0; border-color: #ececf0; font-weight: 600; } | |
| details { border-top: 1px solid var(--line); padding-top: 12px; } summary { cursor: pointer; font-weight: 600; font-size: 14px; list-style: none; display: flex; justify-content: space-between; } | |
| summary::after { content: "+"; color: var(--muted); font-size: 18px; line-height: 1; } details[open] summary::after { content: "\2013"; } summary::-webkit-details-marker { display: none; } | |
| ol { margin: 12px 0 2px; list-style: none; counter-reset: s; display: grid; gap: 10px; } | |
| ol li { counter-increment: s; display: flex; gap: 12px; align-items: flex-start; font-size: 14px; color: #d5d5d5; } | |
| ol li::before { content: counter(s); flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 600; border: 1px solid #3a3a3a; color: #fff; margin-top: 1px; } | |
| .links { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 4px; } .links .btn { padding: 9px 18px; font-size: 14px; } | |
| .badge { position: absolute; top: 18px; right: 18px; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; padding: 4px 10px; border-radius: 99px; border: 1px solid var(--line); color: var(--muted); } | |
| .feature { border: 1px solid var(--line); border-radius: 30px; padding: clamp(24px, 5vw, 54px); background: radial-gradient(800px 320px at 85% 0%, rgba(255,255,255,.05), transparent 60%), var(--card); } | |
| .promise { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; margin-top: 26px; } | |
| .promise div { padding: 18px 20px; border-radius: 18px; background: #0d0d0d; border: 1px solid var(--line); font-size: 14.5px; color: #c4c4c4; } .promise b { display: block; margin-bottom: 6px; font-size: 16px; color: #fff; font-weight: 600; } | |
| .credits { text-align: center; } | |
| .mebig { font-size: clamp(70px, 18vw, 230px); font-weight: 200; letter-spacing: -.065em; line-height: .95; margin-top: 10px; } | |
| .credits .say { margin: 18px auto 0; max-width: 46ch; color: var(--muted); font-size: clamp(16px, 2vw, 21px); } | |
| .crow { margin-top: 44px; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; text-align: left; } | |
| .crow div { padding: 22px; border: 1px solid var(--line); border-radius: 20px; background: var(--card); } .crow b { display: block; font-size: 20px; font-weight: 500; letter-spacing: -.02em; margin-bottom: 6px; } | |
| .crow span { color: var(--muted); font-size: 14px; display: block; } .crow .helper { background: var(--card2); border-color: #343434; } .crow .helper b { font-size: 24px; } | |
| footer { padding: 6vh 0 10vh; text-align: center; color: var(--muted); font-size: 13.5px; border-top: 1px solid var(--line); } | |
| .fgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 22px; } | |
| .fgrid div { padding: 16px 18px; border-radius: 18px; background: #0d0d0d; border: 1px solid var(--line); font-size: 14px; color: #bababa; } .fgrid i { font-style: normal; font-size: 22px; display: block; margin-bottom: 6px; } .fgrid b { display: block; color: #fff; font-size: 15.5px; font-weight: 600; margin-bottom: 3px; } | |
| .techs { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; } | |
| .tc { display: flex; align-items: baseline; gap: 10px; padding: 12px 20px; border: 1px solid var(--line); border-radius: 99px; background: var(--card); transition: border-color .2s; } .tc:hover { border-color: #3a3a3a; } .tc b { font-size: 22px; font-weight: 300; color: #fff; } .tc span { color: var(--muted); font-size: 14px; } | |
| #bar { position: fixed; left: 0; top: 0; height: 2px; width: 0; background: linear-gradient(90deg, #c9a56a, #ececec); z-index: 40; } | |
| .sortsel { padding: 10px 14px; border-radius: 99px; border: 1px solid var(--line); background: var(--card); color: var(--ink); font: inherit; font-size: 14px; } | |
| .card.flash { animation: flash 1.6s ease; } @keyframes flash { 0%, 60% { border-color: #c9a56a; box-shadow: 0 0 0 4px rgba(201,165,106,.18); } } | |
| .btn.sm { padding: 9px 14px; font-size: 13px; color: var(--muted); } | |
| .livesum { margin-top: 18px; color: var(--muted); font-size: 14px; } .livesum b { color: #fff; font-weight: 600; } | |
| .news { margin-top: 26px; display: grid; gap: 0; border-left: 1px solid var(--line); margin-left: 6px; } | |
| .news div { position: relative; padding: 4px 0 22px 26px; color: #c4c4c4; font-size: 15px; } .news div::before { content: ""; position: absolute; left: -5px; top: 11px; width: 9px; height: 9px; border-radius: 50%; background: #ececf0; } | |
| .news b { color: #fff; font-weight: 600; margin-right: 8px; } | |
| .faq details { padding: 16px 0; border-top: 1px solid var(--line); } .faq details:last-child { border-bottom: 1px solid var(--line); } .faq p { color: var(--muted); margin-top: 10px; max-width: 70ch; font-size: 15px; } | |
| .totop { position: fixed; right: 18px; bottom: 18px; z-index: 30; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--rim); background: var(--card2); color: #fff; cursor: pointer; font-size: 18px; opacity: 0; pointer-events: none; transition: opacity .25s; } .totop.on { opacity: 1; pointer-events: auto; } | |
| /* ---- tough pass: depth, glow, motion (all slow, none of it flashes; off for reduced motion) ---- */ | |
| .hero::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5; | |
| background-image: linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px); | |
| background-size: 56px 56px; -webkit-mask-image: radial-gradient(ellipse at 50% 30%, #000 8%, transparent 70%); mask-image: radial-gradient(ellipse at 50% 30%, #000 8%, transparent 70%); } | |
| .hero .wrap { position: relative; z-index: 1; } | |
| .orb { position: absolute; width: 46vmax; height: 46vmax; border-radius: 50%; filter: blur(90px); opacity: .22; pointer-events: none; animation: drift 22s ease-in-out infinite alternate; } | |
| .orb.a { left: -12vmax; top: -10vmax; background: #8a5a2b; } .orb.b { right: -14vmax; top: 6vmax; background: #5a2f2f; animation-delay: -9s; } | |
| @keyframes drift { to { transform: translate(5vmax, 4vmax) scale(1.12); } } | |
| .ticker { overflow: hidden; border-block: 1px solid var(--line); background: rgba(255,255,255,.015); -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); } | |
| .ticker .track { display: flex; gap: 46px; width: max-content; padding: 16px 0; animation: tick 48s linear infinite; } | |
| .ticker span { font-size: 15px; color: var(--muted); letter-spacing: .02em; white-space: nowrap; } .ticker b { color: #fff; font-weight: 500; margin-right: 8px; } | |
| @keyframes tick { to { transform: translateX(-50%); } } | |
| .card { --h: 220; --mx: 50%; --my: 0%; overflow: hidden; transform-style: preserve-3d; will-change: transform; } | |
| .card::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .3s; | |
| background: radial-gradient(420px circle at var(--mx) var(--my), hsla(var(--h), 30%, 70%, .12), transparent 62%); } | |
| .card:hover::before { opacity: 1; } | |
| .card::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: linear-gradient(90deg, transparent, hsl(var(--h), 35%, 62%), transparent); opacity: .55; } | |
| .card:hover { border-color: hsla(var(--h), 25%, 60%, .4); } | |
| .card .tile { box-shadow: inset 0 1px 0 rgba(255,255,255,.17), inset 0 0 0 1px rgba(255,255,255,.04), 0 14px 30px rgba(0,0,0,.6), 0 0 28px hsla(var(--h), 30%, 60%, .14); } | |
| .js .rv { opacity: 0; transform: translateY(26px); transition: opacity .8s cubic-bezier(.2,.7,.2,1), transform .8s cubic-bezier(.2,.7,.2,1); } | |
| .js .rv.in { opacity: 1; transform: none; } | |
| .stat b { font-variant-numeric: tabular-nums; } | |
| .btn.solid { box-shadow: 0 0 0 1px rgba(255,255,255,.2), 0 10px 40px rgba(255,255,255,.10); } | |
| h2 .silver { text-shadow: none; } | |
| #pal { position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.66); backdrop-filter: blur(8px); display: none; align-items: flex-start; justify-content: center; padding-top: 14vh; } | |
| #pal.on { display: flex; } | |
| #pal .box { width: min(560px, 92%); border: 1px solid #343434; border-radius: 20px; background: #0f0f0f; box-shadow: 0 40px 120px rgba(0,0,0,.8); overflow: hidden; } | |
| #pal input { width: 100%; padding: 18px 20px; background: transparent; border: 0; border-bottom: 1px solid var(--line); color: #fff; font: inherit; font-size: 17px; outline: none; } | |
| #pal ul { list-style: none; max-height: 46vh; overflow: auto; padding: 8px; } | |
| #pal li { display: flex; gap: 12px; align-items: center; padding: 11px 14px; border-radius: 12px; cursor: pointer; color: #d5d5d5; } #pal li small { margin-left: auto; color: var(--muted); } | |
| #pal li.sel { background: #1e1e1e; color: #fff; } | |
| #pal .hint { padding: 10px 16px; font-size: 12px; color: var(--muted); border-top: 1px solid var(--line); } | |
| kbd { font: inherit; font-size: 12px; padding: 2px 7px; border: 1px solid #3a3a3a; border-radius: 6px; background: #181818; color: #d0d0d0; } | |
| .kbtn { margin-left: 18px; } | |
| nav b { white-space: nowrap; font-size: 15px; } nav .wrap > div { display: flex; align-items: center; } | |
| @media (max-width: 560px) { .kbtn kbd { display: none; } nav div a:nth-child(n+2) { display: none; } nav .wrap > div .kbtn { margin-right: 0 ; } } | |
| @media (prefers-reduced-motion: reduce) { .orb, .ticker .track { animation: none ; } .js .rv { opacity: 1; transform: none; transition: none; } } | |
| .hide { display: none ; } | |
| :focus-visible { outline: 2px solid #c9a56a; outline-offset: 3px; border-radius: 8px; } | |
| .skip { position: absolute; left: -999px; top: 8px; background: #fff; color: #000; padding: 8px 14px; border-radius: 10px; z-index: 50; } .skip:focus { left: 8px; } | |
| .tools { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin: 26px 0 22px; } .tools .chips { margin: 0; flex: 1 1 auto; } | |
| .search { flex: 0 1 260px; padding: 10px 16px; border-radius: 99px; border: 1px solid var(--line); background: var(--card); color: var(--ink); font: inherit; font-size: 14px; outline-offset: 2px; } .search::placeholder { color: var(--muted); } | |
| .dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: #55555c; margin-right: 6px; vertical-align: 1px; } .dot.online { background: #6fe3a5; box-shadow: 0 0 8px #6fe3a5; } .dot.waking { background: #ffd37a; animation: pulse 1.4s infinite; } .dot.down { background: #ff7a93; } | |
| @keyframes pulse { 50% { opacity: .35; } } | |
| .live { font-size: 12px; color: var(--muted); margin-top: 3px; } | |
| .none { display: none; text-align: center; color: var(--muted); padding: 40px 0; } .none.on { display: block; } | |
| @media (max-width: 640px) { .reveal-frame { aspect-ratio: 3 / 4; } } | |
| @media (max-width: 560px) { .grid { grid-template-columns: 1fr; } nav div a:nth-child(n+3) { display: none; } } | |
| /* card pictures: a real screenshot inside a small browser window, or a designed card where a screenshot would show something private */ | |
| .grid { align-items: start; } | |
| .shot { display: block; position: relative; margin: -24px -24px 4px; aspect-ratio: 960 / 520; overflow: hidden; background: #0a0a0a; border-bottom: 1px solid var(--line); } | |
| .shot img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .7s cubic-bezier(.2, .7, .2, 1); } | |
| .card:hover .shot img { transform: scale(1.04); } | |
| .shot.art { display: grid; place-content: center; justify-items: center; gap: 6px; text-align: center; padding: 0 12%; | |
| background: radial-gradient(110% 95% at 50% 0%, hsla(var(--h), 42%, 26%, .8), hsla(var(--h), 30%, 9%, 1) 62%, #0a0a0a); | |
| box-shadow: inset 0 0 0 1px rgba(255,255,255,.03); } | |
| .shot.art::before { content: ""; position: absolute; inset: 0; background: repeating-radial-gradient(circle at 50% 120%, transparent 0 34px, rgba(255,255,255,.035) 34px 35px); } | |
| .art-emoji { position: relative; font-size: 62px; line-height: 1; filter: drop-shadow(0 14px 22px rgba(0,0,0,.65)); } | |
| .art-name { position: relative; font-size: 28px; font-weight: 300; letter-spacing: -.03em; } | |
| .art-tag { position: relative; color: #a9a9a9; font-size: 13.5px; line-height: 1.35; } | |
| .badge { z-index: 2; } | |
| /* the timeline: one bar per project, from its first commit to its last */ | |
| .gantt { margin-top: 30px; padding: 22px 24px 14px; border: 1px solid var(--line); border-radius: 24px; background: var(--card); } | |
| .g-axis, .g-row { display: grid; grid-template-columns: 168px 1fr; align-items: center; gap: 14px; } | |
| .g-axis { margin-bottom: 8px; color: var(--muted); font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; } | |
| .g-ticks { position: relative; height: 18px; } .g-ticks span { position: absolute; top: 0; white-space: nowrap; } | |
| .g-row { min-height: 40px; border-top: 1px solid rgba(255,255,255,.04); } | |
| .g-name { display: flex; align-items: center; gap: 10px; color: var(--ink); text-decoration: none; font-size: 14.5px; min-width: 0; } | |
| .g-name i { font-style: normal; width: 28px; height: 28px; flex: none; display: grid; place-items: center; border-radius: 9px; background: #1a1a1a; font-size: 15px; } | |
| .g-name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| .g-name:hover span { text-decoration: underline; text-underline-offset: 3px; } | |
| .g-track { position: relative; height: 40px; background-image: linear-gradient(to right, rgba(255,255,255,.06) 1px, transparent 1px); background-size: var(--week) 100%; } | |
| .g-bar { position: absolute; top: 9px; height: 22px; border-radius: 99px; display: flex; align-items: center; padding: 0 10px; overflow: hidden; | |
| background: linear-gradient(180deg, #dedede, #a6a6a6); color: #0a0a0a; font-size: 11.5px; font-weight: 600; white-space: nowrap; transition: background .25s, box-shadow .25s; | |
| transform-origin: left; } | |
| .g-row:hover .g-bar { background: linear-gradient(180deg, hsl(var(--h), 40%, 70%), hsl(var(--h), 36%, 54%)); box-shadow: 0 0 20px hsla(var(--h), 40%, 60%, .3); } | |
| section[id] { scroll-margin-top: 64px; } | |
| .g-note { position: absolute; top: 12px; margin-left: 8px; color: var(--muted); font-size: 11.5px; white-space: nowrap; } | |
| .js .gantt.rv .g-bar { transform: scaleX(0); transition: transform .9s cubic-bezier(.2, .7, .2, 1); } .js .gantt.rv.in .g-bar { transform: none; } | |
| .g-foot { color: var(--muted); font-size: 13px; margin-top: 14px; } | |
| @media (max-width: 700px) { .g-axis, .g-row { grid-template-columns: 1fr; gap: 2px; } .g-axis .g-lab { display: none; } .g-row { padding: 6px 0 2px; } .g-track { height: 30px; } .g-bar { top: 4px; } .g-note { top: 7px; } .gantt { padding: 18px 16px 10px; } } | |
| @media (prefers-reduced-motion: reduce) { .js .gantt.rv .g-bar { transform: none; transition: none; } .shot img { transition: none; } } | |
| .qrbox { display: flex; gap: 28px; align-items: center; flex-wrap: wrap; margin-top: 24px; padding: 24px; border: 1px solid var(--line); border-radius: 24px; background: #0e0e10; } | |
| .qrimg { background: #fff; border-radius: 20px; padding: 14px; line-height: 0; } | |
| .qrimg img { width: 240px; height: 240px; image-rendering: pixelated; } | |
| .qrside { display: flex; flex-direction: column; gap: 14px; flex: 1; min-width: 220px; } | |
| .qrurl { color: var(--muted, #9a9aa3); font-size: 15px; word-break: break-all; } | |
| </style> | |
| <link rel="stylesheet" href="/static/demos.css"> | |
| </head> | |
| <body> | |
| <div id="bar"></div><button class="totop" id="top" aria-label="Back to top">↑</button> | |
| <a class="skip" href="#projects">Skip to the projects</a> | |
| <nav><div class="wrap"><b>Everything I've built</b><div><button class="btn sm kbtn" id="palbtn" style="margin:0 6px 0 0;padding:6px 12px">Jump <kbd>Ctrl K</kbd></button><a href="#reveal">Reveal</a><a href="#projects">Projects</a><a href="#timeline">Timeline</a><a href="#homebase">Mellow</a><a href="#noor">Noor</a><a href="#qr">QR</a><a href="#news">News</a><a href="#tech">Tech</a><a href="#faq">FAQ</a><a href="#credits">Credits</a></div></div></nav> | |
| <header class="hero"><div class="orb a"></div><div class="orb b"></div><div class="wrap"> | |
| <div class="kick">The collection</div> | |
| <h1 class="silver">Everything<br>I've built.</h1> | |
| <p class="lead">15 projects, each one real and online. Open any of them, see how it works, and see how I made it.</p> | |
| <div class="cta"><a class="btn solid" href="#reveal">▶ Watch the reveal</a><a class="btn" href="#projects">Browse the projects</a></div> | |
| <div class="livesum" id="livesum">Checking which sites are awake…</div> | |
| <div class="stats"> | |
| <div class="stat"><b>15</b><span>projects</span></div> | |
| <div class="stat"><b>41</b><span>days to build them</span></div> | |
| <div class="stat"><b>258</b><span>commits</span></div> | |
| <div class="stat"><b>15</b><span>live links</span></div> | |
| </div> | |
| </div></header> | |
| <div class="ticker" aria-hidden="true"><div class="track"><span><b>🏡 Mellow</b>The family app: map, video calls, safety and screen time, honest about every bit.</span><span><b>🌙 Noor</b>A complete Quran app: read, listen, recite and get checked, even offline.</span><span><b>🏎️ VOID</b>The Hydra LTE242, a dream car you can watch, drive and fly through real Dammam.</span><span><b>🧭 Scout</b>A map that you can talk to.</span><span><b>📖 Unwritten</b>A life simulator where the AI types your story live.</span><span><b>🍳 Cookify</b>Recipes that already know your allergies.</span><span><b>✈️ Crosswind</b>A flight simulator that lives in a browser tab.</span><span><b>🍽️ Platter</b>A recipe box with 1,103 recipes.</span><span><b>🕵️ Alibi</b>A murder mystery where one of your friends is the killer.</span><span><b>🧳 Tripmate</b>A travel agent that respects your budget.</span><span><b>🎓 Cramly</b>Turn your notes into something you can actually learn.</span><span><b>🌱 Womanten</b>A confidence and habits coach with a push-up app lock.</span><span><b>🌀 Whatif</b>Type a what-if and watch the world change.</span><span><b>🤪 Totally Normal Website</b>A deliberately terrible website. Nothing makes sense.</span><span><b>🛠️ Cramly Control</b>The owner panel for Cramly.</span><span><b>🏡 Mellow</b>The family app: map, video calls, safety and screen time, honest about every bit.</span><span><b>🌙 Noor</b>A complete Quran app: read, listen, recite and get checked, even offline.</span><span><b>🏎️ VOID</b>The Hydra LTE242, a dream car you can watch, drive and fly through real Dammam.</span><span><b>🧭 Scout</b>A map that you can talk to.</span><span><b>📖 Unwritten</b>A life simulator where the AI types your story live.</span><span><b>🍳 Cookify</b>Recipes that already know your allergies.</span><span><b>✈️ Crosswind</b>A flight simulator that lives in a browser tab.</span><span><b>🍽️ Platter</b>A recipe box with 1,103 recipes.</span><span><b>🕵️ Alibi</b>A murder mystery where one of your friends is the killer.</span><span><b>🧳 Tripmate</b>A travel agent that respects your budget.</span><span><b>🎓 Cramly</b>Turn your notes into something you can actually learn.</span><span><b>🌱 Womanten</b>A confidence and habits coach with a push-up app lock.</span><span><b>🌀 Whatif</b>Type a what-if and watch the world change.</span><span><b>🤪 Totally Normal Website</b>A deliberately terrible website. Nothing makes sense.</span><span><b>🛠️ Cramly Control</b>The owner panel for Cramly.</span></div></div> | |
| <section id="reveal"><div class="wrap"> | |
| <h2>The <span class="silver">reveal</span></h2> | |
| <p class="sub">A short film of how I made each project. Arrow keys skip around, space pauses.</p> | |
| <div class="reveal-frame"><iframe src="/reveal.html" title="The reveal animation" loading="lazy" allowfullscreen></iframe></div> | |
| <div class="reveal-actions"><a class="btn" href="/reveal.html" target="_blank" rel="noopener">⛶ Open it on its own</a></div> | |
| </div></section> | |
| <section id="projects"><div class="wrap"> | |
| <h2>All the <span class="silver">projects</span></h2> | |
| <p class="sub">Every card has a playable demo, the three-step "how to use it" and the three-step "how I made it".</p> | |
| <div class="tools"> | |
| <input class="search" id="q" type="search" placeholder="Search projects ( / )" aria-label="Search projects" autocomplete="off"> | |
| <select class="sortsel" id="sort" aria-label="Sort projects"><option value="def">My order</option><option value="az">A to Z</option><option value="live">Online first</option></select> | |
| <button class="btn" id="wake" title="Free-tier sites sleep when nobody visits. This wakes them all up in the background.">⚡ Wake all sites</button> | |
| </div> | |
| <div class="chips" id="chips"> | |
| <button class="chip on" data-k="all">All</button><button class="chip" data-k="app">App</button><button class="chip" data-k="ai">AI</button><button class="chip" data-k="game">Games</button><button class="chip" data-k="tool">Tools</button> | |
| </div> | |
| <div class="none" id="none">No project matches that. Try a different word.</div> | |
| <div class="grid" id="grid"> | |
| <article class="card rv" style="--h: 18" id="p-homebase" data-id="homebase" data-n="mellow" data-k="app" data-t="mellow the family app: map, video calls, safety and screen time, honest about every bit. mellow (it started as homebase) is a family app for android, windows and the browser: see where everyone is, message with photos and voice notes, and make video calls that really ring. it has sos, safe walk, safety alerts, meals, plans, pocket money and homework, and it links to noor so the family reads the quran together. parents can see screen time and set limits, but it never feels controlling: everyone sees exactly what is shared, can pause it, and every lock is announced in the family chat. kotlin jetpack compose c# windows tracker webrtc flask postgres"> | |
| <span class="badge">Android · Windows · Web</span> | |
| <div class="shot art" style="--h: 18" aria-hidden="true"><span class="art-emoji">🏡</span><span class="art-name">Mellow</span><span class="art-tag">The family app: map, video calls, safety and screen time, honest about every bit.</span></div> | |
| <div class="top"><div class="tile">🏡</div><div><h3>Mellow</h3><div class="tag">The family app: map, video calls, safety and screen time, honest about every bit.</div><div class="live" data-live="homebase"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">Mellow (it started as Homebase) is a family app for Android, Windows and the browser: see where everyone is, message with photos and voice notes, and make video calls that really ring. It has SOS, Safe Walk, safety alerts, meals, plans, pocket money and homework, and it links to Noor so the family reads the Quran together. Parents can see screen time and set limits, but it never feels controlling: everyone sees exactly what is shared, can pause it, and every lock is announced in the family chat.</p> | |
| <div class="stack"><span>Kotlin</span><span>Jetpack Compose</span><span>C# Windows tracker</span><span>WebRTC</span><span>Flask</span><span>Postgres</span></div> | |
| <details><summary>How to use it</summary><ol><li>Open it in the browser, or install the Android app</li><li>Create a family, or join with a code</li><li>Share the map, call, and see screen time</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted a family app that never feels controlling, then renamed it Mellow with a calmer look</li><li>I set the rules: consent first, honest screen time, nothing secret. Claude helped write the Android app, the Windows tracker and the server</li><li>We tested on my real laptop and tablet, fixed what broke (grounding, ringing, two tabs), and I shipped it</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="homebase">▶ Try a demo</button> | |
| <a class="btn open" href="https://homebase-family.onrender.com" target="_blank" rel="noopener">Open the app ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/homebase" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="homebase" title="Copy a link to this project">🔗 Copy link</button> | |
| <a class="btn" href="https://homebase-family.onrender.com/download" title="Download the Android app (APK)">⬇ Android app</a> | |
| <button class="btn sm" data-qr="homebase" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 150" id="p-noor" data-id="noor" data-n="noor" data-k="app" data-t="noor a complete quran app: read, listen, recite and get checked, even offline. all 114 surahs with translation in 21 languages, tafsir, tajweed colours and word-by-word meanings, and 20 reciters you can save for offline listening. recite out loud and noor marks every mistake, or hide the text for tasmi' and get a score. sheikh aws, an ai helper, answers questions about prayer, fasting and duas, and families on mellow see what everyone read while parents give reading and memorizing tasks. prayer times, qibla, ramadan mode, adhkar and a quran platform game too. flask javascript pwa web speech service worker android app canvas game"> | |
| <span class="badge">Android · Web · Offline</span> | |
| <a class="shot" href="https://death242-noor.static.hf.space" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Noor"><img src="/static/shots/noor.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Noor"></a> | |
| <div class="top"><div class="tile">🌙</div><div><h3>Noor</h3><div class="tag">A complete Quran app: read, listen, recite and get checked, even offline.</div><div class="live" data-live="noor"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">All 114 surahs with translation in 21 languages, tafsir, tajweed colours and word-by-word meanings, and 20 reciters you can save for offline listening. Recite out loud and Noor marks every mistake, or hide the text for tasmi' and get a score. Sheikh Aws, an AI helper, answers questions about prayer, fasting and duas, and families on Mellow see what everyone read while parents give reading and memorizing tasks. Prayer times, Qibla, Ramadan mode, adhkar and a Quran platform game too.</p> | |
| <div class="stack"><span>Flask</span><span>JavaScript PWA</span><span>Web Speech</span><span>Service Worker</span><span>Android app</span><span>Canvas game</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Open it on your phone and pick a surah, or tap Listen for Maher Al-Muaiqly</li><li>Tap Recite to read aloud and get checked, or ask Sheikh Aws a question</li><li>Link Mellow so your family sees your streak and can give you tasks</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I asked for a Quran reader, then said: make it an app, white and green, that works without internet</li><li>I kept asking for the big features: Maher, recite and get corrected, tasmi' with a score, Ramadan mode, a Mario-style game, Sheikh Aws and family tasks in Mellow. Claude helped build them; the OpenAI API powers Sheikh Aws and the listening in the app</li><li>I tested it, asked for clearer text and a better design, added my key, and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="noor">▶ Try a demo</button> | |
| <a class="btn open" href="https://death242-noor.static.hf.space" target="_blank" rel="noopener">Open the app ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/quran" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="noor" title="Copy a link to this project">🔗 Copy link</button> | |
| <a class="btn" href="https://huggingface.co/datasets/Death242/downloads/resolve/main/noor.apk" title="Download the Android app (APK)">⬇ Android app</a> | |
| <button class="btn sm" data-qr="noor" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 355" id="p-void" data-id="void" data-n="void" data-k="app" data-t="void the hydra lte242, a dream car you can watch, drive and fly through real dammam. a black and red hypercar inspired by the mclaren 765lt, modelled entirely in code. watch a 44-second film synced to an original phonk track: it takes a 360 loop, launches off a ramp, lifts off on four thrusters and glides into the front seat's dashcam. then play it: free roam in al-tubaishi, dammam, rebuilt from real openstreetmap data with traffic, people, a fly button, missions and a garage. three.js web audio openstreetmap javascript static site"> | |
| <div class="shot art" style="--h: 355" aria-hidden="true"><span class="art-emoji">🏎️</span><span class="art-name">VOID</span><span class="art-tag">The Hydra LTE242, a dream car you can watch, drive and fly through real Dammam.</span></div> | |
| <div class="top"><div class="tile">🏎️</div><div><h3>VOID</h3><div class="tag">The Hydra LTE242, a dream car you can watch, drive and fly through real Dammam.</div><div class="live" data-live="void"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A black and red hypercar inspired by the McLaren 765LT, modelled entirely in code. Watch a 44-second film synced to an original phonk track: it takes a 360 loop, launches off a ramp, lifts off on four thrusters and glides into the front seat's dashcam. Then play it: free roam in al-Tubaishi, Dammam, rebuilt from real OpenStreetMap data with traffic, people, a Fly button, missions and a garage.</p> | |
| <div class="stack"><span>Three.js</span><span>Web Audio</span><span>OpenStreetMap</span><span>JavaScript</span><span>Static site</span></div> | |
| <details><summary>How to use it</summary><ol><li>Press Watch for the film, with sound on</li><li>Press Play, drive out of Tubaishi park, then press F to fly</li><li>Press Build to paint your own Hydra LTE242</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I showed Claude a short video of a car concept website and said: make one like it, but original and cooler</li><li>I picked the look (all black and red, like a McLaren 765LT), named it the Hydra LTE242, and asked for a loop, a ramp, thrusters, wings, a front seat and a dashcam. Claude helped build it in Three.js, with phonk-style music made in code</li><li>I asked for a game too: free roam in al-Tubaishi, Dammam, built from real map data, with traffic, people and a Fly button. Then I tested it and pushed until it felt right</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="void">▶ Try a demo</button> | |
| <a class="btn open" href="https://death242-void.static.hf.space" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/void" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="void" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="void" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 160" id="p-scout" data-id="scout" data-n="scout" data-k="ai" data-t="scout a map that you can talk to. a local-search map with an ai concierge. ask for what you want in plain words and it finds real places near you, using a local index of 103,000 saudi places so answers come back in about a second. flask leaflet overture maps openai"> | |
| <div class="shot art" style="--h: 160" aria-hidden="true"><span class="art-emoji">🧭</span><span class="art-name">Scout</span><span class="art-tag">A map that you can talk to.</span></div> | |
| <div class="top"><div class="tile">🧭</div><div><h3>Scout</h3><div class="tag">A map that you can talk to.</div><div class="live" data-live="scout"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A local-search map with an AI concierge. Ask for what you want in plain words and it finds real places near you, using a local index of 103,000 Saudi places so answers come back in about a second.</p> | |
| <div class="stack"><span>Flask</span><span>Leaflet</span><span>Overture Maps</span><span>OpenAI</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Type what you want, like a quiet cafe with wifi</li><li>The concierge searches real places near you</li><li>Tap a pin for hours and directions</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted a map I could talk to</li><li>I chose the data and the look. Claude helped build the place index and concierge</li><li>I tuned it until it was fast, then put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="scout">▶ Try a demo</button> | |
| <a class="btn open" href="https://scout-15t6.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/scout" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="scout" title="Copy a link to this project">🔗 Copy link</button> | |
| <a class="btn" href="https://scout-15t6.onrender.com/static/scout.apk" title="Download the Android app (APK)">⬇ Android app</a> | |
| <button class="btn sm" data-qr="scout" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 280" id="p-unwritten" data-id="unwritten" data-n="unwritten" data-k="game" data-t="unwritten a life simulator where the ai types your story live. a bitlife-style game. every year the ai writes an event for your life, word by word as you watch, and the choices you make change your money, health, relationships and ending. flask vanilla js openai streaming"> | |
| <a class="shot" href="https://unwritten-dulm.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Unwritten"><img src="/static/shots/unwritten.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Unwritten"></a> | |
| <div class="top"><div class="tile">📖</div><div><h3>Unwritten</h3><div class="tag">A life simulator where the AI types your story live.</div><div class="live" data-live="unwritten"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A BitLife-style game. Every year the AI writes an event for your life, word by word as you watch, and the choices you make change your money, health, relationships and ending.</p> | |
| <div class="stack"><span>Flask</span><span>Vanilla JS</span><span>OpenAI streaming</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Be born and pick a name</li><li>Watch each year's event type itself out</li><li>Choose, age up, and see how it ends</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I asked for BitLife, but written by AI</li><li>I designed the game. Claude helped with the rules and live typing; the OpenAI API writes each event</li><li>I played it, gave feedback, and we balanced it</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="unwritten">▶ Try a demo</button> | |
| <a class="btn open" href="https://unwritten-dulm.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/unwritten" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="unwritten" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="unwritten" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 25" id="p-cookify" data-id="cookify" data-n="cookify" data-k="tool" data-t="cookify recipes that already know your allergies. a recipe site with an allergy and diet engine, ingredient swaps, and a step-by-step cook mode, so what you see is only what you can safely eat. flask vanilla js openai"> | |
| <a class="shot" href="https://cookify-6auu.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Cookify"><img src="/static/shots/cookify.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Cookify"></a> | |
| <div class="top"><div class="tile">🍳</div><div><h3>Cookify</h3><div class="tag">Recipes that already know your allergies.</div><div class="live" data-live="cookify"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A recipe site with an allergy and diet engine, ingredient swaps, and a step-by-step cook mode, so what you see is only what you can safely eat.</p> | |
| <div class="stack"><span>Flask</span><span>Vanilla JS</span><span>OpenAI</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Tell it your allergies and diet</li><li>Search, or let the AI find recipes</li><li>Cook along in cook mode</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted recipes that respect allergies</li><li>I planned the features. Claude helped build the allergy engine; the OpenAI API powers AI search</li><li>I tested it and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="cookify">▶ Try a demo</button> | |
| <a class="btn open" href="https://cookify-6auu.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/cookify" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="cookify" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="cookify" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 32" id="p-crosswind" data-id="crosswind" data-n="crosswind" data-k="game" data-t="crosswind a flight simulator that lives in a browser tab. a flight sim with a real flight model: lift, stall, drag and thrust in si units on a 16 km generated island. four aircraft, hand-written sky, sea and clouds, no installs. three.js custom shaders flask"> | |
| <a class="shot" href="https://death242-crosswind.static.hf.space" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Crosswind"><img src="/static/shots/crosswind.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Crosswind"></a> | |
| <div class="top"><div class="tile">✈️</div><div><h3>Crosswind</h3><div class="tag">A flight simulator that lives in a browser tab.</div><div class="live" data-live="crosswind"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A flight sim with a real flight model: lift, stall, drag and thrust in SI units on a 16 km generated island. Four aircraft, hand-written sky, sea and clouds, no installs.</p> | |
| <div class="stack"><span>Three.js</span><span>Custom shaders</span><span>Flask</span></div> | |
| <details><summary>How to use it</summary><ol><li>Pick one of the four aircraft</li><li>Full throttle, then ease back at about 60 knots</li><li>Fly the island and land on the runway</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I said: make me a plane sim like MSFS</li><li>I picked the aircraft and the feel. Claude helped with the flight physics and the sky</li><li>I flew it, said what felt wrong, and we fixed it</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="crosswind">▶ Try a demo</button> | |
| <a class="btn open" href="https://death242-crosswind.static.hf.space" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/crosswind" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="crosswind" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="crosswind" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 90" id="p-platter" data-id="platter" data-n="platter" data-k="tool" data-t="platter a recipe box with 1,103 recipes. a three-pane recipe box in the style of plate it. diet filters, an ai helper, price estimates, a weekly planner, pantry, and it works offline. flask vanilla js service worker"> | |
| <a class="shot" href="https://platter-87b0.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Platter"><img src="/static/shots/platter.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Platter"></a> | |
| <div class="top"><div class="tile">🍽️</div><div><h3>Platter</h3><div class="tag">A recipe box with 1,103 recipes.</div><div class="live" data-live="platter"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A three-pane recipe box in the style of Plate It. Diet filters, an AI helper, price estimates, a weekly planner, pantry, and it works offline.</p> | |
| <div class="stack"><span>Flask</span><span>Vanilla JS</span><span>Service worker</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Browse more than a thousand recipes</li><li>Filter by diet, or ask the AI helper</li><li>Plan the week and get a shopping list</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I found an app I loved and wanted my own</li><li>I sent the screenshot. Claude helped rebuild it and add 1,103 recipes</li><li>I chose the extras and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="platter">▶ Try a demo</button> | |
| <a class="btn open" href="https://platter-87b0.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/platter" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="platter" title="Copy a link to this project">🔗 Copy link</button> | |
| <a class="btn" href="https://platter-87b0.onrender.com/static/platter.apk" title="Download the Android app (APK)">⬇ Android app</a> | |
| <button class="btn sm" data-qr="platter" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 340" id="p-alibi" data-id="alibi" data-n="alibi" data-k="game" data-t="alibi a murder mystery where one of your friends is the killer. a multiplayer party game. the ai writes a fresh case, one player is secretly the killer, and everyone plays on their own phone: question suspects, search rooms, and solve it before time runs out. flask polling openai"> | |
| <a class="shot" href="https://alibi-d9tn.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Alibi"><img src="/static/shots/alibi.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Alibi"></a> | |
| <div class="top"><div class="tile">🕵️</div><div><h3>Alibi</h3><div class="tag">A murder mystery where one of your friends is the killer.</div><div class="live" data-live="alibi"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A multiplayer party game. The AI writes a fresh case, one player is secretly the killer, and everyone plays on their own phone: question suspects, search rooms, and solve it before time runs out.</p> | |
| <div class="stack"><span>Flask</span><span>Polling</span><span>OpenAI</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Make a room and share the code</li><li>Roles are handed out in secret</li><li>Question, search and name the killer</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted a murder mystery where a friend is the killer</li><li>I came up with the rules. Claude helped build the multiplayer server; the OpenAI API writes each case</li><li>I played it with bots and friends, then shipped it</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="alibi">▶ Try a demo</button> | |
| <a class="btn open" href="https://alibi-d9tn.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/alibi" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="alibi" title="Copy a link to this project">🔗 Copy link</button> | |
| <a class="btn" href="https://alibi-d9tn.onrender.com/static/alibi.apk" title="Download the Android app (APK)">⬇ Android app</a> | |
| <button class="btn sm" data-qr="alibi" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 45" id="p-tripmate" data-id="tripmate" data-n="tripmate" data-k="ai" data-t="tripmate a travel agent that respects your budget. an ai trip planner. say where you are going and what you can spend and it researches flights and stays, checks the total against your budget, and shows the route on a map. flask leaflet openai + web search"> | |
| <div class="shot art" style="--h: 45" aria-hidden="true"><span class="art-emoji">🧳</span><span class="art-name">Tripmate</span><span class="art-tag">A travel agent that respects your budget.</span></div> | |
| <div class="top"><div class="tile">🧳</div><div><h3>Tripmate</h3><div class="tag">A travel agent that respects your budget.</div><div class="live" data-live="tripmate"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">An AI trip planner. Say where you are going and what you can spend and it researches flights and stays, checks the total against your budget, and shows the route on a map.</p> | |
| <div class="stack"><span>Flask</span><span>Leaflet</span><span>OpenAI + web search</span><span class="ai">AI: ChatGPT Agent Builder + OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Say where, when and your budget</li><li>The agent researches flights and stays</li><li>Compare, save, and export to your calendar</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I started in ChatGPT Agent Builder and built the agent myself</li><li>Claude taught me step by step, then helped move my agent into code with the OpenAI API</li><li>I added the extras I wanted and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="tripmate">▶ Try a demo</button> | |
| <a class="btn open" href="https://tripmate-yecg.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/tripmate" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="tripmate" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="tripmate" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 340" id="p-cramly" data-id="cramly" data-n="cramly" data-k="ai" data-t="cramly turn your notes into something you can actually learn. an ai study app. drop in notes, a pdf, slides or a photo and get a study plan, flashcards, quizzes and a tutor that knows your material, plus match and swipe games to make it stick. flask postgres openai"> | |
| <div class="shot art" style="--h: 340" aria-hidden="true"><span class="art-emoji">🎓</span><span class="art-name">Cramly</span><span class="art-tag">Turn your notes into something you can actually learn.</span></div> | |
| <div class="top"><div class="tile">🎓</div><div><h3>Cramly</h3><div class="tag">Turn your notes into something you can actually learn.</div><div class="live" data-live="cramly"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">An AI study app. Drop in notes, a PDF, slides or a photo and get a study plan, flashcards, quizzes and a tutor that knows your material, plus match and swipe games to make it stick.</p> | |
| <div class="stack"><span>Flask</span><span>Postgres</span><span>OpenAI</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Upload notes, a PDF or a photo</li><li>Get a plan, flashcards and quizzes</li><li>Ask the tutor and play the games</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted a study app that was actually good</li><li>I designed the study flow. Claude helped build it on the OpenAI API</li><li>I asked for more features each round until it felt right</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="cramly">▶ Try a demo</button> | |
| <a class="btn open" href="https://cramly-twz5.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/cramly" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="cramly" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="cramly" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 12" id="p-womanten" data-id="womanten" data-n="womanten" data-k="app" data-t="womanten a confidence and habits coach with a push-up app lock. an app for building confidence and healthy habits: an ai coach, a weekly plan, ai-made workout and food plans, habits, a journal, a cycle tracker and challenges with friends. on android, tiktok, instagram and youtube stay locked until you do a push-up on camera, and each push-up earns 10 scrolls. it never rates looks and never counts calories. kotlin ml kit pose detection flask openai"> | |
| <a class="shot" href="https://womanten.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Womanten"><img src="/static/shots/womanten.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Womanten"></a> | |
| <div class="top"><div class="tile">🌱</div><div><h3>Womanten</h3><div class="tag">A confidence and habits coach with a push-up app lock.</div><div class="live" data-live="womanten"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">An app for building confidence and healthy habits: an AI coach, a weekly plan, AI-made workout and food plans, habits, a journal, a cycle tracker and challenges with friends. On Android, TikTok, Instagram and YouTube stay locked until you do a push-up on camera, and each push-up earns 10 scrolls. It never rates looks and never counts calories.</p> | |
| <div class="stack"><span>Kotlin</span><span>ML Kit pose detection</span><span>Flask</span><span>OpenAI</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Open the site, or install the Android app</li><li>Pick what you want to work on and build your week</li><li>Lock your scrolling apps and earn scrolls with push-ups</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted an app like Critique AI, mixing the confidence coach and the habit tracker, and I named it Womanten</li><li>I decided what it must never do (rate looks, count calories) and what it must do: lock the scrolling apps until you do a push-up. Claude helped build it; the OpenAI API writes the plans and coaches</li><li>I asked for it to be more useful, tested it, fixed what felt wrong, and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="womanten">▶ Try a demo</button> | |
| <a class="btn open" href="https://womanten.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/womanten" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="womanten" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="womanten" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 25" id="p-whatif" data-id="whatif" data-n="whatif" data-k="ai" data-t="whatif type a what-if and watch the world change. an alternate-history storyteller. ask any what-if and the ai writes a timeline that fills in while you watch, the domino chain of cause and effect, who wins and loses and how believable it is. change any event to branch a new story, keep them all in your own multiverse, and share one as a link or a poster. flask openai streaming"> | |
| <a class="shot" href="https://whatif-kkq1.onrender.com" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Whatif"><img src="/static/shots/whatif.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Whatif"></a> | |
| <div class="top"><div class="tile">🌀</div><div><h3>Whatif</h3><div class="tag">Type a what-if and watch the world change.</div><div class="live" data-live="whatif"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">An alternate-history storyteller. Ask any what-if and the AI writes a timeline that fills in while you watch, the domino chain of cause and effect, who wins and loses and how believable it is. Change any event to branch a new story, keep them all in your own Multiverse, and share one as a link or a poster.</p> | |
| <div class="stack"><span>Flask</span><span>OpenAI</span><span>Streaming</span><span class="ai">AI: OpenAI API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Type a what-if or pick today's</li><li>Watch the timeline write itself</li><li>Change an event to branch it, then share the link</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I asked for website ideas and picked the what-if one</li><li>I decided it should write the story live, let you branch any event and share it as a link. Claude helped build it; the OpenAI API writes the stories</li><li>I tested it on real questions, fixed where the AI slipped, and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="whatif">▶ Try a demo</button> | |
| <a class="btn open" href="https://whatif-kkq1.onrender.com" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/whatif" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="whatif" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="whatif" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 310" id="p-nonsense" data-id="nonsense" data-n="totally normal website" data-k="game" data-t="totally normal website a deliberately terrible website. nothing makes sense. a joke site with a bad ui on purpose: a runaway button, a potato to chat with, a calculator where 2+2 is fish, a download bar for more ram and a dozen more toys. it opens with a photosensitivity warning and has a calm mode with no flashing or movement. flask vanilla js web audio"> | |
| <a class="shot" href="https://death242-totally-normal-website.static.hf.space" target="_blank" rel="noopener" tabindex="-1" aria-label="Open Totally Normal Website"><img src="/static/shots/nonsense.jpg" width="960" height="520" loading="lazy" decoding="async" alt="A look at Totally Normal Website"></a> | |
| <div class="top"><div class="tile">🤪</div><div><h3>Totally Normal Website</h3><div class="tag">A deliberately terrible website. Nothing makes sense.</div><div class="live" data-live="nonsense"><i class="dot"></i><span>checking…</span></div></div></div> | |
| <p class="about">A joke site with a bad UI on purpose: a runaway button, a potato to chat with, a calculator where 2+2 is fish, a download bar for more RAM and a dozen more toys. It opens with a photosensitivity warning and has a Calm mode with no flashing or movement.</p> | |
| <div class="stack"><span>Flask</span><span>Vanilla JS</span><span>Web Audio</span></div> | |
| <details><summary>How to use it</summary><ol><li>Read the warning and pick Calm mode or the chaos</li><li>Press anything. Most things do something</li><li>Try to catch the button. It gives up eventually</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted the worst website I could think of, on purpose</li><li>I chose every bad idea: the colours, the runaway button, the potato, the nonsense answers</li><li>I asked for a seizure warning and a Calm mode, tested the buttons until they worked, and put it online</li></ol></details> | |
| <div class="links"> | |
| <button class="btn solid demo-btn" type="button" data-demo="nonsense">▶ Try a demo</button> | |
| <a class="btn open" href="https://death242-totally-normal-website.static.hf.space" target="_blank" rel="noopener">Open the site ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/totally-normal-website" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="nonsense" title="Copy a link to this project">🔗 Copy link</button> | |
| <button class="btn sm" data-qr="nonsense" title="Show a QR code to open it on a phone">▦ QR</button> | |
| </div> | |
| </article> | |
| <article class="card rv" style="--h: 0" id="p-control" data-id="control" data-n="cramly control" data-k="tool" data-t="cramly control the owner panel for cramly. a separate private panel for running cramly: see accounts, send a personal message with a unique link, ban or time out an account, and flip a kill switch. owner only. flask admin api"> | |
| <span class="badge">owner only</span> | |
| <div class="top"><div class="tile">🛠️</div><div><h3>Cramly Control</h3><div class="tag">The owner panel for Cramly.</div></div></div> | |
| <p class="about">A separate private panel for running Cramly: see accounts, send a personal message with a unique link, ban or time out an account, and flip a kill switch. Owner only.</p> | |
| <div class="stack"><span>Flask</span><span>Admin API</span></div> | |
| <details><summary>How to use it</summary><ol><li>Sign in with the owner password</li><li>See accounts and message people</li><li>Ban, time out, or use the kill switch</li></ol></details> | |
| <details><summary>How I made it</summary><ol><li>I wanted a private owner panel for Cramly</li><li>I decided what it could do. Claude helped build it</li><li>I set the password and put it online</li></ol></details> | |
| <div class="links"> | |
| <a class="btn open" href="https://cramly-control.onrender.com" target="_blank" rel="noopener">Open the panel ↗</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/cramly-control" target="_blank" rel="noopener">Code</a> | |
| <button class="btn sm" data-copy="control" title="Copy a link to this project">🔗 Copy link</button> | |
| </div> | |
| </article> | |
| </div> | |
| </div></section> | |
| <section id="timeline"><div class="wrap"> | |
| <h2>How fast I <span class="silver">built it</span></h2> | |
| <p class="sub">15 projects in 41 days, many of them at the same time. Each bar runs from a project's first commit to its last, read straight from its git history on 2026-10-24.</p> | |
| <div class="gantt rv" role="list" aria-label="Timeline of when each project was built" style="--week: 17.073%"> | |
| <div class="g-axis" aria-hidden="true"><span class="g-lab"></span><div class="g-ticks"><span style="left: 0.0%">Sep 14</span><span style="left: 17.07%">Sep 21</span><span style="left: 34.15%">Sep 28</span><span style="left: 51.22%">Oct 5</span><span style="left: 68.29%">Oct 12</span><span style="left: 85.37%">Oct 19</span></div></div> | |
| <div class="g-row" role="listitem" style="--h: 160"> | |
| <a class="g-name" href="#p-scout"><i>🧭</i><span>Scout</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 0.0%; width: 80.49%" title="Scout: 25 commits, first 2026-09-14, last 2026-10-16"><b>25 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 280"> | |
| <a class="g-name" href="#p-unwritten"><i>📖</i><span>Unwritten</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 12.2%; width: 53.66%" title="Unwritten: 12 commits, first 2026-09-19, last 2026-10-10"><b>12 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 32"> | |
| <a class="g-name" href="#p-crosswind"><i>✈️</i><span>Crosswind</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 19.51%; width: 46.34%" title="Crosswind: 12 commits, first 2026-09-22, last 2026-10-10"><b>12 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 25"> | |
| <a class="g-name" href="#p-cookify"><i>🍳</i><span>Cookify</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 24.39%; width: 41.46%" title="Cookify: 10 commits, first 2026-09-24, last 2026-10-10"><b>10 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 90"> | |
| <a class="g-name" href="#p-platter"><i>🍽️</i><span>Platter</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 26.83%; width: 53.66%" title="Platter: 29 commits, first 2026-09-25, last 2026-10-16"><b>29 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 340"> | |
| <a class="g-name" href="#p-alibi"><i>🕵️</i><span>Alibi</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 29.27%; width: 51.22%" title="Alibi: 32 commits, first 2026-09-26, last 2026-10-16"><b>32 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 45"> | |
| <a class="g-name" href="#p-tripmate"><i>🧳</i><span>Tripmate</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 31.71%; width: 34.15%" title="Tripmate: 20 commits, first 2026-09-27, last 2026-10-10"><b>20 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 0"> | |
| <a class="g-name" href="#p-control"><i>🛠️</i><span>Cramly Control</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 60.98%; width: 17.07%" title="Cramly Control: 16 commits, first 2026-10-09, last 2026-10-15"><b>16 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 340"> | |
| <a class="g-name" href="#p-cramly"><i>🎓</i><span>Cramly</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 60.98%; width: 17.07%" title="Cramly: 20 commits, first 2026-10-09, last 2026-10-15"><b>20 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 18"> | |
| <a class="g-name" href="#p-homebase"><i>🏡</i><span>Mellow</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 63.41%; width: 21.95%" title="Mellow: 52 commits, first 2026-10-10, last 2026-10-18"><b>52 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 310"> | |
| <a class="g-name" href="#p-nonsense"><i>🤪</i><span>Totally Normal Website</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 70.73%; width: 2.44%" title="Totally Normal Website: 2 commits, first 2026-10-13, last 2026-10-13"><b></b></span><span class="g-note" style="left: 73.17%">2 commits</span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 12"> | |
| <a class="g-name" href="#p-womanten"><i>🌱</i><span>Womanten</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 70.73%; width: 2.44%" title="Womanten: 8 commits, first 2026-10-13, last 2026-10-13"><b></b></span><span class="g-note" style="left: 73.17%">8 commits</span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 25"> | |
| <a class="g-name" href="#p-whatif"><i>🌀</i><span>Whatif</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 75.61%; width: 2.44%" title="Whatif: 1 commit, first 2026-10-15, last 2026-10-15"><b></b></span><span class="g-note" style="left: 78.05%">1 commit</span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 150"> | |
| <a class="g-name" href="#p-noor"><i>🌙</i><span>Noor</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 82.93%; width: 17.07%" title="Noor: 14 commits, first 2026-10-18, last 2026-10-24"><b>14 commits</b></span></div> | |
| </div> | |
| <div class="g-row" role="listitem" style="--h: 355"> | |
| <a class="g-name" href="#p-void"><i>🏎️</i><span>VOID</span></a> | |
| <div class="g-track"><span class="g-bar" style="left: 95.12%; width: 4.88%" title="VOID: 5 commits, first 2026-10-23, last 2026-10-24"><b></b></span><span class="g-note" style="right: 4.8799999999999955%; margin-right: 8px; margin-left: 0">5 commits</span></div> | |
| </div> | |
| </div> | |
| <p class="g-foot">Commits are a rough measure, but they are real: 258 of them, from Sep 14 to the latest one.</p> | |
| </div></section> | |
| <section id="homebase"><div class="wrap"><div class="feature rv"> | |
| <div class="kick" style="margin-bottom:12px">Featured · Android, Windows and web</div> | |
| <h2>Mellow: <span class="silver">stay close,<br>stay yourself.</span></h2> | |
| <p class="sub">A family app that shows where everyone is, lets you message, and makes calls that ring in their own window. Parents see each child's screen time today and can help with limits. Nobody should feel watched: the person being located always sees exactly what is shared, can pause it, and chooses what parents can do.</p> | |
| <div class="promise"> | |
| <div><b>What the family sees</b>Where you are while sharing is on, your battery, your screen time today (minutes playing or watching, never homework), and the messages you send.</div> | |
| <div><b>What parents can do</b>Lock a device (never more than 4 hours a day) or ground certain apps with a minute's warning. Every lock and grounding is announced in the family chat.</div> | |
| <div><b>What it never does</b>Hide itself, read your other apps or messages, turn on your mic or camera by itself, or secretly change your screen time.</div> | |
| <div><b>You are in control</b>Pause any time, set quiet hours, say "not now" to a location request, and switch off any parent permission from your own panel.</div> | |
| </div> | |
| <div class="fgrid"><div><i>📍</i><b>Shared map</b><span>Everyone who is sharing shows up, parents too. Offline? You still see the last place.</span></div><div><i>📹</i><b>Video calls that ring</b><span>Voice and video calls on phones and laptops, with a real ringing window, not a quiet notification.</span></div><div><i>🆘</i><b>SOS and Safe Walk</b><span>Hold for SOS and everyone gets your live location. Safe Walk tells the family if you do not arrive.</span></div><div><i>📖</i><b>Quran with Noor</b><span>See what everyone read in Noor, and give reading and memorizing tasks.</span></div><div><i>⏱️</i><b>Honest screen time</b><span>Counts playing and watching per app, never homework. The child sees exactly what parents see.</span></div><div><i>🔒</i><b>Locks, 4 hours a day max</b><span>A parent can lock a device; the family chat announces it and the child can ask to be unlocked.</span></div><div><i>🚫</i><b>Ground certain apps</b><span>Pick real apps from the child's computer, get a one-minute warning, and only that app closes.</span></div><div><i>💻</i><b>Windows tracker</b><span>A small tray app with its own pop-ups that updates itself and works for two brothers on one laptop.</span></div><div><i>✅</i><b>Jobs and points</b><span>Parents set jobs, children tick them off, parents approve them for points.</span></div><div><i>🙋</i><b>Ask, don't track</b><span>"Where are you?" is a request the child can answer or say not now to.</span></div><div><i>🏡</i><b>Home area</b><span>Know when someone gets home, using a place the family sets together.</span></div></div> | |
| <p class="sub" style="margin-top:24px">Setup: open it in the browser and add it to your home screen (it always stays up to date), or install the Android app. A parent creates the family, then everyone else joins with an 8-character code. On Windows, link the tracker with a 6-digit code.</p> | |
| <div class="cta" style="justify-content:flex-start"> | |
| <a class="btn solid" href="https://homebase-family.onrender.com/app" target="_blank" rel="noopener">Open on your laptop ↗</a><a class="btn" href="https://homebase-family.onrender.com/update" target="_blank" rel="noopener">Get the app</a> | |
| <a class="btn" href="https://github.com/awsaalibdeh-a11y/homebase" target="_blank" rel="noopener">Read the code</a> | |
| </div> | |
| </div></div></section> | |
| <section id="noor"><div class="wrap"><div class="feature rv" style="--h: 150"> | |
| <div class="kick" style="margin-bottom:12px">Featured · Android, web and offline</div> | |
| <h2>Noor: <span class="silver">the Quran,<br>for the whole family.</span></h2> | |
| <p class="sub">Read, listen and recite with a clear Quran font, Maher Al-Muaiqly and 19 more reciters. Noor listens while you recite and marks every mistake, hides the text for tasmi' and scores you, and remembers your streak. Almost everything works without internet.</p> | |
| <div class="fgrid"><div><i>🎙</i><b>Recite and get checked</b><span>Read aloud and every word turns green or red. Tasmi' hides the text and scores you at the end.</span></div><div><i>🎧</i><b>20 reciters, offline</b><span>Maher Al-Muaiqly by default. Download any surah and listen with no internet, with a sleep timer and a memorization loop.</span></div><div><i>🎨</i><b>Tajweed and word by word</b><span>Colour-coded tajweed rules, and tap any word for its meaning and its sound.</span></div><div><i>🌍</i><b>21 languages</b><span>Saheeh International English built in, plus Urdu, French, Turkish, Indonesian, Spanish and more.</span></div><div><i>شيخ</i><b>Sheikh Aws</b><span>An AI helper for prayer, fasting and duas. Quran verses are shown from the real text, never from memory.</span></div><div><i>🕌</i><b>Prayer times and Qibla</b><span>Calculated on the phone, so they work offline. A compass points to Makkah.</span></div><div><i>🌙</i><b>Ramadan mode</b><span>Suhoor and iftar countdown, a juz a day, fasting and taraweeh trackers, and the duas.</span></div><div><i>👪</i><b>Read as a family</b><span>Linked to Mellow: see who read what, and parents give reading and memorizing tasks.</span></div><div><i>🎮</i><b>Noor Quest</b><span>A Mario-style platform game where every ؟ block asks a question about the Quran.</span></div></div> | |
| <div class="cta" style="justify-content:flex-start;margin-top:24px"> | |
| <a class="btn solid" href="https://death242-noor.static.hf.space" target="_blank" rel="noopener">Open Noor ↗</a><a class="btn" href="https://huggingface.co/datasets/Death242/downloads/resolve/main/noor.apk">Get the Android app</a> | |
| <button class="btn" type="button" data-demo="noor">▶ Try a demo</button><a class="btn" href="https://github.com/awsaalibdeh-a11y/quran" target="_blank" rel="noopener">Read the code</a> | |
| </div> | |
| </div></div></section> | |
| <section id="qr"><div class="wrap"> | |
| <h2>Take it <span class="silver">with you</span></h2> | |
| <p class="sub">Point a phone camera at the code to open it there. Pick a project to get its own code, or save the poster.</p> | |
| <div class="qrbox rv"> | |
| <div class="qrimg"><img id="qrimg" src="/qr/showcase.svg" width="280" height="280" alt="QR code for this showcase"></div> | |
| <div class="qrside"> | |
| <select class="sortsel" id="qrsel" aria-label="Which link the QR code opens"><option value="">This showcase</option><option value="homebase">🏡 Mellow (website)</option><option value="homebase-app">🏡 Mellow (Android app)</option><option value="noor">🌙 Noor (website)</option><option value="noor-app">🌙 Noor (Android app)</option><option value="void">🏎️ VOID (website)</option><option value="scout">🧭 Scout (website)</option><option value="scout-app">🧭 Scout (Android app)</option><option value="unwritten">📖 Unwritten (website)</option><option value="cookify">🍳 Cookify (website)</option><option value="crosswind">✈️ Crosswind (website)</option><option value="platter">🍽️ Platter (website)</option><option value="platter-app">🍽️ Platter (Android app)</option><option value="alibi">🕵️ Alibi (website)</option><option value="alibi-app">🕵️ Alibi (Android app)</option><option value="tripmate">🧳 Tripmate (website)</option><option value="cramly">🎓 Cramly (website)</option><option value="womanten">🌱 Womanten (website)</option><option value="whatif">🌀 Whatif (website)</option><option value="nonsense">🤪 Totally Normal Website (website)</option></select> | |
| <div class="qrurl" id="qrurl">death242-showcase.static.hf.space</div> | |
| <div class="cta" style="justify-content:flex-start"><a class="btn solid" id="qrdl" href="/qr/showcase.svg" download>Save the code</a><a class="btn" href="/static/showcase-qr.png" download>Save the poster</a></div> | |
| </div> | |
| </div> | |
| </div></section> | |
| <section id="news"><div class="wrap"> | |
| <h2>What's <span class="silver">new</span></h2> | |
| <p class="sub">The latest things that actually shipped.</p> | |
| <div class="news"><div><b>Noor</b>Families on Mellow read together: everyone's streak and last ayah, and parents give reading and memorizing tasks.</div><div><b>Noor</b>Sheikh Aws, an AI helper for prayer, fasting and duas, with every Quran verse shown from the real text.</div><div><b>Noor</b>Recite and get checked, tasmi' with a score, Maher and 19 more reciters, tajweed colours and 21 languages.</div><div><b>Noor</b>Noor Quest, a jump-and-run game where every ؟ block is a Quran question.</div><div><b>Mellow</b>Homebase is now Mellow: video calls, SOS, Safe Walk, safety alerts, meals and a calmer look.</div><div><b>Homebase</b>Two tabs everywhere, a ringing call window on Windows, and a built-in update guide for the old app.</div><div><b>Homebase</b>Parents see each child's screen time today on the Family tab, on the web and on Android.</div><div><b>Homebase</b>Grounding fixed so only the grounded app closes. The tracker now updates itself.</div><div><b>Homebase</b>Windows tracker, locks with a 4-hour daily cap, grounding with a one-minute warning, jobs and points.</div><div><b>Cramly</b>One Cramly account works across every app, with owner switches for bans, time-outs and a kill switch.</div><div><b>Showcase</b>The reveal got sound, live online/waking status, search and a share image.</div></div> | |
| </div></section> | |
| <section id="tech"><div class="wrap"> | |
| <h2>What I <span class="silver">used</span></h2> | |
| <p class="sub">Counted from the projects above. The bigger the number, the more projects use it.</p> | |
| <div class="techs"><div class="tc" title="Mellow, Noor, Scout, Unwritten, Cookify, Crosswind, Platter, Alibi, Tripmate, Cramly, Womanten, Whatif, Totally Normal Website, Cramly Control"><b>14</b><span>Flask</span></div><div class="tc" title="Scout, Cookify, Alibi, Cramly, Womanten, Whatif"><b>6</b><span>OpenAI</span></div><div class="tc" title="Unwritten, Cookify, Platter, Totally Normal Website"><b>4</b><span>Vanilla JS</span></div><div class="tc" title="Mellow, Womanten"><b>2</b><span>Kotlin</span></div><div class="tc" title="Scout, Tripmate"><b>2</b><span>Leaflet</span></div><div class="tc" title="Mellow, Cramly"><b>2</b><span>Postgres</span></div><div class="tc" title="VOID, Crosswind"><b>2</b><span>Three.js</span></div><div class="tc" title="VOID, Totally Normal Website"><b>2</b><span>Web Audio</span></div><div class="tc" title="Cramly Control"><b>1</b><span>Admin API</span></div><div class="tc" title="Noor"><b>1</b><span>Android app</span></div><div class="tc" title="Mellow"><b>1</b><span>C# Windows tracker</span></div><div class="tc" title="Noor"><b>1</b><span>Canvas game</span></div><div class="tc" title="Crosswind"><b>1</b><span>Custom shaders</span></div><div class="tc" title="VOID"><b>1</b><span>JavaScript</span></div><div class="tc" title="Noor"><b>1</b><span>JavaScript PWA</span></div><div class="tc" title="Mellow"><b>1</b><span>Jetpack Compose</span></div><div class="tc" title="Womanten"><b>1</b><span>ML Kit pose detection</span></div><div class="tc" title="Tripmate"><b>1</b><span>OpenAI + web search</span></div><div class="tc" title="Unwritten"><b>1</b><span>OpenAI streaming</span></div><div class="tc" title="VOID"><b>1</b><span>OpenStreetMap</span></div><div class="tc" title="Scout"><b>1</b><span>Overture Maps</span></div><div class="tc" title="Alibi"><b>1</b><span>Polling</span></div><div class="tc" title="Noor"><b>1</b><span>Service Worker</span></div><div class="tc" title="Platter"><b>1</b><span>Service worker</span></div><div class="tc" title="VOID"><b>1</b><span>Static site</span></div><div class="tc" title="Whatif"><b>1</b><span>Streaming</span></div><div class="tc" title="Noor"><b>1</b><span>Web Speech</span></div><div class="tc" title="Mellow"><b>1</b><span>WebRTC</span></div></div> | |
| </div></section> | |
| <section id="faq"><div class="wrap"> | |
| <h2>Questions <span class="silver">people ask</span></h2> | |
| <div class="faq" style="margin-top:24px"><details><summary>Are these real?</summary><p>Yes. Every card links to a live site you can open now. Free-tier sites sleep when nobody visits, so the first load can take up to 30 seconds. The Wake all sites button warms them up.</p></details><details><summary>Who made them?</summary><p>I did: the ideas, the choices and the testing. Claude helped me write and test the code, and some projects use the OpenAI API for their AI.</p></details><details><summary>What is Noor?</summary><p>A Quran app for the whole family: read, listen, recite and get checked, with tafsir, prayer times and Ramadan mode. Almost everything works without internet.</p></details><details><summary>Is Sheikh Aws a real sheikh?</summary><p>No. Sheikh Aws is an AI helper inside Noor. It cites the Quran and hadith, says where scholars differ, and tells you to ask a qualified scholar for serious personal questions.</p></details><details><summary>Is Mellow (Homebase) spying on kids?</summary><p>No. The child sees exactly what the family sees, can pause sharing, and every lock or grounding is announced in the family chat. It never hides itself.</p></details><details><summary>Why does Homebase count screen time?</summary><p>So a parent can talk about it with real numbers. It counts playing and watching, never homework, and the minutes are never changed in secret.</p></details><details><summary>Can I use them on my phone?</summary><p>Yes. Everything works in a phone browser, and most can be added to the home screen.</p></details></div> | |
| </div></section> | |
| <section id="credits"><div class="wrap credits"> | |
| <div class="kick">Credits</div> | |
| <div class="mebig silver">Me</div> | |
| <p class="say">Every idea, design decision, test and "make it better". I made these.</p> | |
| <div class="crow"> | |
| <div class="helper"><b>Claude</b><span>Anthropic's AI, helped me write and test the code and get it online.</span></div><div class="tool"><b>ChatGPT Agent Builder</b><span>Where I first built the Tripmate agent and learned how agents work.</span></div><div class="tool"><b>OpenAI API</b><span>Powers the AI inside Noor, Scout, Unwritten, Cookify, Platter, Alibi, Tripmate, Cramly, Womanten and Whatif.</span></div> | |
| </div> | |
| </div></section> | |
| <div id="pal" role="dialog" aria-modal="true" aria-label="Jump to a project"><div class="box"> | |
| <input id="palq" placeholder="Jump to a project or section..." autocomplete="off"> | |
| <ul id="pall"></ul> | |
| <div class="hint"><kbd>↑</kbd> <kbd>↓</kbd> to move · <kbd>Enter</kbd> to open · <kbd>Esc</kbd> to close</div> | |
| </div></div> | |
| <footer><div class="wrap">Built one idea at a time. Free-tier sites can take a few seconds to wake up on the first visit.</div></footer> | |
| <script> | |
| const chips = document.getElementById("chips"), q = document.getElementById("q"); | |
| let kind = "all"; | |
| function apply() { | |
| const w = q.value.trim().toLowerCase(); let shown = 0; | |
| document.querySelectorAll("#grid .card").forEach(c => { const ok = (kind === "all" || c.dataset.k === kind) && (!w || c.dataset.t.includes(w)); c.classList.toggle("hide", !ok); shown += ok; }); | |
| document.getElementById("none").classList.toggle("on", !shown); | |
| } | |
| chips.addEventListener("click", e => { const b = e.target.closest(".chip"); if (!b) return; chips.querySelectorAll(".chip").forEach(c => c.classList.toggle("on", c === b)); kind = b.dataset.k; apply(); }); | |
| q.addEventListener("input", apply); | |
| addEventListener("keydown", e => { if (e.key === "/" && document.activeElement !== q && !/input|textarea/i.test(document.activeElement.tagName)) { e.preventDefault(); q.focus(); } else if (e.key === "Escape" && document.activeElement === q) { q.value = ""; apply(); q.blur(); } }); | |
| /* live status: green when a site answers, amber while it is waking up */ | |
| const WORDS = { online: "Online", waking: "Waking up…", down: "Having trouble" }; | |
| async function status(tries = 0) { | |
| let pending = 0; | |
| try { | |
| const d = await (await fetch("/api/status")).json(); | |
| document.querySelectorAll("[data-live]").forEach(el => { const st = d.status[el.dataset.live]; if (st) STATE[el.dataset.live] = st.state; if (!st) { pending++; return; } el.querySelector(".dot").className = "dot " + st.state; el.querySelector("span").textContent = WORDS[st.state] + (st.state === "online" ? " · " + (st.ms < 1000 ? st.ms + " ms" : (st.ms / 1000).toFixed(1) + " s") : ""); if (st.state !== "online") pending++; }); | |
| const all = document.querySelectorAll("[data-live]").length, on = Object.values(STATE).filter(v => v === "online").length; | |
| if (Object.keys(STATE).length) document.getElementById("livesum").innerHTML = on === all ? "<b>All " + all + "</b> sites are online right now." : "<b>" + on + " of " + all + "</b> sites are online right now. The rest are waking up."; | |
| } catch (e) { pending = 1; } | |
| if (pending && tries < 12) setTimeout(() => status(tries + 1), 6000); | |
| } | |
| const STATE = {}; | |
| status(); | |
| document.getElementById("wake").addEventListener("click", e => { | |
| const urls = [...document.querySelectorAll('.links a[href^="http"]')].map(a => a.href).filter(h => !h.includes("github.com")); | |
| urls.forEach(u => fetch(u, { mode: "no-cors" }).catch(() => {})); | |
| e.target.textContent = "✔ Waking " + urls.length + " sites…"; setTimeout(() => status(), 8000); setTimeout(() => { e.target.innerHTML = "⚡ Wake all sites"; }, 6000); | |
| }); | |
| /* sort, deep links, copy link, progress bar, back to top */ | |
| const grid = document.getElementById("grid"), order = [...grid.children]; | |
| document.getElementById("sort").addEventListener("change", e => { | |
| const v = e.target.value, cards = [...order]; | |
| if (v === "az") cards.sort((a, b) => a.dataset.n.localeCompare(b.dataset.n)); | |
| if (v === "live") cards.sort((a, b) => (STATE[b.dataset.id] === "online") - (STATE[a.dataset.id] === "online")); | |
| cards.forEach(c => grid.appendChild(c)); | |
| }); | |
| function openCard(id) { const c = document.getElementById("p-" + id); if (!c) return; c.scrollIntoView({ block: "center" }); c.classList.remove("flash"); void c.offsetWidth; c.classList.add("flash"); } | |
| if (location.hash.startsWith("#p-")) setTimeout(() => openCard(location.hash.slice(3)), 300); | |
| document.addEventListener("click", e => { | |
| const b = e.target.closest("[data-copy]"); if (!b) return; | |
| const url = location.origin + location.pathname + "#p-" + b.dataset.copy, old = b.innerHTML; | |
| (navigator.clipboard ? navigator.clipboard.writeText(url) : Promise.reject()).then(() => { b.textContent = "Copied"; }, () => { prompt("Copy this link", url); }).finally(() => setTimeout(() => { b.innerHTML = old; }, 1500)); | |
| }); | |
| const bar = document.getElementById("bar"), topb = document.getElementById("top"); | |
| addEventListener("scroll", () => { const h = document.documentElement; bar.style.width = (h.scrollTop / Math.max(1, h.scrollHeight - innerHeight) * 100) + "%"; topb.classList.toggle("on", h.scrollTop > 900); }, { passive: true }); | |
| topb.addEventListener("click", () => scrollTo({ top: 0, behavior: "smooth" })); | |
| /* ---- tough pass JS ---- */ | |
| document.documentElement.classList.add("js"); | |
| const calm = matchMedia("(prefers-reduced-motion: reduce)").matches; | |
| /* scroll reveal, with a safety net so nothing can stay hidden */ | |
| const rv = document.querySelectorAll(".rv"); | |
| if ("IntersectionObserver" in window && !calm) { | |
| const io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }), { threshold: .08 }); | |
| rv.forEach((el, i) => { el.style.transitionDelay = Math.min(i % 4, 3) * 70 + "ms"; io.observe(el); }); | |
| setTimeout(() => rv.forEach(el => el.classList.add("in")), 4000); | |
| } else rv.forEach(el => el.classList.add("in")); | |
| /* count the stats up */ | |
| document.querySelectorAll(".stat b").forEach(b => { | |
| const n = parseInt(b.textContent, 10); if (!n || calm) return; let t0 = null; b.textContent = "0"; | |
| const step = t => { t0 = t0 || t; const k = Math.min(1, (t - t0) / 1100); b.textContent = Math.round(n * (1 - Math.pow(1 - k, 3))); if (k < 1) requestAnimationFrame(step); }; | |
| requestAnimationFrame(step); | |
| }); | |
| /* card glow follows the mouse, with a small 3D tilt */ | |
| if (!calm && matchMedia("(hover: hover)").matches) { | |
| document.querySelectorAll(".card").forEach(c => { | |
| c.addEventListener("mousemove", e => { | |
| const r = c.getBoundingClientRect(), x = e.clientX - r.left, y = e.clientY - r.top; | |
| c.style.setProperty("--mx", x + "px"); c.style.setProperty("--my", y + "px"); | |
| c.style.transform = "perspective(900px) rotateX(" + ((y / r.height - .5) * -4) + "deg) rotateY(" + ((x / r.width - .5) * 5) + "deg) translateY(-3px)"; | |
| }); | |
| c.addEventListener("mouseleave", () => { c.style.transform = ""; }); | |
| }); | |
| } | |
| /* command palette: Ctrl or Cmd + K */ | |
| const pal = document.getElementById("pal"), palq = document.getElementById("palq"), pall = document.getElementById("pall"); | |
| const ITEMS = [...document.querySelectorAll("#grid .card")].map(c => ({ id: c.dataset.id, name: c.querySelector("h3").textContent, em: c.querySelector(".tile").textContent, tag: c.querySelector(".tag").textContent, link: (c.querySelector(".links a.solid") || {}).href })) | |
| .concat([["#reveal", "Watch the reveal", "▶"], ["#homebase", "Mellow features", "🏡"], ["#noor", "Noor features", "🌙"], ["#qr", "QR codes", "▦"], ["#news", "What's new", "📰"], ["#tech", "What I used", "🛠️"], ["#faq", "Common questions", "❓"], ["#credits", "Credits", "⭐"]].map(([h, n, e]) => ({ name: n, em: e, tag: "section", hash: h }))); | |
| let sel = 0, shown = []; | |
| function palRender() { | |
| const w = palq.value.trim().toLowerCase(); | |
| shown = ITEMS.filter(i => !w || (i.name + " " + i.tag).toLowerCase().includes(w)); | |
| sel = Math.min(sel, Math.max(0, shown.length - 1)); | |
| pall.innerHTML = ""; | |
| shown.forEach((i, k) => { const li = document.createElement("li"); li.className = k === sel ? "sel" : ""; const e = document.createElement("span"); e.textContent = i.em; const n = document.createElement("span"); n.textContent = i.name; const t = document.createElement("small"); t.textContent = i.hash ? "section" : (i.link ? "open site" : "card"); li.append(e, n, t); li.onclick = () => palGo(i); pall.appendChild(li); }); | |
| } | |
| function palGo(i) { palClose(); if (i.hash) location.hash = i.hash; else if (i.link) window.open(i.link, "_blank", "noopener"); else openCard(i.id); } | |
| function palOpen() { pal.classList.add("on"); palq.value = ""; sel = 0; palRender(); palq.focus(); } | |
| function palClose() { pal.classList.remove("on"); } | |
| document.getElementById("palbtn").addEventListener("click", palOpen); | |
| pal.addEventListener("click", e => { if (e.target === pal) palClose(); }); | |
| palq.addEventListener("input", () => { sel = 0; palRender(); }); | |
| addEventListener("keydown", e => { | |
| if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") { e.preventDefault(); pal.classList.contains("on") ? palClose() : palOpen(); return; } | |
| if (!pal.classList.contains("on")) return; | |
| if (e.key === "Escape") palClose(); | |
| else if (e.key === "ArrowDown") { e.preventDefault(); sel = Math.min(shown.length - 1, sel + 1); palRender(); } | |
| else if (e.key === "ArrowUp") { e.preventDefault(); sel = Math.max(0, sel - 1); palRender(); } | |
| else if (e.key === "Enter" && shown[sel]) palGo(shown[sel]); | |
| }); | |
| </script> | |
| <script src="/static/tour.js" data-app="showcase" data-auto="0" defer></script> | |
| <script src="/static/demos.js" defer></script><script src="/static/demos-a.js" defer></script><script src="/static/demos-b.js" defer></script><script src="/static/demos-c.js" defer></script> | |
| <script> | |
| (() => { | |
| const URLS = { "": "https://death242-showcase.static.hf.space", "homebase": "https://homebase-family.onrender.com", "homebase-app": "https://homebase-family.onrender.com/download", "noor": "https://death242-noor.static.hf.space", "noor-app": "https://huggingface.co/datasets/Death242/downloads/resolve/main/noor.apk", "void": "https://death242-void.static.hf.space", "scout": "https://scout-15t6.onrender.com", "scout-app": "https://scout-15t6.onrender.com/static/scout.apk", "unwritten": "https://unwritten-dulm.onrender.com", "cookify": "https://cookify-6auu.onrender.com", "crosswind": "https://death242-crosswind.static.hf.space", "platter": "https://platter-87b0.onrender.com", "platter-app": "https://platter-87b0.onrender.com/static/platter.apk", "alibi": "https://alibi-d9tn.onrender.com", "alibi-app": "https://alibi-d9tn.onrender.com/static/alibi.apk", "tripmate": "https://tripmate-yecg.onrender.com", "cramly": "https://cramly-twz5.onrender.com", "womanten": "https://womanten.onrender.com", "whatif": "https://whatif-kkq1.onrender.com", "nonsense": "https://death242-totally-normal-website.static.hf.space" }; | |
| const sel = document.getElementById("qrsel"), img = document.getElementById("qrimg"), dl = document.getElementById("qrdl"), lab = document.getElementById("qrurl"); | |
| const set = id => { sel.value = id; img.src = "/qr/" + (id || "showcase") + ".svg"; dl.href = "/qr/" + (id || "showcase") + ".svg"; lab.textContent = (URLS[id] || URLS[""]).replace("https://", ""); }; | |
| sel.addEventListener("change", () => set(sel.value)); | |
| document.addEventListener("click", e => { const b = e.target.closest("[data-qr]"); if (!b) return; set(b.dataset.qr); document.getElementById("qr").scrollIntoView({ behavior: "smooth" }); }); | |
| })(); | |
| </script> | |
| <script src="/static/hub.js" data-app="showcase" defer></script> | |
| </body> | |
| </html> |