Skip to content

Releases: andrewnakas/skate3-level-loader

v0.1.6 — Windows: New San Van trees no longer draw as spikes

Choose a tag to compare

@andrewnakas andrewnakas released this 28 Sep 06:15

Windows: New San Van trees no longer draw as spikes

On the converted New San Van map, the trees and props in two mountain cells were drawn as long stray triangles across the map. This happened on both D3D12 and Vulkan.

The converted pack is not at fault. All 42,048 of its meshes check out: every index is in range and every vertex is inside its bounding box. What goes wrong is at runtime. For every mesh in those two cells, the game resolves the vertex and index buffer addresses into the wrong memory block. The native renderer read garbage from there and drew it.

Fixed: the native renderer now checks every mesh's indices against its vertex count before uploading it. A mesh that points past its own vertices is skipped instead of drawn. It keeps being retried, and the log shows a recovered line if one ever reads correctly.

Known limitation: the affected meshes, about 33 in those two cells, are hidden rather than repaired, so a few trees and props there are missing. Fixing the address resolution itself is still open.

Tested on an RTX 4050 laptop: on New San Van, at the spots that showed the glitch, the spikes are gone.

Assets

skate3-engine-0.1.6-windows-x86_64.zip: unzip it and run skate3.exe. Your ISO and Title Update 3 are asked for on first launch, and map packs go in the dlc folder beside the exe, as in v0.1.5. Linux, Steam Deck and macOS engines stay on v0.1.5. The launcher archives are added by CI after this release is created.

No game data is included, and none can be: supply your own disc image and title update.

v0.1.5 — Windows build with an add-on picker, and Steam Deck touchpad holds

Choose a tag to compare

@andrewnakas andrewnakas released this 04 Sep 21:56

Windows: pick your add-on at startup

skate3-engine-0.1.5-windows-x86_64.zip is new in this release. Unzip it and run skate3.exe. The first launch asks for your Skate 3 ISO and Title Update 3 and installs the game into game\ beside the exe.

The zip comes with an empty dlc folder beside skate3.exe, with a README in it. To add maps, drag each pack's folder into it:

dlc\MYMAP\mymap_00000000.big        (beside skate3.exe)
%APPDATA%\skate3\dlc\MYMAP\...      (also scanned)

A bare .big works, and so does one with its .header beside it. With more than one pack, the game opens Choose an add-on before it boots. Pick one with the controller, keyboard or mouse, or choose Base game only. Your last choice is remembered. In game, the pack is under pause → challenge map → Locations, as the last entry.

Fixed: the v0.1.3 Windows build froze on that picker. Windows marked it "Not Responding" and closed it, and in some cases it crashed. Two causes:

  • The picker never pumped Windows messages, so it never painted, and it never noticed that you had made a choice.
  • It read pack headers and your last choice through a file handle from the wrong C runtime.

Tested on an RTX 4050 laptop:

  • two packs at the picker, pick one, staged, in gameplay in about 14 s
  • a pack with a loose .header loaded into gameplay
  • the saved last choice was read back on the next launch

Not yet on Windows: the SDK half of v0.1.4 (the suspend/resume fix) and v0.1.5 (touchpad). That work is still on the Linux build machine. This Windows engine is the v0.1.3 engine plus the picker fix. macOS stays on the v0.1.3 engine.

The launcher archives (skate3loader-0.1.5-*) are attached as well; the version check that stopped them publishing since v0.1.2 is fixed. On Windows the recommended way to play is the in-game picker above. On a brand-new profile the launcher's automation currently stalls at the first-run difficulty screen.


Steam Deck touchpad fix, on top of everything in v0.1.4.

Holding a preload on the right touchpad now works

Pulling down on the right touchpad and holding it — an ollie preload — kept collapsing back to centre with the thumb still planted, and flip tricks were unreliable as a result.

The pad reports lifts that never happen. Tracing a play session found 29 of 74 lifts were phantoms: an UP immediately followed by a DOWN in the same place, eleven of them in the same millisecond, with the thumb motionless throughout. Each one either completed a release — snapping the stick to centre and popping a trick nobody asked for — or was taken as a fresh gesture, and a fresh gesture deliberately starts the stick at centre before travelling back out to the finger. Both send the stick through centre mid-hold, on roughly forty percent of gestures.

The hold logic itself was never at fault: the same trace shows the stick sitting at full deflection for three and a half seconds whenever the pad did not interrupt it.

A lift is now judged by whether the thumb was moving when it arrived.

  • Moving — a flick, acted on immediately, exactly as before. Tricks are as sharp as they were.
  • Stationary — a planted thumb, which is the only case the pad lies about, and the case where waiting costs nothing because nothing is moving. The stick keeps its position briefly, and a finger reappearing nearby is treated as the same contact continuing rather than a new gesture.

New setting under Select + Start → Controls → Touchpads: Reacquire window, default 120 ms, which covers every phantom lift observed. Set it to 0 for the old behaviour. It cannot affect how responsive flicks feel — a moving lift never goes through this path.

Also in this release

hid_sdl_touchpad_trace logs every right-pad event and the resulting stick value, for anyone diagnosing a pad that behaves differently. Off by default.

Assets

linux and steamdeck are the same binary; Deck defaults are applied on detection at runtime. macOS and Windows remain at v0.1.3 and do not yet carry the suspend/resume fix from v0.1.4.

No game data is included, and none can be: supply your own disc image and title update.

v0.1.4 — Steam Deck, and a suspend/resume fix for every platform

Choose a tag to compare

@andrewnakas andrewnakas released this 04 Sep 21:21

Engine build with Steam Deck support, and a suspend/resume fix that matters on every platform.

Suspend and resume no longer freeze the game

Suspending the machine mid-game and waking it left the picture frozen on the last frame while the game carried on running underneath — audio looping, input dead, nothing in the log to explain it. This is fixed.

The cause was a signed overflow in a timer deadline. The game asks for "16 ms from now" as a negative number; across a suspend its own subtraction goes negative and flips the sign, so the request arrives as an absolute date a few milliseconds after the 1601 epoch. Real hardware treats an absolute time in the past as "fire immediately", so the game never notices. Converting that date to the scheduler's clock means subtracting about 425 years, which fits comfortably in the guest clock's 100 ns units but overflows int64 once widened to nanoseconds — wrapping a deadline in the deep past into one roughly 160 years in the future. The timer was queued correctly and never fired. The guest thread waiting on it waited forever, the game's main thread waited on that thread, and every other thread waited on the main thread. The renderer was not in that chain, so it went on drawing a world that could no longer change.

Two changes fix it: an absolute due time already in the past now fires immediately, matching hardware, and the conversion that overflowed clamps before widening so this class of wrap cannot recur.

Not a Steam Deck problem — any machine that suspends can hit it, including a laptop closing its lid.

Also fixed along the way:

  • A one-second suspend was not detected at all. Resume handling only triggered above two seconds, so the shortest suspends — the common ones — bypassed every recovery path. The threshold is now 250 ms.
  • The controller is re-attached after waking. It is a USB device and re-enumerates across a suspend; SDL does not reliably re-announce it, leaving the driver polling a handle that no longer referred to anything.
  • The SDL event pump could wedge permanently. A one-shot latch was never cleared if queueing was refused, silently killing input for the rest of the session.

Steam Deck

Runs on the Deck, with defaults applied automatically on detection (both LCD and OLED).

  • Touchpads: right pad as an absolute right stick, left pad as a press-activated d-pad, tunable under Select + Start → Controls → Touchpads
  • Select + Start opens the settings menu — the old chord was unusable while skating, since RB is held constantly and Start is pause
  • The screen no longer dims mid-session; a controller looks like idleness to a desktop idle timer
  • The handheld video preset and the panel's frame cap now actually persist

Note for players on other hardware: the touchpad mappings are on by default. On a controller with a single touchpad (DualSense, DS4) that pad becomes a d-pad. It does nothing in this game otherwise, and it can be switched off in the same settings page.

Frame rate

  • Turning off "VRR / Tearing" no longer disables triple buffering. Mailbox presentation never tears, but it was being switched off along with the modes that do — leaving plain vsync, which quantizes hard. On a 90 Hz panel that is 90, or 45, and nothing between, so a game running in the seventies displayed as 45.
  • The automatic frame cap works on Linux for the first time. It derives its target from the display refresh rate, and the GTK backend never implemented the query — so it always answered "unknown", fell back to the explicit cap (zero, meaning uncapped) and read as enabled while doing nothing. If you preferred it uncapped, turn the automatic cap off.
  • The detected refresh rate is now logged once at startup, since it silently sets the ceiling for everything above it.

Packaging

The archive no longer ships a desktop shortcut with an absolute path compiled into it, which was wrong on every machine except the one that built it. Run install-desktop-entry.sh to add a menu entry pointing at wherever you unpacked the folder.

Assets

linux and steamdeck are the same binary — Deck defaults are applied on detection at runtime. macOS and Windows are unchanged from v0.1.3 and do not yet carry the suspend fix.

No game data is included, and none can be: supply your own disc image and title update, as before.

v0.1.3 — Linux and macOS engine: performance presets and drop-in custom maps

Choose a tag to compare

@andrewnakas andrewnakas released this 28 Aug 05:18

Linux and macOS engine builds, focused on performance and on making custom maps work without a launcher.

This is the engine, not the game. You supply your own Xbox 360 disc image and Title Update 3; the first launch installs them. No game data is included.

download for
skate3-engine-0.1.3-macos-arm64.zip Apple Silicon Mac (M1 or newer), macOS 13+
skate3-engine-0.1.3-linux-x86_64.tar.gz Linux x86-64 with AVX2 (2013 or newer)

Installing

macOS — unzip and double-click Skate 3.app. macOS will refuse the first launch: the app is signed, but not by a paid Apple Developer account, and anything downloaded is quarantined. Right-click the app → Open, then confirm. Once, not every time. If it still refuses:

xattr -dr com.apple.quarantine "Skate 3.app"

MoltenVK is bundled inside the app — nothing to install, no Homebrew, no Vulkan SDK.

Linux — extract and run ./play-skate3.sh. To play it on a Steam Deck: Add a Non-Steam Game, point it at play-skate3.sh. A controller works throughout, including the setup screens and the map picker.

On both, the first launch asks for your Skate 3 ISO and installs the game once.


Performance

macOS

Measured on an M1 MacBook Air (7-core GPU, 8GB) at 2560x1600 Retina:

settings result
quality — AO, bloom, god rays, soft shadows, 2x MSAA, 2x draw distance holds 60fps
ultra — the above at 2x render scale and 4x MSAA ~52fps (p50 16.7ms, but p95 32.6ms), -13% vs quality
potato — effects off 116–130fps, GPU busy only 18% of the frame — +93% to +117% vs quality

That is the smallest Apple Silicon GPU there is, holding 60 with the effects on. The frame is GPU-bound with headroom: the CPU side is about 8ms of the 16.7ms budget.

New here: Start + Select opens a performance page showing frame rate, frame time and GPU wait, and says in one line what is limiting you — the frame cap, the graphics card, or the emulation. Turning quality down only buys frames while it says the graphics card.

Linux

The video defaults were a desktop discrete GPU's, applied to every machine: the world drawn at twice the window with 4x MSAA. On integrated graphics that is unplayable. Presets now come from the hardware on the first run, and are one click in Escape → Video → Preset.

Measured on an integrated Intel UHD (Raptor Lake-P, 48 EU) at 1280x800, median over 600-frame windows of real gameplay:

preset fps
quality (what every machine used to get) 7.4
deck — auto-selected on a Steam Deck or any machine with no discrete GPU 36.0 (+386%)
performance — no shadows, bloom or ambient occlusion 42.2 (+470% vs quality, +17% vs deck)

Past the deck preset, turning effects off buys very little on a weak GPU: halving the draw distance changed nothing (36.3), quartering it changed nothing (36.0), and quarter resolution reached only 37.3. Shadows are the one exception, which is what performance takes. Supersampling is the whole story — the rest is close to free.

Linux binaries are built for x86-64-v3 (AVX2), which the recompiled PowerPC vector code uses directly: 225.2 fps against 186.7 for the same build at the old generic baseline (+20.6%), measured on a discrete RTX 4050 where the CPU is what limits. Needs a 2013-or-newer CPU (Intel Haswell, AMD Zen) — every Steam Deck and modern handheld qualifies. This flag does nothing on Apple Silicon, which has no AVX2; the Mac build gets the presets and not the CPU gain.

An explicitly set cvar always beats a preset, in both directions.

Windows

First Windows build — windows-release didn't exist as a CMake preset before this release; it does now, on clang-cl, with both D3D12 and Vulkan built (gpu_backend picks at runtime).

Measured on a laptop with both a discrete NVIDIA RTX 4050 and an Intel iGPU as separate GPUs, real Career-mode gameplay, uncapped fps:

GPU config avg fps
RTX 4050 (discrete) quality preset 159
RTX 4050 (discrete) performance preset 167 (+5%)
RTX 4050 (discrete) performance + HDR/haze off + 0.5x draw/LOD distance 255 (+53% vs performance, +60% vs quality)
Intel iGPU (integrated) performance preset 177

On this discrete GPU the game is CPU-bound, not GPU-bound — switching presets alone only buys +5%, the AVX2 build is what does the real work (same story as Linux). On integrated graphics it's the reverse: GPU-bound, so preset choice is what matters. HDR and haze are on by default regardless of preset; turning them off plus halving draw/LOD distance is worth another +53% over the plain performance preset with no further gain found pushing further.


Custom maps without a launcher

Drop map packs in dlc/, either shape:

dlc/MYMAP/mymap_00000000.big     (with its .header beside it)
dlc/SomeOfficialDLCContainer     (a LIVE/CON package)

On Linux that is dlc/ beside the binary. On macOS it is dlc/ beside Skate 3.app, or ~/.local/share/skate3/dlc — both are scanned.

No packs boots the base game. One loads it silently. More than one asks which to play at startup, with controller, keyboard and mouse — before the game boots, because the choice has to be made before the content is staged and the boot scan reads it.

Only the chosen pack is installed — the game's content scan does not survive a large collection installed at once, and every installed pack piles its locations into the same menu. Packs you are not playing are parked and come back instantly when reselected. Your files are never moved out of dlc/.

Once in the game, a custom map is reached the same way official DLC is: pause → challenge map → tab across to Locations → your pack is the last entry.


Also fixed

macOS, so the app runs on a machine that is not the one that built it:

  • It loaded whatever MoltenVK the machine happened to have. The Vulkan library was found by bare name, so a Mac with Homebrew got Homebrew's copy and a Mac without got nothing at all. The app now loads the copy inside its own bundle.
  • The game folder was a build machine's path. On another Mac that is /Users/someone-else/skate3/game, which cannot even be created — the install failed with a permission error naming a stranger's home directory.
  • Game data landed beside the app's folder instead of in it. game/, dlc/ and saves/ now all live under ~/.local/share/skate3. An existing install at the old location is still used, so nobody's game is orphaned.
  • A dlc/ folder next to Skate 3.app was never scanned — inside a bundle, "beside the executable" is three levels below where anyone sees the app.

Both platforms:

  • The game quit immediately after a content scan: it restarts itself by the retail executable name (sk83_na_f.xex), which a recomp install does not have. Now aliased to the real entry point.
  • Console noise: 898 log lines a session down to 344, and 18 errors down to 0. Almost none of it was a fault — texture re-decodes are normal (event ads, lightmap pages, CAS composites), and the XmaContext ... exceeds buffer size error is an audio packet boundary the decoder resynchronises past inaudibly. The renderer's per-mesh bookkeeping is now behind skate3_native_render_scene_verbose.
  • The DLC scan no longer warns about the README.txt the dlc/ folder ships with.

Platform builds

platform status
macOS arm64 attached — bundled MoltenVK, ad-hoc signed, measured on an M1 Air
Linux x86_64 attached — AVX2, measured
Windows x86_64 attached — AVX2, D3D12/Vulkan both built, measured on a discrete RTX 4050 and an Intel iGPU

Known issues

The first-run difficulty screen draws its options as blank rows. The list works — press A/Enter to take the highlighted one — and it is shown once, before your profile exists.

The macOS app is ad-hoc signed rather than notarised, which is why Gatekeeper needs the right-click. Notarisation needs a paid Apple Developer account.


Linux tarball rebuilt 2026-08-29. The original build was compiled against glibc 2.43 and would not start on anything older, failing with version 'GLIBC_2.38' not found and similar. It is now built against glibc 2.35 and ships its own libstdc++, so it runs on Ubuntu 22.04+, Debian 12+, SteamOS 3.5+, Fedora 36+ and current rolling distros. Same engine, same commit — only the toolchain changed. Re-download if you hit that error.

v0.1.2

Choose a tag to compare

@andrewnakas andrewnakas released this 23 Aug 06:02

Maps load in 25 s instead of 40 s. Most of the wait was the launcher, not the game.

What changed

Boot to skating, phase by phase (scripts/boottime.py, Maloof Money Cup, warm):

                    before   now
host + guest boot     3.0s   3.8s
press-start           2.4s   2.3s
boot world load       4.7s   4.6s
macro settle          2.5s   0.8s
macro                22.0s   7.6s   <-
activate              4.6s   5.3s
TOTAL                40.1s  25.3s

The menu macro was more than half the wait, and almost all of that was ten tab
presses waiting 1500 ms each. The tab strip clamps on Locations — the presses
are idempotent, so the long wait bought nothing. 300 ms now, with the same ten
presses of margin against a swallowed input.

Verified by screenshot, which is the only thing that can tell which world you
actually landed in: Maloof Money Cup 4/4 matching its confirmed reference, and a
second map landing exactly where the old macro put it.

If a boot is slow on your machine, every timing is an environment variable:

SKATE3LOADER_SETTLE_MS=2500 SKATE3LOADER_TAB_DELAY_MS=1500 ./skate3loader

Still the launcher only

Unpack the engine archive into an engine/ folder beside the launcher — on
macOS beside the .app, never inside it.

  • skate3loader-0.1.2-linux-x86_64.tar.gz — glibc 2.35+
  • skate3loader-0.1.2-windows-x86_64.zip — skate3loader-gui.exe to play
  • skate3loader-0.1.2-macos-arm64.zip — Apple Silicon, macOS 15+

macOS: xattr -dr com.apple.quarantine "Skate 3 Level Loader.app", or
System Settings → Privacy & Security → Open Anyway.

v0.1.1

Choose a tag to compare

@andrewnakas andrewnakas released this 23 Aug 03:41

The launcher opens on the game itself, and takes maps by drag and drop.

What changed

Skate 3 is the first card. A fresh install could not play anything from the
launcher until it had a map pack. Now the game as it ships is right there — no
DLC staged, no menu automation, straight into Port Carverton.

Drag and drop a .big onto the window — or a whole folder of them — and it
is installed. Import pack… and skate3loader scan still work.

Packs you do not have are no longer shown. The launcher ships knowing 43
packs by name, including which of their maps load and which hang, but not the
files. Those records are memory now, not cards: drop the matching .big in and
the pack arrives complete, with its tested status intact. v0.1.0 showed all 43
as dead entries and claimed "121 playable".

Setup screen: no dangling "or" when there is no existing install, the Title
Update field says what that file is, and a missing engine is reported before you
pick anything rather than after.

The engine is still separate

These are the launcher only. Unpack the engine archive into an engine/ folder
beside the launcher — on macOS beside the .app, never inside it, or its
signature breaks:

Skate 3 Level Loader.app     skate3loader/          skate3loader\
engine/                      engine/                engine\
  skate3                       skate3                 skate3.exe
  librexruntime.dylib          librexruntime.so       rexruntime.dll

Downloads

  • skate3loader-0.1.1-linux-x86_64.tar.gz — glibc 2.35+
  • skate3loader-0.1.1-windows-x86_64.zip — skate3loader-gui.exe to play
  • skate3loader-0.1.1-macos-arm64.zip — Apple Silicon, macOS 15+

macOS is not notarized: xattr -dr com.apple.quarantine "Skate 3 Level Loader.app",
or System Settings → Privacy & Security → Open Anyway.

v0.1.0

Choose a tag to compare

@andrewnakas andrewnakas released this 22 Aug 17:42

First packaged build of the Skate 3 Level Loader.

Pick a map, a loading screen covers the boot, and you drop into it with no
menus. Quit the game and the library comes back.

The engine is not in this release yet

These archives are the launcher only. It drives a patched build of
skate3recomp — the in-engine
loading cover, the level picker and the warp all live there — and that build is
attached separately. Without it the launcher opens, shows your library, and
stops at setup.

Unpack the engine into an engine/ folder beside the launcher — on macOS
beside the .app, never inside it, because writing into the bundle invalidates
its signature and it will not start:

Skate 3 Level Loader.app     skate3loader/          skate3loader\
engine/                      engine/                engine\
  skate3                       skate3                 skate3.exe
  librexruntime.dylib          librexruntime.so       rexruntime.dll

Downloads

  • skate3loader-0.1.0-linux-x86_64.tar.gz — glibc 2.35+ (Ubuntu 22.04, Debian 12, Fedora 37+)
  • skate3loader-0.1.0-windows-x86_64.zip — skate3loader-gui.exe to play, skate3loader.exe for the commands
  • skate3loader-0.1.0-macos-arm64.zip — Apple Silicon, macOS 15+

Checksums in SHA256SUMS.

Your own game files

First run asks for your Skate 3 ISO and Title Update 3 package and hands them to
the engine's own installer — the launcher extracts nothing itself. If a
Skate3Recomp install is already on the machine it offers that instead.

The map catalog

43 packs and 134 maps come with the launcher: names, world ids, spawn nodes, and
for the ones that have been through the sweep, whether they load or hang. The
pack files are not included and are not ours to distribute, so those records
show FILE MISSING until you point them at your own copy with
Locate pack file…. skate3loader scan ~/Downloads imports new packs.

macOS

Not notarized, so Gatekeeper blocks it until you either run

xattr -dr com.apple.quarantine "Skate 3 Level Loader.app"

or use System Settings → Privacy & Security → Open Anyway.

Known gaps

  • Guest-memory handover detection is Linux-only; on Windows and macOS the
    launcher falls back to the log going quiet, so the hand-off from the loading
    screen is a little coarser.
  • The test harness under scripts/ (sweep, verifyspot, screenshot verification)
    is Linux-only by design and is not in these builds.