← Devlog
v0.3.7-pre-alpha

Ultraviolet v0.3.7-pre-alpha: the map folds up, and a second cleanup pass

Four builds in one post, and only the first three change anything you can see. v0.3.3 gave you a boss and swings you could read. Since then the mission stopped being a corridor.

v0.3.4–v0.3.6 were tagged but never pushed here, so this build carries all four at once.


The mission is a map now, not a line

The old mission was a chain of rooms you walked through one at a time, streamed in as you crossed a seam. The new one is one continuous map — every room standing at once on a 640×360 grid — and the generator places it with a self-avoiding walk in two dimensions: right, up, down, sometimes doubling back. So the map folds into vertical (about 8×4 cells now, against the old 17×1 straight line) and can loop back on itself.

The biggest piece of this was a measurement, not an idea: all sixteen of the old rooms were already sitting on that 640×360 grid, to the pixel — the camera bounds, the door positions, the spawn point, the floor height, all of it was a function of the grid cell. Nobody had named the grid. Naming it turned “stitch the next room onto the last one” into “read the room’s position off the grid”, and a whole class of seam-alignment bugs stopped existing.

The room pool was rebuilt from zero for this. The old rooms were corridors — one way in, one way out — and you can’t retrofit vertical travel onto a corridor. The new tiles come from one template: every tile has four sides, all sealed, and the map opens only the ones it actually connects. A hole in the floor and a hole in the wall are the same operation now. Down the middle of every tile runs a vertical column: a shaft to climb and a hole at its base, on the same axis — because a climb that ends under a solid floor isn’t a passage.

Three numbers in that column are measured, not chosen: the climb channel is 88 px wide (that’s all the climb can carry), the crossing is 64 px (bodies are 34), and the drop-hole is 64 px (a jump clears ~79, so you leap the horizontal route over the gap).


Wall-jump

A grid cell is 360 px tall. A double jump reaches about 76. Stairs sit 26 apart. A vertical link built out of ledges would be a fourteen-rung ladder — so, wall-jump, with three rules from design:

The wall_contact / wall_slide / wall_jump sprite strips have been sitting unused in the project since long before this. They finally play.


A camera that looks where you’re going

The camera used to sit dead centre on the player. Now it leads your movement, it looks up or down when you ask it to, and when you’re falling fast it looks down on its own — so you see the ground before you land on it. The frame is a little wider than before (you see about 36% of a room instead of 29%).

One thing came free with this: Camera2D.offset finally has a single owner. The screen-shake was zeroing that field every frame, so anything else writing to it would have vanished without a trace. The design caught that before a line of code was written.


Minimap

A small view in the corner the whole mission, and the whole discovered map on a held Tab (stacked above the read-only relic/tattoo/souls panel that Tab already showed). The discovery rule: a room you’ve been in shows in full, a room next to one you’ve been in shows as an outline only, everything else doesn’t show at all — and a secret room never shows before you’ve walked into it.


One player for the whole mission — doors don’t heal any more

This is the change you’ll feel most. There used to be a fresh Player instance in every room host, and a component that sets your health to full when it loads — which meant every screen wipe healed you back to full. A branch, a secret, the walk up to the Legion arena. You always fought the boss on a full bar.

Now nothing swaps the scene mid-mission, so nothing re-runs that. Your health carries the whole way down. Secrets, the reliquary and the boss arena open up inside the mission scene, next to the frozen map — so you come back out the same door, the map doesn’t reset, and the dead stay dead. You go down to Legion with what you have left.

The design decision that pays for this — a guaranteed chapel before the boss door, to heal at a cost — doesn’t exist yet. For now the run is one unbroken resource curve, and whether that’s bearable without the chapel is an open question for this build.


Three rounds of playtesting and one line of code

Across v0.3.6 the map got played three times and every time the report was about geometry: “can’t reach the rooms higher up”, “walking right you fall out of the map forever”, “this level can’t be finished”. Real things got fixed along the way — a missing kill-plane in the mission scene, décor sitting in the walk path (39 px of clearance for a 34 px body), a mirrored wall-slide animation, an unresponsive wall-kick — and the pool was rebuilt.

But the cause of all three reports was one line: the spine connector was writing every edge as “right”. The rooms stood in the right places (position comes from the grid cell), but the data about the rooms lied about which way each door faced — and the seals, the portals and the minimap all trust that data. 479 of 500 seeds were unwinnable. Look in the description, not in the thing described.


v0.3.7 — the second cleanup pass

Like v0.3.0 a while back, this is a version with no gameplay changes on purpose. Same correctness bar — it plays exactly the same — and this time it’s proven: the map generator produces a byte-for-byte identical map for the same seed across 60 seeds, against the pre-cleanup code. The test suite went 31 → 33.

Nine phases, each collapsing one piece of duplication: physics-layer exclusions that four different places had each worked out; a marker convention two systems had each learned differently; three near-identical HUD bars into one; the portal, the reliquary and the NPC into one interactive-object base; two long methods broken into the steps they already were; the test scaffolding that every suite had been rebuilding for itself. Plus a pile of dead code and four doc comments that had drifted onto the wrong function.

The one visible change: the wall_contact / wall_slide frames draw the body a few pixels shy of the cell edge, and unlike the ledge-hang there was nothing correcting for it — so the wall-slide pose floated a little off the wall, on both sides. It’s pinned to the wall now.


Controls

Unchanged since v0.3.3, with wall-jump added.

ActionKeyboardPad (Xbox)
Move← / →left stick / d-pad
Jump (double)Space / EnterA
Wall-slide / wall-jumphold toward the wall in the air to slide · jump to kick offsame
Melee (3-hit combo)A — tapRB
Charged attackA — hold ≥ ~0.5 sRB — hold
Third-hit varianthold ↓ heavy · nothing = fast · ↑ = air launchersame
Block / parryD — hold / tap just before the hitLT
Riposteautomatic — hit within 0.4 s of a parry, same enemysame
Dodge (dash, i-frames)ShiftLB
Shoot (8-way)SRT
ReloadR (auto on empty)Y
Interact / throw-outEX
Look up / down↑ / ↓ held (standing still)same
Full map + overview (held)TabSelect
Pause / menuEscStart
Ledge grabautomatic; climb = jump / ↑, drop = ↓same

Note: a small minimap sits in the corner the whole mission. Holding Tab opens the read-only overview — which now leads with the full discovered map, then the active relic, your tattoos and your soul count.


How to run it

SystemFileNotes
Windowsultraviolet.exe (+ ultraviolet.pck beside it)SmartScreen may warn about an unsigned file — “More info” → “Run anyway”.
Linuxultraviolet.x86_64 (+ .pck beside it)chmod +x, then ./ultraviolet.x86_64.
macOSUltraviolet.appUnsigned: right-click → Open → confirm, or xattr -dr com.apple.quarantine Ultraviolet.app.

Quitting: Esc in the main menu closes the game. In a run, Esc opens the pause menu — quit to the main menu from there.


Still pre-alpha — what’s not here


How to report feedback

BUG — what happened, where (menu / hub / which part of the map / boss room), how to reproduce, which platform. If it’s a map problem, the seed helps enormously — run with --map-seed=N after -- to pin one, or just tell me what the minimap looked like.

FEEL — it works, but how does it play?

Leave feedback in the comments under the game or this post.

Thanks for playing something that’s still mostly rectangles.

— SolarNine · v0.3.7-pre-alpha