Mohammad Mohammad
Open to Summer 2027 internships
I build gameplay systems in C++ and Unreal Engine 5, and the tools and tests that keep them honest.
Computer science at Carleton University in Ottawa, graduating May 2028. By day I build C# test automation for the Department of National Defence.
- 4 cities, 6 missionsin LinguaSpy, my UE5 C++ spy game
- 23 automated testsrun headless on its gameplay and learning core
- 100% at 150 msof on-screen hits registered with my lag compensation
Work
Hitreg Lab
A UE5 C++ first-person test range for how shots feel and register: data-driven weapons, controller aim assist, client prediction with server-side rewind lag compensation, a peeker's-advantage meter and a kill cam, all measured over a dedicated server.
A UE5 C++ FPS lab: lag compensation, peeker's advantage, aim assist and a kill cam, all measured.
LinguaSpy
A top-down spy game about learning a language. You keep your cover in Paris, Madrid, Tokyo or Rome by answering locals in French, Spanish, Japanese or Italian.
A UE5 C++ spy game: keep your cover by answering locals in French, Spanish, Japanese or Italian.
Raytracer
A CPU path tracer in C++17, started from Ray Tracing in One Weekend. I fixed five sampling and shading bugs and added a binned-SAH BVH, OpenMP rendering and Russian roulette.
A C++17 path tracer. I fixed five rendering bugs and added a SAH BVH, OpenMP and Russian roulette.
Hitreg Lab
A first-person test range in Unreal Engine 5 and C++ for studying how shots feel and how they register. It has data-driven weapons, controller aim assist, client-predicted firing with server-side rewind lag compensation, a peeker's-advantage meter and a kill cam. Every system is measured over a dedicated server with two clients, not just built.
- 100%of on-screen hits registered up to 150 ms ping with lag compensation, vs 23–30% without
- 76 → 247 mspeeker's advantage at 60 Hz as round trip goes from 0 to 150 ms (160 measured trials)
- ~4 msclock-sync error under 40 ms jitter; the engine's own clock was off by 40–70 ms


Read the write-up: the shot pipeline, the rewind, and three bugs the measurements caughtSource on GitHub
LinguaSpy
Solo projectPrototype v0.6
A top-down spy game about learning a language, in Unreal Engine 5.8 and C++. You're undercover in Paris, Madrid, Tokyo or Rome and keep your cover by answering locals in French, Spanish, Japanese or Italian. Wrong answers drain the cover meter. Blow it and you're sent back to drill the phrases you missed.
What's in the C++: a sentence grader that marks each word and spots accent-only mistakes, a Leitner spaced-repetition scheduler, a policy that picks the exercise type from how well you know a phrase, branching dialogue and mission graphs stored as data assets, a versioned save format with migrations, and a Slate editor tab for authoring conversations. 23 automation tests cover the pure logic.
- Engine
- Unreal Engine 5.8
- Code
- C++ game and editor modules, 23 automation tests, Python editor tooling
- Built
- Sept to Nov 2026
- Build
- Windows build and 80-second trailer
Four cities, one set of systems
Paris in French

- 9 conversations, 2 missions, 2 assessment forms
- Voiced offline with Piper TTS
- Operation First Contact: order a coffee from Camille at the café
Madrid in Spanish

- 9 conversations, 2 missions
- Text only for now; Spanish voices are on the list
- La Tapa Secreta at the tapas bar; El Palacio is the A2-level mission
Tokyo in Japanese

- 3 conversations, 1 mission
- Konbini Contact: buy an onigiri from Sato-san
- Unspaced chunk tiles with optional romaji readings; text only because of the voice licence
Rome in Italian

- 3 conversations, 1 mission
- Protocollo Espresso: ask Giulia the way to the fountain
- Text only for now; Operazione Colosseo is still to be built
Answer a local
TypeScript port of the game's C++ grader and scheduler, tested against the same cases. The game itself is C++; this runs in your browser so you can try the rules without installing anything.
No French needed: leave out a word, or drop an accent, and watch what the grader says. The six boxes underneath are the Leitner scheduler; the clock buttons skip ahead so phrases come due.
Read the full write-up: grader, scheduler, save format, editor toolWatch the trailer
Raytracer
A CPU path tracer in C++17, extended from Peter Shirley's Ray Tracing in One Weekend with triangles and OBJ meshes, light sampling, normal maps and JSON scenes. Version 2 adds a binned-SAH BVH, OpenMP rendering, Russian roulette, fixes for five sampling and shading bugs, and a WebAssembly build that runs right here in your browser.
Static renderhero_materials.json, 960×540, 1024 samples per pixel, from the WebAssembly build of my path tracer. Press the button to watch it render here, on your CPU.
Drag the image to orbit. Every move throws away the samples and starts again from noise.
Converging
Scroll, or drag the slider: the same scene from 1 to 256 samples per pixel.

Three of the fixes, side by side
Drag across the image. Each pair is the same scene rendered from the commit before and the commit after the fix.
Random number range

b79885c
351cc24random_float kept its distribution in a function-local static, so it kept the range of its first call, [0, 1). Every later request for [-1, 1) got [0, 1) too, and random points in the unit sphere and disk came from one octant only. Compare the fuzzy metal sphere (almost a sharp mirror before) and the defocus blur on the near yellow sphere.
Transposed TBN matrix

b79885c
3c6446aDebug view: colour is 0.5 × (n + 1). glm::mat3 takes columns, so typing T, B and N in row by row built the transpose, the world-to-tangent matrix. After the fix every sphere is green on top (+y), red on the right (+x) and blue toward the camera (+z).
Direct light, 1/π

8d651dd
704fd0cThe light-sampling term computed radiance × cos / pdf with no 1/π, so direct light was π times too bright, and it was added to mirrors and glass, which made them look partly matte. Now it is (albedo / π) × L × cos / pdf, for diffuse surfaces only.
The BVH, measured
Without a BVH every ray tests every object. Mine bins primitive centroids into 16 buckets per axis, picks the split with the lowest surface-area cost, stores the tree in one flat array and walks it near child first.
bvh_bench against a bumpy sphere tessellated into more and more triangles. Measured on an Intel Core i5-14400F, Windows 11, one thread, WebAssembly build (wasm32-wasi, clang -O2) running in Node 24.20. Native builds are faster; the ratios are the point. Brute force ran on a subset of the same rays for the big meshes, and its hit distances matched the BVH for every ray.All measured values
| Triangles | SAH build (ms) | BVH nodes | BVH, SAH (Mrays/s) | BVH, midpoint (Mrays/s) | Brute force (Mrays/s) | Speed-up, SAH vs brute force |
|---|---|---|---|---|---|---|
| 128 | 0.7 | 123 | 8.015 | 8.422 | 0.97074 | 8× |
| 1,058 | 1.4 | 1,125 | 5.34 | 3.953 | 0.08136 | 66× |
| 8,192 | 14.7 | 8,805 | 3.055 | 2.833 | 0.00982 | 311× |
| 32,768 | 48.5 | 35,681 | 2.86 | 2.238 | 0.00238 | 1,202× |
| 131,072 | 244.2 | 142,811 | 1.703 | 1.546 | 0.00048 | 3,513× |
| 524,288 | 1070.7 | 570,307 | 1.543 | 1.393 | 0.00013 | 11,585× |
A whole render of hero_knot.json (17,287 objects, smooth-shaded knot, 320×180, 4 spp) took 0.44 s with the BVH and 111.0 s without it, about 250× faster. The two output images were byte-identical.
Read the full write-up: each fix and the maths behind itSource on GitHub
About
I'm a computer science student at Carleton University (B.C.S. Honours, AI and Machine Learning stream), graduating in May 2028, and I want to spend my career on the code that decides how a game feels in your hands.
I play Black Ops 6 and Overwatch, and that's a big part of why I'm aiming at gameplay programming: movement, gunplay and hit registration are the systems I most want to build.
My day job is testing other people's software. Since May 2026 I've been a QA automation developer at the Department of National Defence, on a C# framework that turns recorded interactions into Excel-driven Selenium tests. I built its debug mode: a failed run pauses, the tester fixes the step in the spreadsheet, and the run resumes from the last passing step. Before that, from January to April 2026, I was an IP network engineering intern at Nokia, writing Python and Tcl regression suites for protocol state machines. Both jobs left me with a habit you'll see across these projects: if a system matters, it gets an automated test.
Also on this site: TitanInfer, a C++20 neural-network inference library with a cache-blocked AVX2 matrix multiply.
The fastest way to reach me is email: mohpresentations@gmail.com. My résumé is a PDF, my code is on GitHub, and my work history is on LinkedIn.










