Rayane Hassani Explore the gameThe game
FR EN
Projects

Portfolio RPG

8–13 msp95 frame time on a 4× throttled CPU, down from 35–45 ms before the performance pass

Not a single image file in the village: scenery, buildings and characters are drawn by code at startup.

Two worldsSharedGamePhaservillage, camera, NPCsand collisionsBridgeEventBridgeevents only, nocross importsInterfaceReactHUD, dialogues andseven interior roomsStartupCanvas2D texturesdrawn once,at startupLanguageLanguage storeoutside React, read byboth worldsContentJSON contentevery project and role,in French and English
Explore the game
The village can be visited on a computer or a phone, in English or French.

Showing how I decide in a few minutes of play

A CV says what you have done, but it shows neither how you make decisions nor the care you put into your work, and a recruiter often gives it no more than a few dozen seconds. I wanted a portfolio that demonstrates those skills instead of stating them, by offering an experience you walk through and whose construction is itself the proof.

The game had to stay smooth on an ordinary computer, read in French as well as in English, and not waste a busy visitor's time, hence a more classic version offered alongside it for those who want to get straight to the point. It is the one you are reading right now, and I sincerely thank you for taking the time to stop by.

Phaser for the village and React for the interface

The application combines two worlds, each with its own role. Phaser runs the village, with its map, its characters, its camera and its collisions, while React handles everything related to the interface, such as the HUD, the dialogue windows and the seven interior rooms where the content is read. Visitors move with the keyboard or the mouse, walk into a building through its door, and the room takes over full screen.

Text goes through a language store written without dependencies, which both Phaser and React read directly, and the content of each project or experience is stored in French and in English in JSON files.

A village drawn in code and a performance pass

The first structural choice was to isolate Phaser and React from each other. The two never call each other directly: they communicate through a single event bus, on which the game announces for instance that a door has been crossed and on which the interface replies that a room has been closed. This separation lets the interface evolve without touching the game engine, and it spared me the side effects that appear as soon as two rendering systems share the same state.

The second choice concerns the village's graphics. Scenery, buildings and characters are drawn by code in Canvas2D at startup, instead of being loaded from image files. This gave me complete freedom over the art direction, down to the outlines of the squares, which I generate with multi-octave noise to avoid shapes that look too geometric. It also caused a performance problem early on: placing one image per tile on a map of that size made the game stutter. I therefore grouped the ground into large textures precomputed in blocks, which brings tens of thousands of tiles down to a handful of textures.

The third choice is the performance pass I carried out before adding content. Phaser walks through and draws its whole list of objects on every frame, including what lies at the other end of the map. I put in place culling that removes distant scenery from that list and adds it back as the camera approaches, switched off particle emitters outside the view, and limited depth updates to objects that actually move, since each change triggers a sort of the whole scene. To measure the gain honestly, I profiled a production build with the CPU throttled four times, because on a fast machine the 120 Hz display hid any difference.

Documentation kept in step with the code

I develop this project with Claude Code, Anthropic's coding agent, which led me to treat documentation as a core part of the project. After a period when it had drifted away from the code to the point where the written decisions no longer matched what was actually running, I rewrote it from an audit and split it into four documents, each with its own update rhythm: a constitution that sets the stack and the locked decisions, a log of the current work, a register of technical debt ranked by priority, and a roadmap of the improvements I want to make.

Frame time down from 35–45 ms to 8–13 ms

The 95th percentile frame time, measured on the central square with the CPU throttled, went from 35–45 ms to 8–13 ms thanks to the performance pass. The village now has seven inhabited buildings, each with its own animated interior room, and all the content is available in French and in English. The next steps are mobile support and deployment on my own server.