stardance has been extended another month! the new deadline is october 31 :)

You are browsing as a guest. Sign up (or log in) to start making projects!

xenoaitham

@xenoaitham

Joined September 9th, 2026

  • 49Devlogs
  • 3Projects
  • 3Ships
  • 34Votes
I am mazen a Dev from Egypt so am sorry if my englis is bad or smth i hope u like my projects <$60419> is the project that took hundred of hours from me still 60 percent done hope u like it
Open comments for this post

8h 22m 47s logged

002: opening the Dreaming Rooms

The second realm asks for a different kind of unease. The Crypt is weight, darkness, and armor. The Dreaming Rooms are open space, pale surfaces, repetition, and objects that almost belong together: cream plaster, checker floors, cloud windows, shallow pool imagery, impossible sky openings. Familiar rooms that refuse to feel fully ordinary.

The theme changes more than the palette. Wider, looping halls change how encounters play out. Porcelain wanderers drift through while mirror figures circle the player, pearl weapon materials and glass resonance change how the same actions feel, and a detuned choir carries the audio without any recordings.

The Oneiric Witness anchors the realm: a suspended porcelain mask, a dark eye, a hollow body, flowing ribbons, a halo, orbiting eyes. It shouldn’t read like another armored guard, and its movement has to keep that identity while still reading as danger.

The fight uses two contrasting patterns. A delayed lunge commits to a direction during its wind-up, giving a lateral dodge a clear purpose. A dream pulse holds position and marks a dangerous area on the floor. One asks the player to read direction, the other to read space, and both leave a recovery window.

Below half health the mask cracks and the room’s light changes. An attack’s timing is captured when it begins, so crossing that threshold never moves a cue already in progress. Small decision, big effect on trust: the warning the player sees has to describe the attack they actually get.

One touch of the blue seal enters the boss arena, with layout, player, and enemies switching generation together. Beating the Witness reaches the Dreamcore ending, and restarting keeps the chosen realm.

Limits: the browser suite covers realm selection, portal entry, same-frame generation changes, lunge direction, pulse radius, timing, defense, defeat, restart, and audio bounds. No new performance measurement here, and frame rate and audio quality across devices remain unverified.

0
0
34
Open comments for this post

6h 41m 44s logged

Devlog 001 Building the Crypt from scratch

UNDERCROFT starts with a constraint: construct a playable first-person dungeon
from shader code. There is no game engine, imported model library, texture pack,
or collection of recorded sounds behind the Crypt. Its rooms, enemies, sword,
interface, and audio are procedural constructions in GLSL. A small browser host
supplies input and presents the shader output.

That restriction shapes the world. Stone arches frame narrow paths. Torchlight
breaks up the darkness and gives the player a direction to read. Armored figures
occupy the same spaces the player can walk through. The dungeon needs to feel
like a place, but it also needs to show where movement is possible and where an
enemy can reach you.

The technical foundation is a persistent texture. One shader stores the layout,
player state, enemies, and progression there; the image shader reads that state
to draw the scene. This gives collision and rendering a shared source of truth.
Movement checks the path between positions rather than trusting the final
position alone, which matters when a frame takes longer than expected.

Combat grows around commitment. A sword sequence spends stamina. Dodging spends
more, while blocking trades incoming damage for stamina. Three healing flasks
give the player a limited chance to recover. The goal is to make a missed swing
or an exhausted dodge matter without making every mistake end the run.

The Cinder Warden gives those rules a destination. Its visible anticipation,
charge, and recovery create a cycle the player can read. Below half health, the
fight becomes faster. Recovery remains important: a boss needs moments when the
player can answer its attack, not only moments when the player must retreat.
Defeating the Warden leads to the Crypt ending; death and victory both support a
fresh run.

Audio follows the same construction rule as the environment. A dedicated shader
generates stereo samples, and the browser passes those samples to Web Audio.
Material sounds and attack cues belong to the simulation’s timing rather than
to a separate JavaScript combat system.

Verification and limits. The Crypt browser suite exercises movement,
collision, looking, stamina, healing, dodge, block, pickups, sword damage, the
ending, restart, and sound bounds. This entry records the foundation’s design;
it does not claim a new benchmark run. Desktop WebGL2 with floating-point shader
targets is required. Frame rate across different GPUs and sound perception on
different speakers remain device-dependent and unverified here.

0
0
13
Ship Pending review

I made OpenPorts, an attack surface monitor for small companies: you add a domain, prove you own it by publishing one TXT record at _openports.<yourdomain>, and a scanner that lives inside the web app itself sweeps the 100 most common TCP ports, has one short conversation with every open port, reads the TLS certificate on 443 and the mail ports, and checks SPF, DMARC, MX, HSTS, the http to https redirect and the server header. Every scan is diffed against the previous one, changes are held unconfirmed until a second scan agrees, and verified targets are rescanned every six hours without anyone pressing anything. The whole product is one process and one SQLite file: no redis, no docker, no queue service, two commands to run.

The hardest bug was one I inflicted on myself. The scheduler’s due query used ORM column objects inside a raw SQL fragment, the ORM rendered them unqualified, and inside a correlated subquery a bare id resolved to the wrong table, so the query compared every scan against itself and concluded the target was due on every two second tick. The worker scanned the demo host seventeen times in three minutes before I noticed. The fix was hand qualifying the table names and pinning the generated SQL in tests, so the next person who makes that mistake fails a test instead of discovering it from a host’s point of view. The second hard part was honesty under a flapping network: the demo host’s port 80 gives different answers to different conversations seconds apart, so a naive monitor would cry wolf on every run. Changes now announce immediately, tagged unconfirmed, and only confirm when two of the last three scans agree.

I am proud that nothing on screen is faked. Findings are never staged; every number in the report came off the wire, including the disagreements, which the report prints instead of hiding. And I am proud of the gate: nothing is ever scanned until ownership is proven, the worker rechecks verification before touching the network, and the single exception is scanme.nmap.org, which the Nmap project runs for exactly this purpose.

To test: open https://emotions-finger-earthquake-hints.trycloudflare.com in a browser, nothing to install. Click run scan again on the target and watch a real scan finish in about four seconds, then expand raw scan output to see what actually came off the wire. Or run it locally: npm install, npm run dev, then open http://localhost:4310.

  • 8 devlogs
  • 47h
Try project → See source code →
Open comments for this post

3h 22m 37s logged

022: v1.0 stamped, the gap priced a fourteenth time

One headline: stamp v1.0. Not new scope, just a clean stamp on what already works, so a stranger can clone, install, run, add a domain, publish one TXT record, and get real reports every six hours. The owner added one rule above everything else: commit nothing and push nothing until they say the word, so every git step is prepared and held.

The box rebooted again, the fifth pickup like it, and both handoff processes died with it. Restoring them took one command each. The database wasn’t empty this time, since the owner had seeded two scans, and that led to the best surprise: the seed had made the target six hours stale, so on boot the scheduler enqueued a scan by itself. First scheduled rescan on the real clock since the cadence was proven, no rewind, no hand-inserted row, no request in the log before it. Four independent sightings of the due branch now.

The scratch got cleared: four places, thirteen lines, all dead comments, a duplicate export and an unused constant, with the test count at 56 before and after. The README got read as a stranger would read it, every claim checked against the code, and none lied. One omission fixed: a single line naming the Node version.

The domain question got priced again, and the baseline held on every corner. The cloud CLI lists thirteen projects, and every one answered that the DNS API is disabled. Enabling it and creating a zone is a billable action nobody takes on their own behalf, so two targets on one cadence and two scans at once stay pinned by a race test instead of watched live.

A fresh set of twelve screenshots came out clean, though the browser cache was gone again and had to be refetched. The changes feed still has never shown a populated state on live data: seven done scans, every diff empty, nothing staged to force one.

The release steps are queued in order, waiting for the word: scratch commit, README commit, version stamp, tag, push, release.

0
0
7
Open comments for this post

7h 49m 39s logged

007: the cadence on the real clock, and the gap that stands

The oldest open question in the project closed: the six hour cadence fired on the real clock, no rewind, nothing inserted by hand. The scheduled scan appeared about a second after the mark, got claimed seven milliseconds later, finished in under four seconds, and stored the same empty diff as the one before it. Both feeds stayed honestly quiet. Every process watching it had died and the machine had been rebuilt around them, which didn’t matter, since the clock reads the database, not any process.

One small decision along the way: the politeness check stays on one stored address per target. Matching every address would need an address history table inside the claim, real machinery for round-robin hosts a small company rarely has, and politeness is a courtesy, not a correctness property.

Two lessons for the watching kit. Wiping the database with rm deafens any watcher, since it keeps polling the deleted file and the log just stops with no error, so restart it after every wipe, and after the migrate. And the production server doesn’t migrate, only dev does.

The gap that stands: two owned targets sharing the cadence, and two scans running at once, still pinned by a race test instead of watched live. Two more runs checked, and the second went deeper. No DNS credentials anywhere, then a cloud CLI turned up with two accounts, one with a dead token and one that sees ten projects with the DNS service disabled on every one. There’s a difference between no panel and a panel one billable step away, and enabling it is a purchase on someone’s account, not something to do unprompted.

Meanwhile the loop held every time: add the public test target, scan it, same four findings, port 80 splitting its personality between a 200 on the banner grab and a refused connection on the redirect check. It never flapped, so the populated changes feed has still never been seen on live data, and nothing was staged to force it.

0
0
18
Open comments for this post

6h 13m 41s logged

006: the pool, the bound, and the storm that never got to happen

Three jobs landed: a small worker pool with an atomic claim, retention finally observed deleting past its bound on a real run, and a decision about targets that never succeed. Still no second owned domain, so two scans running at once is pinned by a race test instead of watched live.

The pool is three workers, one plain constant. The whole design is the claim: one SQL statement picks a queued row and flips it to running in the same breath, so two workers can never take the same row. A test runs two real processes over one database file with twelve queued rows, and together they claimed all twelve, no duplicates. A politeness rule rides on top: a queued scan waits while any scan of the same target, or any target at the same address, is running, so one host never gets swept by two workers at once.

Watched it live: a burst of four scans on one host ran strictly one at a time, each starting within a millisecond of the previous finish. Boot recovery marked several stranded running rows failed at once, and a real kill mid-sweep recovered cleanly, the next queued scan picking up seconds later.

Retention had never deleted anything, since the real bound is a hundred. Lowered it to five for a soak, then restored it. The prune deleted exactly the five oldest done rows in the same instant, findings and diffs went with them through the cascade, failed rows were untouched, and neither feed noticed.

The never-succeeded decision: a target whose scans always fail used to be requeued every two seconds, forever, hammering a host that’s already failing. Now any finished scan resets the cadence, so a failing target is retried once per cadence like a healthy one. Cost, written down: a failed manual scan delays the next scheduled one.

One tooling incident: leftover watchers went deaf partway through, and my cleanup matched its own command line and killed a mix of shells and watchers. Watchers get a pidfile now.

0
0
29
Open comments for this post

9h 7m 10s logged

005: the window armed, and the run that went dark

Planned three things: catch the scheduler firing against a real clock, get a photo of a populated changes feed, and if there was room, add a retention limit to the scans table. The retention part landed clean. The clock-watching part did not, since the whole attempt crashed unexpectedly partway through and came back much later with only a partial trail left behind.

Retention is simple and real: keep the last hundred completed scans per target, prune right after a scan finishes, never let a failed cleanup corrupt a scan that actually succeeded. Deleting an old scan correctly drags its stored history with it, since nothing on screen ever looks back further than the limit already allows anyway.

The near miss is worth writing down. A log line looked exactly like proof the real scheduler behavior had finally been caught live. It was not, a different unrelated row fired for an unrelated reason, and it nearly got written up as the real finding before a second look caught it. Worse, the machine’s own clock had been wrong for the entire stretch, quietly off by a meaningful margin, so no timing claim from that window can be trusted. Every timing tool now stamps both the wall clock and a separate monotonic clock side by side, so drift shows up honestly instead of lying silently. Someone else picked up the real observation properly, on a trustworthy clock, the same day.

One real bug got caught and fixed regardless: a visual check of the live pages turned up literal broken source text rendering in production on every page, leftover from unrelated commits, plus a stray constant pasted into the middle of an unrelated import. Both fixed and disclosed rather than skipped past.

The actual lesson: the product held up fine through all of it. The environment around it, crashes, clock errors, lost caches, was what actually failed this time.

0
0
24
Open comments for this post

5h 17m 23s logged

004: the feed and the clock

Two real jobs this time, since a monitor that rescans itself is useless if nobody can see what changed without opening every target by hand. Gave the changes feed a real home across all targets at once, and then verified the scheduler against an actual running clock instead of just faking the passage of time.

The feed now lives on the dashboard as one shared section instead of being buried per target. The part that actually matters: both the per-target view and the new dashboard view call the exact same underlying function with the same inputs, so there’s no way for them to ever quietly disagree, a test pins that guarantee directly.

Then watched the scheduler live instead of trusting it on paper. Queued three scans back to back and watched a live monitor poll the database every tenth of a second: each one started within a millisecond of the previous finishing, strictly one at a time, exactly as claimed. Let the scheduler run untouched for a few minutes after and it correctly saw nothing was due yet, zero extra scans fired. Then did a real crash test, killed the server mid-scan for real, and on restart the interrupted scan correctly recorded itself as failed with an honest reason and a real timestamp, while the next queued scan picked up normally right after. Nothing stalled, nothing doubled up.

Also added a small “last changed” column to the main table, reading how long ago a target last actually recorded a real change, falling back to an honest dash instead of a false zero when there’s simply no history to look back through.

Honest gaps left standing: the scheduler’s actual auto-triggered scan path still hasn’t fired against a real clock, since nothing happened to go stale during this run, and the fully populated version of the new feed has never actually been seen live, since the test target just didn’t flap this time.

0
0
15
Open comments for this post

10h 54m 53s logged

the sculpt wires into the product flow

The proportion and volume sculpting work was measured and gated, but had no real user-facing path yet. That debt got paid: a new command line tool measures a reference image’s proportions and volume ratios into one deterministic file, and both the manual tool and the interactive in-app action now call the same shared function underneath, so they can’t quietly drift apart. The real proof was ordering: sculpt once at rest pose, then animate, and the sculpt has to survive byte-identically. It does, frame-one drift came out effectively zero across seventy checks.

Three real bugs earned their keep. First, two test rigs sharing one scene made solved values look wrong, the real cause was one fixture already carrying an earlier sculpt while the other’s baseline measurement accidentally captured the overlapping shape of both figures at once. Took a full debugging ladder to isolate, fixed with a clean scene per case, a lesson the project had already learned once before, now learned twice.

Second, baking an animation shifts frame numbers by one internally, so comparing a frame against its own neighbor instead of itself made results look dramatically worse than they actually were. A one-line offset fix, with the reasoning written directly into the check itself this time so it can’t get silently lost again.

Third, comparing raw bone positions across an animated sequence turned out to be the wrong check entirely, since a position-based re-solve is supposed to compensate for the current pose’s rotation by design, not match it exactly. Redefined what the check actually verifies, and caught a related bug along the way: an assigned animation silently overrides a rest-pose snapshot unless that animation gets explicitly muted first.

Landed with fifteen new tests, the full suite green, and every number comfortably inside its bar except one, a single rig type’s re-sculpt accuracy sits just barely over target, left as the next rough edge.

0
0
11
Open comments for this post

7h 53m 26s logged

volume from silhouette

The third model decision is made and the volume feature is real. The engine now carries a third pinned model, a segmentation pass, plus a working body sculpt: feed it a reference shape and the character’s hip, waist, chest, and thigh widths move to match it, skeleton provably untouched.

Getting there meant benchmarking five real candidate models on real hardware, checksums, speed, and accuracy each, rejecting six other families with the evidence written down. Funniest catch: the model built specifically for segmenting people was completely blind to the test case, zero accuracy, while the general-purpose model saw it fine and ran cheaper too. The mechanism authors real shape keys per body region, so the adjustable sliders are the solved math directly, and every pose/animation path downstream sees a completely unchanged skeleton.

The real fight was realizing the first passing test was a lie. A whole-frame comparison technically passed on a completely unsculpted body, since the measurement was too insensitive to tell a correctly sculpted shape from an untouched one. Fixed by scoping comparisons to the actual body regions with no model in the loop, publishing a baseline next to every result so a cheating pass can’t hide again. Smaller lessons banked too: a slider silently defaulting to zero killed half its usable range, one rig type needed its math in a different coordinate space entirely or it silently did nothing, leftover scene state poisoned later measurements, and naive bone-weight assignment broke the hip region specifically.

Numbers came out solid: worst-case regional accuracy clears the bar across every test case, width delivery lands exact to four decimal places, solved values track intended targets within about 3% through the real model, and resetting a sculpt restores the original mesh almost exactly.

Next: wire both sculpts into the real user-facing flow, and prove the sculpt survives animation, set once, then animate, and the widths hold.

0
0
30
Open comments for this post

5h 18m 52s logged

003: the monitor runs on its own

Three things landed, and one caught a real bug in the tool itself. Targets now get rescanned automatically on a fixed cadence instead of only when someone manually triggers one, with guards so a slow scan never piles another behind it and a crash-interrupted scan gets marked failed on restart instead of stalling the cadence forever.

The bug lived in that scheduler. A raw SQL fragment had a column reference that wasn’t properly scoped, so inside a nested subquery it silently matched against the wrong table entirely, meaning every tick thought every target was already stale and due again. The worker rescanned the test target seventeen times in about three minutes before anyone noticed. Killed it, fixed the query by hand, and pinned the actual generated SQL in a test so the same mistake fails loudly next time instead of quietly hammering a shared target.

That accidental storm also proved the flap-detection design works for real: the scheduled runs watched the flaky test port close three times, catch it opening once with exactly the single expected unconfirmed alert, then stay quiet through seven more scans that all agreed. One honest announcement, then silence, no crying wolf.

Extended certificate checking from just the main port to the mail ports too, and testing it against a real mail server caught another real bug, the handshake was sending the resolved IP address as the server name instead of the actual domain, so every check failed with a false hostname mismatch on a certificate that was actually fine. Fixed to match what a real browser does, and the same server that falsely failed a minute earlier came back clean.

Also did another full visual pass and caught a few smaller things left over: red still marking a normal state, a decorative pulsing dot next to text that already said the same thing, inconsistent spacing across tables, and a rare timing mismatch between server-rendered and client-rendered relative timestamps.

0
0
83
Open comments for this post

4h 21m logged

002: the ui rework

The scanner works and the loop is honest, but the frontend read like it came off an assembly line. Screenshotted every page with real data and judged each one as a skeptical stranger: does one person’s point of view show here, or does it pattern-match a template. Verdict: every shot patterned. Terminal-cosplay monospace headline, a numbered marketing-style “how it works” section, prose before any real output, tinted pill badges doing what a plain word could do, a green accent spent purely on decoration.

That same review caught two real bugs, not the code review. Findings rendered worst-last instead of worst-first, so the most important result sat at the bottom. And a completely expected, normal state rendered in alarm red, exactly the thing that trains people to ignore red.

Rebuilt around one stance: paper, not a dashboard. Off-white background, no rounded corners, no shadows, no gradients. Tables are the interface. Monospace only for actual data, ports, tokens, timestamps. Color appears exactly once, for severity, nothing else. The landing page now shows a real report pulled live from the database instead of marketing copy.

Shipped port banner grabbing too, so an open port says what’s listening instead of a bare number. One real security call won along the way: a first draft quietly disabled certificate validation to read self-signed certs, and that got reverted, since a self-signed cert is exactly what a monitoring tool should flag, not quietly read through.

Also added a real diff feed between scans. A flaky test target’s port flips open and closed between runs, so announcing every change instantly would be worthless noise. Settled on showing a change immediately but marked unconfirmed until two of the last three scans agree, resolving a one-scan flap back to its real state too.

Still missing: scheduled rescans, so the feed only moves when someone manually triggers a scan, and mail TLS ports are identified but not checked for certificate expiry yet.

0
0
15
Open comments for this post

5h 2m 19s logged

001: the first loop works

 OpenPorts watches a domain from the outside and reports what it exposes: open ports, TLS certificates on their way out, mail records that let anyone spoof you, headers that give away the stack. The first full loop went end to end: add a domain, publish one TXT record to prove you own it, then the scanner runs. No record, no scan, one exception for the public test target Nmap itself runs for scanner builders. 

The scanner stays deliberately modest: one connect sweep over the hundred most likely ports, a TLS handshake to read the certificate, a few DNS lookups for spoofing protection, and three small HTTP checks. Nothing sends a payload, nothing probes services. A full scan takes under three seconds. 

Two real bugs worth writing down. First, the hand-assembled port list was just wrong, missing port 3389 entirely, so the single highest-severity finding in the whole catalog could never actually fire. A boring test that just checks a list of numbers felt like pure ceremony right up until it caught exactly that. 

Second, the test target’s port 80 turned out flaky in the worst way for a monitoring product: sometimes it answers fully, sometimes the connection opens but the request just hangs until timeout, and reported findings silently change between runs though nothing on the customer’s end did anything. Now recording exactly what the network said instead of pretending every check came back clean; confirming a change twice before reporting it is next. 

Architecture choices so far: a simple embedded database instead of a separate one to babysit, and one plain interval-based worker in the main process instead of real job infrastructure, the least moving parts that still survives a restart without double-scanning. What doesn’t work yet: no service identification on open ports, TLS only checked when the main web port answers, and only one scan at a time. 

Next: naming what’s running on each open port, scheduled rescans, and diffing between scans, since “this port showed up since yesterday” is the real product.

0
0
32

Followers

Loading…