Skip to content
vp.Ven Petrov
WorkWritingAboutAt a glance
← Projects & notes
Warloop: Echoes of SolmaraProject story · 3 min read

Warloop: turning generated character art into a playable prototype

Good-looking character images became tiny figures, a backwards walk and misplaced bosses in the game. I worked through the gap between generated art and playable behavior.

Ven PetrovArchived game prototype

Warloop: Echoes of Solmara is a dark-fantasy 2D game prototype. The game-design document came from a collaborator. I worked with Claude Code on turning that design into phases of implementation, using TypeScript and Phaser.

I was concerned about the art from the beginning. I wanted the game to look good, and generating the assets was part of the development problem. I also asked for separate phase documents and session notes, because the work would have to continue across conversations with limited context.

The downloaded image and the character on screen were different tests

The art pass used Ludo.ai for character images and animations. Aurha, the player character, served as a visual reference for later characters. The intended style was detailed 2D dark fantasy rather than pixel art.

The files could look good on their own and still fail in the game. During a playtest I reported that the downloaded characters had good-quality images, but were so small on screen that they were barely recognizable. Aurha also walked while facing the opposite direction, so I asked to invert it.

Those were visible problems I could point to. They weren't answered by a successful image-generation request or a successful build.

Phaser needs to know how to read a spritesheet: an image containing multiple animation frames. BootScene loads it with explicit frame dimensions and creates named animation sequences. The game then has to display the right sequence at a useful size, facing the right way, with a collision body that fits the character.

The development notes record problems with frame layouts, facing direction and body offsets after resolution changes. At one point I adjusted a boss's height manually. Getting a good-looking asset was only the beginning of making that character work in its scene.

An animation should not decide whether the boss was defeated

One bug involved the boss's death animation. The code waited for a 1,500 ms visual effect to finish before reporting the defeat. If the player died during that interval, the scene could restart and cancel the animation. Its completion callback would never run, and the defeat could be lost.

The changed BaseBoss.die() method reports the game event before playing the visual effect. It marks the boss dead, stops movement, disables collision, creates the rewards and emits boss-defeated. The animation comes afterward; its final callback only destroys the sprite.

Defeat is recorded before the 1,500ms fade

  1. 01isAlive = falseIgnore a second defeat call
  2. 02Disable bodyStop movement and collisions
  3. 03boss-defeatedCreate rewards and emit the event
  4. 04Fade, destroyThe callback only removes the sprite
The event no longer depends on the tween completing. Other reported level and boss-placement problems remained unresolved.

The early dead-state check also stops the same defeat from being processed twice. The ordering lets the game finish the important transition even if the screen changes before the visual effect ends.

The zone code has related cleanup: reset the enemy list and boss reference when a scene starts, and remove its player-death and shadow-defeat listeners when it shuts down. Otherwise an old scene can keep responding to events after it is no longer the active one.

Keep the mistakes with the project

I asked whether we had a file for the pitfalls we were finding and fixing, so a later session would know what to do and what to avoid. The resulting record covers scene reuse, event listeners, the delayed defeat event and sprite geometry.

That record mattered because I was continuing through separate development phases. I wanted the next session to know what had been built and what remained, rather than rediscover the same problems from a fresh prompt.

The prototype reached generated characters, animations and game scenes, and Vite builds passed during development. It wasn't finished. In later playtesting I still couldn't find bosses in several levels and asked for their placement to be checked. Those remaining playability problems belong alongside the parts that worked.

Project sources & checks
Starting brief

The user starts from a game-design document supplied to the project, suggests Phaser and asks for phased implementation, persistent session notes and a plan for high-quality art.

Art and playtest feedback

Actual Ludo.ai source operations and user feedback cover character art, animation integration, tiny in-game characters, reversed walking direction, a manual boss-height adjustment and later missing bosses.

Code example

BaseBoss.die records the defeated state, disables its body, creates rewards and emits boss-defeated before its 1,500 ms visual tween. ZoneScene resets state and removes its player-death/shadow listeners on shutdown.

Current limits

Successful historical Vite builds and selected archived source support the implementation. The original project folder is unavailable on this Mac, and there has been no fresh complete playthrough.

On this page
The downloaded image and the character on screen were different testsAn animation should not decide whether the boss was defeatedKeep the mistakes with the projectSources & checks
TypeScriptPhaserLudo.aiState machinesGame development

Connected to this

All writing
Between Us · Project story

Between Us: why I kept the first take and widened the shot

Ven PetrovSoftware engineer · Barcelona
GitHub ↗LinkedIn ↗Email ↗

Find a project or a note

17 results

Transfutur ERP · ExperienceERP for transport and logisticsAs the sole engineer, I built an ERP from zero for transport and logistics. It supported roughly €5–6 million in annual invoicing across two offices, and I kept it running for about a year.Financial review lab · Project storyExploring a financial report with Python and FastAPII started with one income change, then opened up the same 54-page report: products, regions, cash flow, core adjustments and a dataset whose figures lead back to the source.Crude-oil narrative tracker · Project storyCrude-oil research from global news and market dataI wanted help following global events that could matter for crude oil. The prototype combines news research with calculated market and position values, while keeping recent assessments separate from the longer numeric history.MNQ time-series research · ExperimentTime-series prediction experimentsAn exploration of high-resolution market data: choosing what to acquire, checking its limits, comparing time intervals and testing whether a prediction survived later data and the cost of acting on it.NQ/MNQ backtest engine · Technical noteA missing closing bar left the simulator’s short position openThe strategy reset for a new day while a shared counter still counted yesterday’s short. A small replay shows why closing the position has to happen before clearing its state.Small-cap edge research · Project storyTurning small-cap trading ideas into repeatable researchI asked Claude Code for a fresh research system that could test named price patterns, compare later periods and carry its methodology into new sessions. One candidate shows how features, entry timing and costs fit together.Gadgeon Europe applications · ExperienceConnected-device dashboards and mobile apps at Gadgeon EuropeI worked on Ionic and Angular applications that brought several APIs into dashboards for energy monitoring and connected-device control, with releases and maintenance across multiple client versions.ctxforge · Project storyctxforge: discovering what to build before codingA context discovery framework that asks an LLM to act like a senior engineering interviewer: understand the idea, uncover requirements and agree the scope before an agent starts building.Sociedades Inactivas enquiries · Technical noteSaving an enquiry before trying to send its emailOn the Sociedades Inactivas catalogue, a visitor can ask about a company or send a general enquiry. The form separates saving that request from delivering its notification, including when the visitor retries.Astro local-services website · Project storyA local-services site assembled from city, service and FAQ recordsThe Astro site describes flooring and other local services across different cities. Shared templates check availability, read the matching content and select one FAQ set for both visitors and structured data.3D Spaces website migration · Project storyMoving 3D Spaces to Next.js while its email stayed on the old serverI rebuilt the virtual-tour website with AI coding collaborators, preserving its content and URLs. The cutover also had to protect the mailbox, enquiry flow and existing analytics history.Capture CRM · Project storyConnecting classified listings to contacts in a small CRMA Chrome extension and Next.js dashboard bring classified listings, platform profiles and contact history together. Saving a listing again can add the person who was missing from an earlier import.Product-description comparison bench · ExperimentComparing one model call with separate vision and writing stepsA small product-description tool lets me inspect the visual analysis before the copy is written, change the model used for each step and compare request measurements.Between Us · Project storyBetween Us: why I kept the first take and widened the shotI compared dialogue takes, asked for wider shots and more physical acting, then changed the workflow when its studio limited the scenes I wanted to make.Restaurant-service voice agent · ExperimentDesigning a restaurant-service call around the real offerI worked through a Spanish outbound agent prompt, corrected a free visit to the actual paid service and compared how two drafts handled transfers and bookings.Vapi and Telnyx voice integration · Technical noteThe Vapi agent could speak, but it could not hear me clearlyMy Telnyx number connected to the assistant, but the caller audio was distorted. Three codec tests recovered the connection without fixing that original problem.Warloop: Echoes of Solmara · Project storyWarloop: turning generated character art into a playable prototypeGood-looking character images became tiny figures, a backwards walk and misplaced bosses in the game. I worked through the gap between generated art and playable behavior.
esc to close · Tab to move through results