Full-Stack Developer — Immersive 3D Web
ሙሉዓለም — Amharic for “a whole world”
A fitting name for the job: I build worlds in browsers — 3D stores you can walk through, games, GPU simulations, and AI-powered tools. From concept to deployed product.
↓ scroll for contact & skills · ← → / side-swipe to browse projects
I'm a full-stack developer specializing in immersive 3D web experiences and interactive applications. With expertise in Three.js, React, and WebGL, I transform complex ideas into engaging digital products — from 3D games and GPU simulations to AI-powered productivity tools.
- 5+ years building immersive 3D web applications and interactive experiences.
- Expert in Three.js, WebGL, and GLSL for real-time graphics in the browser.
- Delivered projects spanning e-commerce, games, simulations, and productivity tools.
- Built AI-powered apps for text summarization, mind mapping, and content visualization.
- Strong foundation in mathematical modeling — GPU particle systems, slime mold simulations.
gta-kenny-world
Open-world city you can drive, walk and get chased around in a browser — a seeded 28×28 tile city where the traffic, the crowd and the police are simulations rather than scripted set pieces.
- Three.js
- three-mesh-bvh
Images
Videos
- Seeded tile-grid city with a lane graph, signalled junctions and routed traffic.
- ~50 AI drivers that queue, yield and re-route, and ~30 pedestrians that use the pavements and wait at the zebras.
- Wanted system with police pursuit, officers that carry the chase on foot, and a real escape condition.
- Kinematic bicycle-model driving — handbrake drifts, weight transfer, tyre marks and bodywork that comes off.
- Shared three-mesh-bvh capsule collision for cars and bodies, with a dither cutout that opens a hole through occluders.
- Draw calls cut 613 → 393 on desktop and a dynamic resolution scaler that holds ~40 fps; touch, gamepad and mouse-look on one input contract.
input-world-reboot
Ground-up rebuild of input-world-third-person: a round two-floor glass dome store in a landscaped garden, modelled in Blender from build scripts, with nine playable characters, foot-locking IK, sit and cap-inspect sequences, and product cards that link to the merch store.
- Three.js
- React Three Fiber
- Rapier
- ecctrl
- Blender
- ez-tree
Images
Videos
- The whole dome comes from Blender Python scripts (shell, furnishing, landscape, hedges) and exports to one 9.2 MB Draco + WebP GLB with a contract check on node names and invisible _col collider meshes. Draco and not meshopt, because meshopt broke the Rapier colliders in the old project.
- Two stair layouts live in the same GLB as sibling groups. T switches the visible group and mounts only that group's colliders, and the mezzanine closes to a full ring in spiral mode.
- Foot locking ported from an IK demo: a toe that is slow and low is planted where it touched down, two-bone IK holds it there, and the ground comes from Rapier ray casts, so stairs and props count.
- Sit and cap-inspect are scripted sequences on one shared controller. The walk to the seat or table is an A* route on a 25 cm grid with a body-sized clearance box, then string-pulled, so he never steps onto a sofa or through a bench.
- One shared gust field moves everything: per-plant 2-axis spring rigs bend meshes in the shader, ivy strands are verlet ropes, garments are pendulums with a lagging hem, and the grass and trees use the same wind.
- The lawn is real grass blades in a tile that follows the camera, placed from a ground map baked in Blender (height, lawn mask, edge distance per 40 cm cell). Blades grow only on lawn and bend away from the player's feet.
- A screen-door dissolve inside a capsule from the camera to the player keeps him visible behind columns and glass, per fragment, so merged meshes open only where they block.
r3f-sniper
A browser sniper game in React Three Fiber, in development: timed contracts against a cutaway apartment block and three glass villas, with NPCs that panic, report and walk their boss to an extraction, eleven rifles with their own scopes and powers, and a bullet kill cam on every headshot. It plays on desktop and on phones.
- React Three Fiber
- Three.js
- Rapier
- three-mesh-bvh
- postprocessing
- Blender Python
Images
Videos
- All gameplay time comes from one game clock that is ticked once per frame, and `pnpm lint:clock` fails if gameplay code reads the render clock, performance.now or Date.now. Pause, slow motion, the kill-cam freeze and the 'click to take aim' hold are then each one time scale on that clock.
- The kill cam is decided at the trigger from the resolved hits (headshot, wall-bang, multi-kill, disposal) and flies five beats. Each frame it scores sixteen candidate seats against the level BVH, so it never films a wall. It borrows the player camera because each camera or composer swap rebuilt the EffectComposer for 100 to 370 ms.
- Villas are headless Blender Python scripts that export the GLB and the gameplay JSON from the same coordinates. Tests check that anchors stand on nav planes, that the perch can see every building, and that the boss can reach his extraction.
- The alert is a pure module. A witness walks to a guard to report, so a kill on the way stops the alert. Radios are instant but can be cut short. At lockdown two guards escort the boss to a car, a helicopter or a boat.
- Every bullet kill hands the animated skeleton to an 11-capsule Rapier ragdoll at the impact frame and applies the impulse at the exact hit point, with the wound decal attached before the handoff. There are no death animations.
- Three quality tiers are chosen at startup from the renderer string (`?tier=` overrides). A PerformanceMonitor governor then steps down and latches after eight real changes, so the tier does not flip back and forth.
- Touch and mouse write to one input object that the camera reads once per frame, so a drag never re-renders React. A phone gets the same round with on-screen fire, scope, breath, ammo and pinch zoom.
etfc-fight
UFC-style 1v1 cage fight built for an ETFC event: you are Jhonny, the CPU is Sedo. The headline bout (?reallusion) is played out with paired Reallusion mocap, so every hit, dodge, throw, knockdown and KO is one two-person take; the default build is a Mixamo fight with a 90-second round, knockdowns and a decision on the bell.
- React Three Fiber
- Three.js
- Zustand
- Vite
- Blender Python
Images
Videos
- Paired-mocap combat (?reallusion): the outcome is resolved first (hit, dodged, knockdown, KO) and then the Reallusion two-actor take that performs it is played, so there is no collision and no interpenetration.
- Each pair is re-anchored with a rigid 2D transform that maps its clip-space hip starts onto the fighters' current positions, tweened over the crossfade and pinned on a downed fighter so a lying body never slides.
- Knockdowns chain into get-ups baked from frame 95 of the pack's kip-up takes, matched to whether the fall ends face-up or face-down; KOs and knockdowns drop the global clock to 0.28 and 0.45.
- Headless Blender bakes every FBX into one GLB of named clips and trims the frozen tail CC4 adds to each take by sampling bone motion at a 15-frame stride.
- Default fight logic is pure TypeScript with Vitest tests; strike ranges come from forward kinematics over the shipped GLBs, and a strike thrown from too close becomes a clinch weapon so limbs never pass through bodies.
- Knockback is the exact integral of exponential decay, so a slide travels the same distance at 30 fps and 144 fps; hitstop and camera shake sit on separate envelopes that never disturb the framing.
- Mixamo materials are reclassified on load (skin, eyes, hair, cloth, shoes, metal) to fix half-metal skin, doubled specular and zero-scale normal maps from the bake.
berlin-runner-reboot
Ground-up rebuild of the 2022 infinite runner as a 5 km race through a curved low-poly Berlin — thirteen landmark corners, a server-validated leaderboard with live events, and sellable ad boards paced through the city.
- React Three Fiber
- Three.js
- TypeScript
- Supabase
Images
Videos
- The endless run became a 5 km race ending on a measuring pole — the € at the tape and the crossing speed set the launch height, and the peak pays back as a bonus.
- One shared uniform bends the whole city on the GPU, with a matching bent depth material so cast shadows follow the curve.
- Corners are fixed-radius arcs integrated at the step midpoint over the chord, so the exit lands on the new centerline at any speed or frame rate.
- Server-authoritative leaderboard — HMAC run tokens, speed and coin ceilings and a profanity filter inside a Supabase Edge Function that CI redeploys on every change.
- Sellable ad inventory: three tiers over a nine-slot catalogue, one board every ~8 tiles, uploaded and priced from an in-app admin dashboard.
- Boot rebuilt around a canvas pre-mounted behind character select — PLAY to playable fell 5.9s to 2.1s at 4× CPU throttle once the GLB library was re-encoded to meshopt + WebP.
polished-man
Cel-shaded browser world where a robot mascot walks a procedurally generated planet with radial gravity — you shoot flying monsters, eat what they drop, dodge their bombs, and talk to the robot through a DeepSeek LLM.
- Three.js
- React Three Fiber
- three-mesh-bvh
- DeepSeek API
Images
Videos
- Seeded cube-sphere planet — 4-octave value-noise FBM displacing a radius-40 sphere, seam-welded so the rendered mesh doubles as the BVH collision mesh.
- Kinematic capsule controller under radial gravity: 6-substep depenetration against a merged obstacle BVH, with the heading parallel-transported through the surface tangent frame.
- Cel look in two halves — direct diffuse quantised into hard bands via onBeforeCompile so the toggle is one uniform write with no shader recompiles, plus a 4-tap depth and 4-tap normal outline pass with a time-wobbled ink boil.
- The mascot's face is a 512×512 canvas redrawn every frame — 30 expressions, saccades, blinks and a typewriter terminal that types the LLM reply onto the screen.
- DeepSeek chat driven by a system prompt rebuilt per message from live game state (kills, eats, HP, armed bomb count), proxied through a Vercel function so the key never reaches the bundle.
- One 200-entry forest layout serves as both scene dressing and the sole collision source, exp-map projected onto the sphere and stamped in three cap rotations.
rakitecht.rubix
2×2 Rubik's Cube built from custom 3D celebrity heads for Rakitecht, where the grabbed layer tracks your finger in screen space and settles onto the nearest quarter turn, with per-character access codes.
- Three.js
- React Three Fiber
- GSAP
- Web Audio API
Images
Videos
- Drag-to-follow turns: the raycast face normal fixes the two physically possible axes, and the live drag is compared against each axis projected into screen space, so direction stays correct at any orbit angle.
- Release snaps to the nearest quarter turn, with angular velocity over the last six samples letting a flick complete a turn it never quite reached.
- Every committed turn is recorded as {axis, coord, quarters} — undo inverts the last one, reset replays every inverse in reverse to unscramble step by step.
- Three runnable Node self-tests cover the axis pick, the group-rotate-bake permutation, and scramble-then-inverse-replay-back-to-solved.
- Per-turn friction audio: recorded stone foley gain-modulated by the layer's live rotation speed, with four procedural noise-filter fallbacks and a synth seat thump.
- Self-hosted Draco decoder wired through all 64 useGLTF call sites, with a targeted preload fired the moment the access-code dialog opens.
rakitecht.chess
3D chess with Nike- and adidas-branded piece models, rebuilt in 2026 around chess.js and a worker-run negamax engine so a lone visitor can play the computer rather than only hotseat a friend.
- Three.js
- React Three Fiber
- Next.js
- chess.js
Images
Videos
- Custom Nike- and adidas-branded piece models, Draco-compressed 53.2MB → 2.65MB after decoding both sets and comparing vertex bounds — worst deviation 1e-7 units.
- chess.js is the rules authority, wrapped to keep stable per-piece ids so meshes animate through castling, en passant and promotion instead of remounting; 59 tests, up from zero.
- Negamax with alpha-beta and piece-square tables at three depths, moved into a Web Worker because depth 3 measured up to 2.5s on the main thread.
- White studio staging — a procedural Lightformer softbox rig replaces the HDR, with one steep key light and a shadow camera sized to the board.
- Legal squares carry a shape as well as a colour: a dot for a quiet move, a ring for a capture.
- Undo, PGN copy, and a localStorage resume that persists the PGN rather than the FEN so history, captures and undo all survive a refresh.
input.world
First-person 3D online store enabling immersive product exploration with selectable environment themes and integrated media.
- Three.js
Images
Videos
- Custom first-person camera controller.
- Region/radius-based context menu for product discovery.
- Selectable environment themes and integrated music player.
- Custom external link navigation handler.
input.platformer
3D platformer with modular level design, robust character control, dynamic moving platforms, and a time-based leaderboard.
- Three.js
- React Three Fiber
Images
Videos
- Character selection with advanced controller supporting animations and moving platforms.
- Streamlined level integration workflow from Blender.
- Extensible movement protocols for dynamic level components.
- Time-based gameplay with leaderboard and integrated sponsorship marketplace.
berlin-runner
Original 2021–2022 version, superseded by berlin-runner-reboot. Web-based infinite runner built with Three.js featuring character selection, dynamic weather, procedural world generation, and a score-linked reward system.
- Three.js
- GLSL
Images
Videos
- Interactive 3D character selection with 3-lane controller (jump, slide).
- Dynamic weather system — rain, snow, sunny cycles.
- Procedural world tile and obstacle/reward placement.
- Score-based dynamic difficulty and external reward linking.
- Finite state machine for game state management and in-game tutorial.
input-world-third-person
Original 2024–2025 version, superseded by input-world-reboot. Immersive 3D online store where users explore and interact with products in third-person perspective — blending e-commerce with game-like engagement.
- Three.js
- React Three Fiber
Images
Videos
- Character selection system with third-person controller and full animation set.
- Post-processing pipeline for a stylized, pixelated aesthetic.
- Custom region/radius-based context menu for product cataloging.
- In-world 3D YouTube video player and music player.
- Physics-based environmental interactions and extensive micro-interactions.
- Custom external link redirection system.
truck-cap-configurator
Browser configurator for a truck-cap maker: six trucks, two cap generations, several cap models and a few dozen accessories, all generated by Blender scripts from catalogue data. Every door, drawer and rack works, parts interlock like the real ones, and changing truck or cap morphs the geometry in place instead of loading a new model.
- React Three Fiber
- Three.js
- Blender Python
- Web Crypto API
- PostHog
- Cloudflare Workers
Images
Videos
- Blender-to-app pipeline: headless Blender 5.2 scripts build each truck, cap kit and product size from catalogue JSON into its own GLB, and a node contract (glTF extras → three.js userData) carries hinge and slide parts, mount anchors, model tags and interlocks, so the app has no per-product geometry code.
- Truck swaps morph rather than reload: every same-named node and every mesh with the same vertex count glides from the file on screen to the target file, and the generators keep names, counts and vertex order fixed across dimensions, checked by a script that reports 0 mismatches.
- The switch between the two cap generations goes through a shared featureless hull (3,250 vertices, identical topology in all 11 cap files, baked per vertex): the old cap melts into it and the new one reforms out of it, because the two generations share no topology.
- Products mount generically from data: anchors (point, line, grid, surface, ground), sides, counts and declarative interlock rules with the hint shown to the user, so every accessory runs through one code path.
- Model files are AES-GCM encrypted at build time and served from hashed paths, decrypted in memory with the Web Crypto API; the deployed build ships no .glb, source maps or debug hooks.
- A preloader fetches, decrypts, parses and GPU-warms every model (six at a time, retries with backoff), so after the loader every truck swap, cap switch and product works offline with 0 requests.
- PostHog analytics stay anonymous (no cookies, no replay, no identify) and fire only in the production build, not in dev, film mode or under automation, so the test runs send nothing.
design-court
A 3D sports-court configurator for basketball, tennis and pickleball. Pick a sport, recolour the surface, apron, key and lines, set fences, a gate and light poles, flip to night, then share the exact design as a link or export it as JSON or a hi-res PNG. The court markings are drawn into a single canvas texture, so there are no line meshes and no texture files.
- React 19
- React Three Fiber
- Three.js
- Zustand
- Tailwind CSS
Images
Videos
- All court markings for all three sports are drawn with the 2D Canvas API into one CanvasTexture on one plane, which replaced about forty line meshes; a sport or size change redraws the canvas, it does not rebuild geometry.
- Court size, line colour and gate position are shader uniforms patched in through onBeforeCompile, after the first build baked them into GLSL strings and the gate slider silently stopped moving the opening.
- The fence is a shader-drawn chain-link plane: the gate is a discard window driven by a uniform, and a fresnel term raises wire opacity at grazing angles so the mesh reads solid from a distance.
- frameloop="demand" with explicit invalidate() calls: camera presets, the first-load sweep and the day/night lerp render only while they move, so an idle configurator draws nothing.
- Undo and redo through zundo's temporal middleware, with a partialize that keeps camera preset and quality tier out of history so undo only steps through design decisions.
- Share links compress the design with lz-string into ?design=, and the decoder validates the sport, clamps dimensions and rejects malformed light arrays before anything reaches the store.
- Court standards (key, three-point radius, kitchen depth, apron width) live in one constants module that the store, the texture draw and the area readout all import, so the painted court and the square-footage numbers cannot disagree.
raptor
Real-time browser render of a 2021 F-150 Raptor with six camera shots, four lighting rigs and eight paint swatches — 1.13 M triangles lit entirely by a procedural HDRI, with no textures anywhere in the material bank.
- Three.js
- React Three Fiber
- GLSL
- postprocessing
Images
Videos
- Twenty-three material slots compiled as six GLSL families through onBeforeCompile, keyed by customProgramCacheKey so each family builds exactly one program.
- Every spatial detail is world-space procedural — the GLB has no tangents and degenerate UVs on 10 of 23 slots, so paint flake, mould grain, tyre sidewall lettering and rotor flash rust are shaded in rather than textured.
- A screen-space derivative pixel-footprint helper gates each detail band, fading the 2 mm flake cell and the 0.8 mm mould cell out before either can alias.
- Six-zone world-space dirt model — rocker spray, rooster tails off each contact patch, tailgate wake, settled top dust, wash-off blotching — behind a single Dust slider.
- Emissive levels divided by their own Rec.709 luminance so the 1.1 bloom threshold catches lamps and never paint; the red tail lamp runs at 15.79 to clear it.
- Vertex normals recomputed in float32 at bind time, because the GLB's normalized-BYTE normals are a 1-degree lattice that the 0.055 clearcoat resolved as terraces.
calathea
Realtime three.js render of a Cigar Calathea — a studio lighting study in the browser, with the model and its textures shipped as one encrypted, origin-gated bundle rather than as downloadable files.
- Three.js
- Web Crypto API
Images
Videos
- Studio lighting rig with ACES Filmic tone mapping and 4096px soft shadow maps.
- Post-processing chain — temporal AA, GTAO ambient occlusion, restrained bloom and SMAA.
- Model and textures sealed into a single AES-256-GCM blob and decrypted in memory at runtime.
- Asset key served by a same-origin-gated function, so the deploy exposes no .FBX or texture URL.
- Build step packs the raw source into the served bundle, keeping source files out of the deploy entirely.
character-customizer
Bilal, a browser-native 3D wardrobe for input.online: dress a rigged character from a configurable wardrobe, pose it, light it, capture and share. Four procedural places (harbor pier, rooftop, forest clearing, dunes) and four times of day light every look, and a sky dome feeds the garment reflections. Three.js r185 and Vite, no framework.
- Three.js
- Vite
Images
Videos
- Four procedural places swap with one button, four times of day light every place, and the sky dome feeds the garment reflections.
- Body-coverage rules decide what can be worn together, proven over all 8,640 outfit combinations.
- Depth of field and a cinematic finish on desktop, and a panel-aware framing keeps the figure centred when a panel opens.
- A transparent turntable loader covers the model load, and the models arrive brotli-compressed from the edge.
- Mobile pass: holds 60 Hz on the low and medium tiers at a phone viewport with 4x CPU throttle.
truck-customizer
3D product configurator for a canopy manufacturer — buyers interactively build and visualize their truck canopy in real time.
- Three.js
- React Three Fiber
Images
Videos
- High-fidelity, photorealistic 3D rendering.
- Interactive component customization with open/close animations.
- Color selection and toggle-based feature customization.
koi-pond
A Japanese garden koi pond seen from straight above, made for a floor or wall projector in care homes where a moving hand is the only input. The water ripples where the hand passes, a few pellets fall and the koi rise to feed; a hand kept on one koi brings it up to nuzzle, and a fast sweep scatters them — no menu, no score, no text.
- Three.js
- GLSL
- Blender
- Vitest
Images
Videos
- Dispersive ripple sim on the GPU (iWave-style kernel with least-squares-fitted weights plus a stabilising Laplacian), so a touch makes a widening train of rings instead of one shock front; tests pin stability and dispersion.
- Caustic net from a projected surface grid: each vertex refracts the sun through its own normal onto the bed and fragments take the area ratio from screen-space derivatives, replacing a per-pixel heuristic.
- Water rendered as one pass over an HDR under-water target — refraction by real water thickness, Beer-Lambert absorption, Fresnel sky, glints — with no depth write, so floaters are never cut by the surface.
- Koi modelled, rigged and animated in Blender from a build script (GLBs are build output, checked by tests); sixteen varieties come from pattern code in the shader over two meshes.
- Thrust-driven beat-and-glide gait, and every goal blended into one low-passed heading, speed and depth, so a koi never freezes mid-swim or flickers between competing pulls.
- Bodies are capsules in the plane, every pair projected ahead with a right-of-way rule, because from straight above depth does not excuse one koi cutting into another.
- Input is booth-shaped XY bursts from an IR motion camera, read as a presence charge with decay; a perf pass took 8.2 to 5.8 ms p50 at 1080p at 0.04% image difference.
hellas-gold-olympias
Guided 3D tour of the Olympias mine for a 50-inch portrait touchscreen at a Hellas Gold booth: an attract orbit, an overview and five points of interest, one of which flies through a portal and down a tunnel into an underground cavern. English-only panels, offline-first, and a ~75 s unattended film when nobody touches it.
- Three.js
- React Three Fiber
- postprocessing
- Zustand
- Supabase
Images
Videos
- Portal-to-cave cut hidden by a window plane: a colour+depth render of the tunnel from the exact cut pose, ray-marched with the live camera, so the frame before the cut matches the frame after it; the two worlds swap imperatively in the same frame because a React commit lands one frame late.
- Flight, dolly, cut and tunnel travel run at one cruise speed (the cut falls at the dolly's share of the path), and flights to the portal move the focus point only while the camera is far and high, so the look never whips at the stand-off.
- The truck haul loop is built from the client's road mesh at load: ~64 rough seeds, resampled to 240 points, each re-centred by scanning ±2.5 u across the road for mesh hits and median-filtered, so a re-export that nudges the road heals itself.
- POI beacons are polar discs with every vertex dropped onto the terrain, with the ring and radar pulse drawn in the fragment shader from horizontal radius, so the pulse animates without scaling geometry that would lift off the ground.
- Shot field of view is authored vertical for the 9:16 kiosk and converted per aspect to keep the same angular width across the short side of the visible area (minus the landscape side sheet), so a subject is the same size on a phone, a laptop and the kiosk.
- Booth tiers (?booth, ?booth=low) and a ?config settings screen saved in localStorage let staff tune render scale, DoF, AO and stop positions on the integrated-GPU booth laptop without a rebuild.
- The 588 crystal shards in the cave GLB are split by connected component into five ore materials (gold, silver, galena, sphalerite, pyrite) instead of asking the artist for a re-export.
hellas-gold-skouries
Touchscreen kiosk for the Skouries copper-gold mine, built for a 50-inch portrait panel: a camera tour over a living diorama of the site — haul trucks, workers, cranes and an underground cavern — with bilingual Greek/English data panels. Runs offline from bundled assets.
- React Three Fiber
- Three.js
- postprocessing
- Zustand
- Vite
Images
Videos
- Hand-copied port of the Olympias kiosk with no shared history, kept in step by a /sync-olympias command that cherry-picks chosen upstream commits with -x and resolves site-specific conflicts (model, copy, colours) on the Skouries side.
- Haul trucks shuttle the artist's real 265 u route: chain points welded under 0.06 u, a 2048-bin curvature map feeding a braking curve, turn-rate-capped crawl through hairpins tighter than a truck, and a keep-right lane offset so two-way traffic passes cleanly.
- When the V_0.0.2 road spline did not survive glTF export, the truck loops were extracted in Blender as A* routes over the road mesh's face-adjacency graph, so every path point is a road face centre.
- Underground stop: the Olympias portal system re-measured to the 0.23 u Skouries arch — the camera is clamped above sampled terrain and camera.near ramps down by distance to the mouth, then the world swaps to a cavern at y −600.
- Bilingual EL/EN copy in one content file with a check:content script that fails on structure drift; idle 75 s resets to attract in Greek, and the 2 Sep round spelled every unit out in both languages.
- The loader waits for the first presented frame rather than asset progress, so the UI never fades in over a bare background while shaders compile on the booth iGPU.
- Shared render-cost pass (from Olympias): transparent DoubleSide materials were drawn twice per frame, so single-pass is enabled per material only where the edge-fade alpha stays within one 8-bit step — 98 to 77.6 draw calls, checked by a frozen-clock visual-regression harness.
amharic-alphabets
All 355 Ethiopic glyphs of Noto Sans Ethiopic rebuilt as clean all-quad 3D letters, then dropped into a real-time physics pile you can drag, throw and summon from an alphabet table. Each letter you pick floats to the centre and bends, twists, squashes and wobbles with its quad wireframe deforming with the skin.
- Three.js
- React Three Fiber
- Rapier
- Blender
- Remotion
Images
Videos
- Hand-authored quad layout per glyph: four-sided patches with corners on the font outline, one segment count solved per chord and Coons-filled, giving 4 quads across every stroke and no interior poles in most of the 355 glyphs.
- Built-in quality gate (minimum quad angle 30°, maximum aspect 4) and an exact outline, because the raw font fill gives sliver triangles and QuadriFlow auto-remesh warps the letter shape.
- Blender extrusion with even depth loops and a two-segment rim bevel so the solids stay all-quad; the quad edges ship as a separate glTF LINES child because glTF triangulates faces.
- Rapier runs in a Web Worker with compound convex colliders, merged greedily while the merged hull adds under 10% area (about 30 pieces to about 12 per letter), so concave letters stay concave.
- Settled letters are frozen as fixed bodies and thaw only on contact with a fast or carried letter, because Rapier wakes a whole touching island and one contact would re-simulate the full 355-letter pile.
- One GLSL deform() driven by six damped springs is patched into both the surface and the wire material, so the quad wireframe twists, bends and squashes with the skin; normals come from finite differences.
- Render on demand: letters are posed from the last two physics snapshots, the frame loop sleeps while the pile is frozen, and the shadow map re-renders only while letters move.
animated-doodles
A sheet of ink-doodle heads drawn in code on Canvas 2D: drag a head to turn it, tap it to see it large, and switch on the camera to have it mirror your face and hands. There is no 3D library: each head is an ellipsoid, and every feature is drawn in the tangent frame of that surface. Inspired by the HEAD CASES doodle sheet by @chetaslua.
- Canvas 2D
- MediaPipe Face Landmarker
- MediaPipe Hand Landmarker
- MediaRecorder API
- Vite
Images
Videos
- Heads are ellipsoids with features at longitude/latitude addresses, drawn in the projected tangent frame, so a head turns in 3D with plain Canvas 2D and a hand-written rotation matrix instead of Three.js.
- One inker gives all of the hand-drawn look: resampled polylines, seeded jitter, two strokes, and a three-phase boil at 6 Hz, so the lines breathe but the drawing stays the same.
- The jaw is a hinge inside the surface function, so chin, jawline and beard swing down together. The lips are MediaPipe's lip rings with the head rotation undone, which cut the width change of a closed mouth on head turns from 26% to 7.5%.
- Hands are painted onto a mask and traced with a Moore-neighbour walk into one contour that cannot self-intersect. Then the fingers are drawn again far to near with paper fill, so fists and side views hold.
- Glasses on/off can change only in a window of about 1.5 s that opens when a hand comes near the eyes. A per-person logistic model on an 800-value eye patch decides, and the user can refit it with two 2.5 s recordings.
- Every tracked channel has its own one-euro filter, and the puppet draws one camera reading behind, blending the last two, so a 30 fps camera gives smooth motion at the display rate.
- Record draws the doodle alone onto a 1080 px square canvas for MediaRecorder. The OBS overlay keys alpha from how much darker each pixel is than the paper, so lines hidden behind a paper-filled hand stay hidden.
sakura-ripple
Ambient WebGPU water piece where sakura petals rain onto a simulated surface and each landing rings a piano note — spawns are scheduled a full fall-time ahead of the beat, so the ripples play a classical piece in rhythm.
- Three.js
- WebGPU
- TSL
- Web Audio API
Images
Videos
- 256² Hugo Elias wave field stepped on the CPU and uploaded as float height and normal DataTextures, after three r185's WebGPU render-target ping-pong read back zero and killed the feedback loop.
- A conductor dispatches every petal on one absolute timeline — spawned exactly its own fall time before the note's onset — so landings stay beat-exact across loop seams with no clock reset.
- Descent is an authored quadratic-to-terminal profile with a ±10% per-frame time-warp against the live wavy surface, so contact happens on the beat and on the water rather than punching a crest.
- Landings voice a procedural piano (three sine partials, 12 ms attack, 2.2 s decay) stereo-panned by projecting the landing point through the camera; seven timed pieces ship with tempo and beat gaps.
- Water shader written entirely in TSL: Schlick fresnel over a half-resolution planar reflector, screen-space refraction from a water-less pre-pass, and analytic Beer-Lambert absorption using the flat floor for path length instead of a depth pass.
- Seven directional sine swells are the single source of truth — the shader displaces from them and the floating petals sample the same height and slope in JS, and foam is thresholded off the laplacian of the sim height so only real ripple fronts whiten.
physarum-simulation
Reboot of the 2021 slime-mold simulation on Vite and Three.js — up to 1.05M agents steered by three-sensor pheromone sampling on the GPU, now with seven behaviour presets, seven colour ramps and a bespoke control panel.
- Three.js
- GLSL
- Vite
Images
Videos
- Four ping-pong GPU passes per simulation step — agent update, additive point deposit, diffuse-decay, then colorize.
- Agent state packed one agent per RGBA32F texel as position, heading and seed; 320² by default and up to 1024², or 1.05M agents.
- Jones (2010) steering written straight into the update shader: three sensors at ±SA, a turn of RA toward the strongest, random tie-break when both flanks win.
- Pheromone field evolves as decay × mix(field, 3×3 box blur, diffuse) + deposit, wrapped toroidally with fract() so networks never hit an edge.
- Seven behaviour presets that ease every parameter over 750 ms instead of snapping, each bound to one of seven 256×1 palette ramps built as DataTextures.
- Bespoke glass control panel replaces dat.gui — the active palette's accent recolours the whole UI, and drag or double-click feeds pheromone directly into the field.
bira.biro
Night-garden hero where sixteen shader-lit butterflies gather around the cursor or scatter from it — the aurora, the wing iridescence and every flight path are code, the only asset a 5.8 KB untextured wing outline.
- Three.js
- React Three Fiber
- GLSL
Images
Videos
- Sixteen butterflies placed by a mulberry32 seed, each given its own wing speed, glide frequency, wander radius, hue and curiosity.
- A cursor wisp writes position and smoothed speed to a shared attractor — butterflies orbit it when it lingers and flee once it darts past four units per second.
- Wing shader builds thin-film interference bands over a drifting fbm flow field with 34-cell scale twinkle, so no texture is ever loaded.
- Flap phase is integrated rather than sampled, easing the wingbeat into a wings-up glide, with yaw, bank and pitch derived from the frame's own velocity.
- The headline is real 3D text parented to the camera, so a flickering pointer torch rakes specular light across the serifs.
- Aurora sky is a 70-unit back-face sphere driven by five-octave fbm, additively blended above a blurred reflector floor that catches every wing and trail.
black-dots
Single-screen teaser for Exposem — a full-viewport field of 1,250 Canvas-2D dots that drift, wire themselves into clusters over a 20-second intro ramp, and detonate under the cursor, with proximity-driven sound.
- Canvas 2D
- React 19
- Vite
- Tailwind CSS
Images
Videos
- Union-find cluster detection every tenth frame, with clusters inheriting id, age and velocity by member-overlap vote so natural end-of-life explosions can actually fire.
- Cell-based spatial grid for neighbour lookup instead of an O(n²) scan over 1,250 dots, plus a Map index that removes the O(n) indexOf inside the union loop.
- Twenty-second intro ramp eases attraction range, attraction force and connection opacity from zero to 70 / 0.05 / 0.15 by mutating one shared controls object in place.
- Physics and drawing moved onto logical CSS pixels, fixing a device-pixel-ratio bug that simulated 2× past the visible screen on Retina displays.
- Connection segments bucketed into ~40 quantised alpha steps and stroked per bucket, so the per-distance fade renders instead of one alpha for the whole path.
- Mount-once RAF loop with theme and sound flowing through refs — the theme toggle stopped rebuilding the engine and the per-frame setState is gone.
cattyum-online
Experimental 3D menu concept featuring an interactive animated mascot companion that engages users during navigation.
- Three.js
Images
Videos
- Unique 3D menu layout with interactive mascot.
- Mascot with diverse emotes, outfit customization, and music-synced animation.
- Screenshot functionality for capturing character poses.
orb.vibe
Meditative digital environment where an orb character contemplates 'vibes' across a procedurally generated landscape with reactive grass.
- Three.js
- React Three Fiber
- Zustand
Images
Videos
- Instanced grass on terrain surface following its geometry.
- Interactive grass displacement reacting to vibe point proximity.
- Orb controller via ecctrl with user contemplation tracking.
- Atmospheric lighting and ambient grass animations.
da-grass
Open-source system for rendering dense strand-based geometry (grass, hair) on arbitrary mesh surfaces using GPU instancing and custom GLSL shaders.
- Three.js
- React Three Fiber
Images
Videos
- Efficient instanced geometry placement on any mesh surface.
- Noise-driven wind animation for realistic movement.
- GLTF/GLB model support — freely available open-source codebase.
galaxy-experiment
GPU particle system simulating a galaxy with dynamic energy fields and mouse-driven particle manipulation via GLSL shaders.
- Three.js
- GLSL
Images
Videos
- Vibrant GPU particle system with time-based color evolution.
- Spherical energy fields with mouse-driven localized effects.
- Smooth, aesthetically pleasing particle interactions.
slime-mold-simulation
Original version, superseded by physarum-simulation. GPU-accelerated simulation of Physarum polycephalum behavior using Three.js and GLSL, implementing a published biological model of slime mold transport networks.
- Three.js
- GLSL
Images
Videos
- Accurate GPU recreation of Physarum polycephalum emergent behavior.
- Three-point sensor system per agent computed entirely in GLSL shaders.
- Ping-pong buffers for efficient state updates.
- Diffusion-decay trail system producing organic patterns.
- Real-time interaction with thousands of particles and live parameter adjustment.
mixdown
Chrome extension that bulk-downloads the Mixamo catalog (animations, animation packs and characters) by driving the real site in 1 to 8 parallel worker tabs. Every export lands as Name__hash.fbx next to a matching GIF preview, and one shared progress ledger gives resume, retry and live progress from the popup. Version 1.2.0 is published on the Chrome Web Store; the site is mixdown.mulualem.com and the source is public on GitHub. Not affiliated with Adobe or Mixamo.
- JavaScript
- Chrome Extensions MV3
- chrome.downloads API
- chrome.storage API
- Web Audio API
Images
Videos
- A service-worker orchestrator splits the animation catalog into contiguous page slices across 1 to 8 background worker tabs. 'Everything' queues the characters job and the slices over one pool, and a tab that finishes takes the next queued job.
- A download router on chrome.downloads.onDeterminingFilename matches each Mixamo export to a pending expectation and renames it to folder/subfolder/Name__hash.fbx. The confirmed start lets the engine continue after a 1.2 s settle instead of the scripts' fixed 9 to 18 s sleeps.
- The file suffix is an 8-hex FNV-1a hash of the catalog item id, also used on the companion GIF, so same-named clips ('Idle', 'Walking') never collide and every FBX pairs with its preview without a matching step afterwards.
- Engine waits race a local timer against a 'sleep' message that the service worker answers, and a 40 Hz tone at 0.01 gain keeps the tab exempt from Chrome's background-timer throttling, because Mixamo's CSP blocks worker-based timers.
- One progress ledger per catalog in chrome.storage.local, written with a serialized read-merge-write after every item and a resume cursor per slice, so parallel workers do not overwrite each other and skip items that another worker finished.
- Failures keep their page and index, and 'Retry failed' searches for only those items by name. Run state lives in chrome.storage.session, so a restarted service worker continues the run.
- The DOM automation and its timings are a direct port of the two proven console scripts, unified behind one mode table. Their saved localStorage progress is imported automatically on the first load.
tldr.map
Web app that summarizes text and generates interactive mind maps via AI (Gemini/Deepseek), with editing tools, export, and customizable gradient backgrounds.
- React
- Next.js
Images
Videos
- AI-powered text summarization and mind map generation via Markmap.
- Integrated editing tools with secure API key management.
- Export to Markdown and high-resolution mind map image.
- Customizable gradient backgrounds for presentations.
tldr.map chrome extension
Chrome extension that creates visual mind maps from any web page using Gemini AI and Markmap, with dark mode, API key management, and export options.
- HTML
- CSS
- JavaScript
Images
Videos
- One-click mind map generation from any web page via Gemini AI.
- Markmap-based interactive mind map visualization and editing.
- API key management with default model and prompt customization.
- Export to Markdown and high-resolution image.
xar.map
Personal site dedicated to curated, high-quality interactive mind maps of books and information sources, rendered with Markmap.
- React.js
- Next.js
Images
Videos
- Markmap-based interactive mind map rendering.
- Curated, freely accessible library with search functionality.
hum
A quiet iOS focus timer, shipped as hum and on the App Store: pick a duration, hold to begin, and Screen Time mutes the apps that pull you away while a click-wheel iPod plays your Apple Music or Spotify library until the session ends.
- SwiftUI
- FamilyControls
- ManagedSettings
- DeviceActivity
- MusicKit
- Spotify iOS SDK
Images
Videos
- Blocking runs on FamilyControls and ManagedSettings with a DeviceActivityMonitor extension, so the shield lifts on schedule even after the app is killed.
- ShieldActionResponse cannot open a URL, so the ShieldAction extension sets a flag in App Group defaults that the app reads on its next foreground to present the intervention screen.
- Music apps stay playable under a block-everything selection: the exemption is subtracted from the app list and passed as except: on the category policy, and the shield drops briefly while Spotify foregrounds for auth or a playback wake.
- The system FamilyActivityPicker opens with state bled from a sibling picker, so the exemption picker binds to a throwaway buffer seeded per presentation and commits only on a validated Done.
- Device logs showed every foreground writing a 208-app, 13-category, 546-domain shield twice; applyShield now skips a byte-identical rewrite inside 0.5 s instead of removing either caller.
- The click wheel reads an O(1) item count per drag frame instead of building a String array of thousands of MusicKit items, and song queues are capped to a 75-song window so playback starts at once.
- Spotify Web API client with 401 renew-retry, 429 backoff and stale-cache fallbacks, and token renewal that never switches apps after the one user-initiated link.
dynback
Menubar macOS app, in development, that draws live Metal shaders as the desktop wallpaper, in a desktop-level window behind the icons. It has 34 presets with tunable parameters (6 originals, including a 3D Aurora ribbon ported from a WebGL piece, plus 28 ports of paper-design/shaders), a Studio window where the shader fills the whole window, and battery and FPS controls.
- Swift
- SwiftUI
- AppKit
- Metal
- MetalKit
Images
Videos
- Wallpaper is a borderless NSWindow at CGWindowLevelForKey(.desktopWindow) on every display: it ignores the mouse, joins all Spaces, and overrides constrainFrameRect to cover the menu bar strip, so the menu bar material blurs the live shader.
- Frames come from a 120 Hz Timer in the .common run-loop mode that throttles to the FPS limit, with the MTKView paused, because MTKView's default-mode loop froze the wallpaper during menu and slider drags.
- Drawables render at 1x point resolution with a 1920 px limit on the longest side, and pipelines are cached per vertex|fragment|geometry key, so a 3456 x 2234 Retina panel and preset switches do not overload the GPU or stall the UI.
- Aurora is a GLSL/WebGL piece ported to Metal with its vertex shader: a 128 x 64 tessellated plane displaced on the GPU gives a true 3D ribbon in place of a flat fragment-only copy.
- Presets are schemas: each ParamSpec maps a float or colour into a slot of a 32-float uniform array, and the menubar panel and the Studio generate their controls from it, with values clamped on load.
- 28 paper-design/shaders ports; the 6 image presets sample a user image with cover-fit UVs, and a 1x1 white placeholder texture keeps the texture slot bound before an image loads.
- Pause-on-battery is a pure PowerManager.decide() function over the IOKit power source, and a launch-at-login (SMAppService) start is detected from the launch AppleEvent so it stays windowless.
veneer
Native macOS app that turns any image into a folder icon. Drop in folders, pick an image, choose a Closed or Open folder style, see a live preview and apply it to all of them at once; every folder it touched stays in a list with a one-click Reset. In development.
- SwiftUI
- AppKit
- Core Graphics
- Core Image
- Swift Testing
Images
Videos
- Closed style masks the image with the live NSWorkspace system folder icon and overlays a grayscale copy of it, so the shape and shading follow the host macOS version instead of a bundled bitmap.
- Open style is one SVG split into five layers (shadow, back mask, paper strip, front mask, front shading), rasterised to 1024 px PNGs by a script and composited with Core Graphics clip masks.
- Each icon is built as a multi-representation NSImage with hand-rendered 16 to 1024 px bitmaps, so Finder shows a sharp icon at every icon size.
- Re-apply clears the existing custom icon before setting the new one, because Finder only re-reads a folder icon when the kHasCustomIcon bit flips.
- Every applied folder is stored as a JSON record with a security-scoped bookmark, so the Customized list and Reset keep working across relaunches and folder moves inside the sandbox.
- Dropped items pass through one validation step that resolves aliases and symlinks, drops files and packages, and de-duplicates by resolved path.
- The Open-style layer table is a static let built once, which removes a data race under Swift Testing's parallel tests.
watchdog
Open-source (MIT) menu-bar utility for macOS that shows which apps use your Wi-Fi data, per app and per day. Build from source: the code is public at github.com/MULUALEM-TEKLE/watchdog. It polls nettop once a second, folds helper processes into their parent app, keeps a year of hourly history for Today / This week / This month and a stacked-bar Reports view, and has per-app block toggles for a network filter extension that is scaffolded but not yet wired.
- SwiftUI
- Swift 6.2
- Swift Charts
- Swift Testing
- AppKit
- NetworkExtension
- ServiceManagement
Images
- Traffic comes from polling /usr/bin/nettop once a second in CSV mode, so monitoring needs no system extension, no TCC prompt and no paid developer account.
- Deltas are tracked per socket, not per process: each connection keeps its own baseline, a shrinking counter rebaselines without counting, and baselines survive 60 missed ticks so nettop's dropped rows are not counted twice.
- Only internet traffic is counted: remote addresses in private, link-local, CGNAT, multicast and IPv6 unique-local ranges are skipped, so LAN transfers, mDNS and AirPlay do not inflate usage.
- Helper and XPC processes fold into their parent app by resolving each pid with proc_pidpath and cutting the path at the outermost .app bundle.
- History is hourly buckets in one JSON file, keyed "YYYY-MM-DD HH" so a plain string compare prunes it to a year; Today, This week, This month and the Swift Charts reports all merge from the same buckets.
- A 10-second kill switch terminates a wedged nettop (sleep/wake, interface teardown), and the pipe is read before waiting because the output is larger than the 64 KB pipe buffer.
- Blocking is an NEFilterDataProvider system extension kept out of the build until a paid team can sign it; the write-up caught that the root-run extension cannot read the user's app-group defaults, so the block list must move to the filter configuration or XPC.