Portfolio

Live demos and coding projects, grouped by category — from algorithms and simulations built from scratch, to real-time multiplayer systems and everyday web apps. This website itself belongs on this list too: a bilingual site built from scratch with PHP, CSS and vanilla JavaScript, with an AI pair-programmer alongside. Pick a category and explore.

Beam Analysis

An interactive structural beam calculator — shear force and bending moment diagrams plus deflection, solved analytically with Macaulay's method. Set the supports, point loads and a distributed load, and watch the diagrams update live.

  • Structural engineering
  • Macaulay's method
  • SVG
Open demo →

Truss Analysis

A 2D truss solver using the direct stiffness method — the same matrix structural analysis used in real FEM software. Set the span, height, panel count and loads; member tension/compression and the deflected shape update live.

  • FEM
  • Stiffness method
  • Structural engineering
Open demo →

Modal Analysis

Natural frequencies and animated mode shapes of a beam, from a consistent-mass FEM eigensolver written from scratch (Cholesky reduction + Jacobi rotations). Every frequency is compared live against the exact closed-form solution — including, with a tip mass, the root of the transcendental characteristic equation.

  • FEM
  • Eigenvalues
  • Vibration
Open demo →

Composite Laminate

Classical Laminate Theory from scratch: stack plies at any angle and get the ABD stiffness matrix, the effective laminate constants, the directional stiffness rosette, per-ply stresses and the Tsai-Wu first-ply-failure load factor. A quasi-isotropic stack comes out isotropic even though not one of its plies is — which is the check that it works.

  • Composites
  • CLT
  • Tsai-Wu
Open demo →

Engine Cycle

A crank-angle-resolved engine simulation: real slider-crank kinematics, Wiebe finite heat release and Woschni wall heat transfer, integrated with RK4. Shrink the burn duration and the simulated efficiency converges onto the ideal Otto cycle — the textbook cycle falls out as a limiting case. Sweeps the spark advance to find MBT timing.

  • Thermodynamics
  • ODE / RK4
  • Combustion
Open demo →

micro-GPT

A character-level transformer — attention, LayerNorm, GELU, Adam, and the reverse-mode autodiff engine that trains it — written from scratch in one file with no libraries, and trained live in your browser on the text of this site. What it writes is nonsense, and the demo says so; the claim it actually makes is measurable. The loss has to cross the bigram entropy of the corpus — the best score any model that only ever reads the previous character can achieve, obtained by counting — and crossing it is the moment attention starts paying for itself. Every one of the engine's gradients is checked against finite differences, and the causal mask is proved exact: perturb a future token and earlier logits stay bit-for-bit identical.

  • Transformer
  • Autodiff
  • Attention
Open demo →

RL vs LQR

An inverted pendulum on a cart, driven by two controllers side by side: LQR, whose gain comes out of a Riccati equation and is provably optimal for the linearised problem, and a 113-weight neural policy trained live in your browser by evolutionary search, which knows no physics at all. Each one fails badly in the other's regime, and the demo measures rather than asserts it: near upright the policy may never score below the optimum — a theorem, and a check — while from hanging, LQR stands the pole up from 2 of 30 starts against the hybrid's 25. So the shipped controller is Åström's: the network swings, the Riccati gain catches.

  • Reinforcement learning
  • LQR / Riccati
  • Control theory
Open demo →

PINN vs FEM

A neural network solves an Euler-Bernoulli beam from the physics alone — no data, ever: the loss is the differential equation. It trains live against two rivals, the closed-form solution and my own finite element solver, on a hand-written autodiff engine (Taylor jets over a reverse-mode tape, so the network can be differentiated four times with respect to its own input). And FEM still wins — the demo says so out loud, and shows exactly where the network earns its keep instead.

  • PINN
  • Autodiff
  • FEM
  • Deep Ritz
Open demo →

Neuroevolution

A population of 150 neural networks teaches itself to play Flappy Bird through a genetic algorithm — no trainer, no data, just natural selection across generations.

  • Genetic algorithm
  • Neural nets
  • AI
Open demo →

Connect Four · AI

Play against an AI written from scratch: minimax with alpha-beta pruning, adjustable search depth and a live view of how many positions it evaluates each turn.

  • Minimax
  • Alpha-beta
  • AI
Open demo →

Autograd Engine

A reverse-mode automatic differentiation engine written from scratch — the scalar core is about 200 lines of Python with no PyTorch and no NumPy autodiff, just a Value class, a computational graph and the chain rule — alongside a second n-dimensional engine whose every backward pass, including the adjoint of broadcasting, is hand-derived. That rewrite is worth ~5,000x on the same 337-parameter problem, and the reason is counted rather than asserted: 129,938 graph nodes per forward pass collapse to 23. Correctness is pinned to truths outside the engine — hand-derived Hessians, the closed-form (p − y) gradient of softmax cross-entropy, and the exact normal-equations solution the training loop is required to land on — then double-checked against PyTorch, which agrees to zero in places. 210 checks. The benchmark caught itself flattering the engine, too: an early run claimed it beat PyTorch, which turned out to be PyTorch measured cold. A static write-up, not a live in-browser demo.

  • Autodiff
  • Python
  • NumPy
Open demo →

GPU Neural Trainer

A tensor/autodiff engine written from scratch with two backends — plain JS and hand-written WebGPU compute shaders in WGSL, forward and backward, no TensorFlow.js, no ONNX Runtime — training a 2-layer MLP live in the browser on 8×8 handwritten digits (sklearn's load_digits, baked in at build time, no fetch). The CPU reference engine is gradient-checked against central finite differences on all 167 parameters of a real network to under 1e-6 relative error, and trained end-to-end to 97.8% held-out test accuracy (351/359 unseen digits, on a network that separately reaches 100% on its own training set — so the gap is honestly the generalisation gap, not a leak). Because the GPU kernels run in float32 while the reference runs in float64, they can't be bit-exact — so instead of asserting a number, the page ships a live self-test panel that runs an identical forward+backward pass through both backends, on real digit images, in your own browser, and reports the measured max deviation (five decimal places, not a claim) against a stated 5e-3 tolerance. Writing the mode-2 backward matmul kernel by hand surfaced a real indexing bug — the uniform buffer was packing the wrong operand's row count into the output stride — caught by re-deriving each WGSL kernel's index arithmetic against its own docstring rather than trusting that it compiled. A benchmark panel times CPU vs GPU training steps across several batch/width combinations live and reports whichever way it actually comes out — kernel-launch and buffer-transfer overhead means a small MLP can easily lose to a tight CPU loop, and the page says so rather than picking favourable numbers. No WebGPU means an automatic, fully working CPU fallback, not a blank page.

  • WebGPU
  • WGSL
  • Compute shaders
Open demo →

Diffuzie

A DDPM-style denoising diffusion model — forward noising process, a 109,632-parameter noise-predicting MLP, ancestral reverse sampling, all on a hand-written tensor/autodiff engine with no PyTorch, TensorFlow or JAX in the shipped model — trained offline on sklearn's 1,797 8×8 handwritten digits, with the reverse process animating live in your browser from a hand-ported JS inference engine checked against the trained Python model to ~1e-7. Before a single real digit was generated, the machinery was pinned to four closed-form or Monte Carlo ground truths (48 checks): the forward process's empirical mean/variance against the closed form q(xt|x0) across 11 timesteps and two independent code paths; a noise predictor trained on a 3-Gaussian toy mixture converging to within 0.6% of its provable Bayes-optimal loss; a finite-difference gradient check on every parameter (~1e-11) doubled by an independent PyTorch oracle agreeing to machine precision; and a reverse-chain consistency check that, fed the exact optimal denoiser, had to reproduce the toy distribution's known statistics from both pure noise and a mid-trajectory noised state — which caught a real finding along the way: at only 50 reverse steps this check measurably failed (one mixture component absorbed nearly double its true sample share) even with the exact score plugged in, so the shipped model runs 1,000 steps, not 50. On real digits: generated samples average 2.50 L2 distance to their nearest real neighbour (vs. 2.05 real-to-real, vs. 7.09 for uniform noise — not memorized, not degenerate), and an independently-trained classifier assigns the intended class to 96.8% of samples, confidently (p>0.8) for 91.3% — with digit "8" as the honestly-reported weak point at 85%/62.5%.

  • Diffusion models
  • DDPM
  • Autodiff
Open demo →

Scriitor (nano-LLM)

A 1,069,824-parameter decoder-only transformer — 4 layers, 4 heads, a 128-token context over a 1024-entry byte-level BPE vocabulary — trained offline on one CPU in 8.7 minutes on 1.70 MB of public-domain English and Romanian prose (Austen, Carroll, Caragiale, Slavici, Queen Marie; every download SHA-256-pinned, Gutenberg boilerplate stripped), then written a second time from scratch in JavaScript and shipped here. That is 44x the parameters and 37x the corpus of the micro-GPT above, with a context reaching ~320 bytes of text instead of 32 characters. No PyTorch, TensorFlow or JAX anywhere in the model that trains or runs it: every gradient flows through a hand-written reverse-mode autodiff engine, and torch appears in exactly one test file as an optional oracle — where it agrees with that engine on all 660,992 parameters of a full-width model to 1.7e-15. The headline claim is not that it writes well — it does not. It is that two independently written implementations of the same forward pass (the JS was written against the architecture prose, never transpiled from the Python) agree on the same dequantised int8 weights to 1.6e-14 on every logit, produce an identical argmax at all 384 test positions, and emit an identical 200-token sample — exact integer equality, no tolerance to hide behind. 232 checks in total (189 Python + 43 JS), each pinned to something outside the thing being checked: central finite differences on all 1,336 parameters of a complete tiny transformer; the causal mask as a bit-for-bit identity; a zero-layer model that must converge onto a counted bigram table (max Δp 1.21e-05) whose entropy must itself recover the true entropy of a Markov chain it was never told about; an exact int8 error bound asserted elementwise on 1,064,960 values; and a contamination scan finding 0 of 2,000 held-out 64-token spans in the training stream. On held-out text it reaches 2.3846 bits/byte and beats the counted bigram floor it was never shown by 0.19 nats/token (and each language beats its own floor separately: EN +0.24, RO +0.16). Two honest failures are published rather than tuned away: it loses to a counted trigram model by 0.39 nats — found only by refusing to score against a deliberately over-smoothed baseline the model would have "beaten" — and the training curve shows it is under-trained, falling monotonically across all 12 evaluations and stopping before its minimum, which is very likely why. An independent character-trigram classifier (validated at 100% on human text first) says 98.8% of continuations stay in the prompt's language, and the verbatim-copy rate is 0.0% — so it learned rather than memorised. What it actually writes is locally fluent and globally nonsense, and the page says so.

  • Transformer
  • BPE tokenizer
  • Offline training
Open demo →

Search Engine

A search engine built from scratch in PHP — inverted index, BM25 ranking and typo tolerance — searching the real content of this site.

  • PHP
  • Inverted index
  • BM25
Open demo →

Sales Dashboard

Interactive analytics dashboard — data generated in PHP, charts rendered with Chart.js.

  • PHP
  • Chart.js
  • JavaScript
Open demo →

Daily Brief

A personal dashboard combining local weather and relevant news, with simple context-based suggestions (rain → take an umbrella, heat → stay hydrated). Built with Next.js, TypeScript and React Query; all external API calls are proxied server-side so keys never reach the browser.

  • Next.js
  • TypeScript
  • React Query
Open demo →

Booking App

A slot-booking app for escape rooms/coaching sessions, with admin cancellation and password reset. Overlap prevention is a Postgres exclusion constraint, not a check-then-insert race in application code — verified with a real two-transaction concurrency test. Row-Level Security keeps customer data out of the public calendar entirely.

  • Next.js
  • Supabase
  • PostgreSQL
Open demo →

Record Shop

A test-mode vinyl shop — browse and filter the catalogue, add to cart, and check out. The client never sends a price: it sends product ids, and the server re-reads every price from the database before building the Stripe Checkout session. An order is marked paid only by a verified, idempotent Stripe webhook — never the success redirect — and stock is decremented in the same step. Every sleeve is generated procedurally from a seed, so there is not a single image file.

  • Next.js
  • Supabase
  • Stripe
Open demo →

Voronoi & Delaunay

A Delaunay triangulator built from scratch with the Bowyer–Watson algorithm, drawn live alongside its dual Voronoi diagram. Scatter the points or drag them and the mesh re-triangulates instantly. Delaunay triangulation is the meshing that underlies every FEM solver — so every triangle is checked live against the empty-circumcircle property, and the harness pins the mesh to Euler's counts, the nearest-neighbour theorem and exact convex-hull tiling.

  • Computational geometry
  • Bowyer–Watson
  • Meshing
Open demo →

Contour Lines

Smooth iso-contours pulled from a live scalar field with marching squares — the exact post-processing step a CAE tool runs to draw a stress plot. Drag the Gaussian sources and the contours redraw in real time. With linear edge interpolation the contour of any linear or bilinear field is exact to machine precision — the verify panel proves it live, and shows a circle's contour length converging onto 2πr as you refine the grid.

  • Marching squares
  • Isosurfaces
  • Canvas
Open demo →

Fourier Epicycles

Draw any closed shape and a chain of rotating circles retraces it — each circle is one term of the Discrete Fourier Transform. Slide the harmonic count and watch the approximation sharpen. It is mesmerising but exact: the demo checks the DFT→IDFT round-trip and Parseval's energy identity live, and the harness pins the transform to eight discrete-Fourier theorems (single-frequency, shift, linearity, best-K convergence).

  • DFT
  • Signal processing
  • Canvas
Open demo →

Cloth Simulation

A mass-spring cloth integrated with Verlet and position-based distance constraints — grab it, tear it, blow wind through it. Verlet integrates constant gravity exactly, and the constraint solver is pinned to real mechanics: one rigid link swings with the exact pendulum period 2π√(L/g), and a chain pinned at both ends settles onto the analytic catenary y = a·cosh(x/a) to within a fraction of a percent.

  • Verlet integration
  • Physics
  • Constraints
Open demo →

Sorting Visualizer

Watch bubble, insertion, quick and merge sort race each other, with live stats and speed control.

  • Algorithms
  • JavaScript
  • Canvas
Open demo →

Ray Tracer (WASM)

A physically-based path tracer — diffuse, metal and dielectric materials, emissive quads and boxes for a Cornell box preset, a BVH over the scene, Russian roulette path termination — written in C++ and compiled to WebAssembly, rendering sample-by-sample straight into the canvas. The BVH is proved to change nothing but speed: bit-for-bit identical framebuffers with and without it. The headline check is the white furnace test — a convex object in a uniform-radiance environment must render exactly albedo × L, so a perfect reflector disappears against its background — plus Russian roulette proved unbiased, camera geometry checked against closed-form projection relations, an area light checked against the Howell configuration-factor equation, and convergence refit in linear light (not gamma-corrected pixels) to the correct 1/√n slope. It also states its own weak point instead of hiding it: with no next-event estimation, the small bright light in the Cornell box measures 22x noisier than the sky-lit scene at equal sample count. 105 checks, all against closed-form ground truth or bit-exact identities, not the renderer's own output.

  • C++
  • WebAssembly
  • Path tracing
Open demo →