Adrian Raudaschl

1.3K posts

Adrian Raudaschl banner
Adrian Raudaschl

Adrian Raudaschl

@Raudaschl

Inventor of RAG Fusion. Ex-doctor. Writing on retrieval epistemology, the relevance trap, and the design of AI tools that push back.

London, UK Katılım Mart 2009
152 Takip Edilen474 Takipçiler
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Got the Angel Island map from Sonic Adventure running on Sonic R. Another step closer to making my own level. It was an absolute pain to do the object importing and then the texture remapping and then trying to get the segmentation working correctly enough to try to reduce clipping, although there's still a bit of that. Had to rework the limits of the engine to accept higher-poly models in the memory buffer, but here we are.
English
0
0
0
43
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Last week I posted about getting Sonic R running on my Mac and tracing its physics through Ghidra. The closing thought was that I felt close to designing my own courses. This Sunday I sat down for an evening with LLM coding tools and ended up there. The plan was modest. Crack the two file formats I'd flagged as opaque last week (.ply and .map) and call it done. Started around 6pm. Both turned out to be sister formats that have nothing to do with collision, which is what I'd assumed for two weeks. They're playfield textures. .map is a 128×128 grid of one-byte tile indices, .ply is a 320×384 RGB image laid out as 120 little tiles you reference by index. The neat thing is the same byte simultaneously drives rendering and a sub-pixel collision check. A 1996 Saturn engineer was clearly counting bytes. I tested the writer by painting all the water tiles in Resort Island cyan. Whole lake turned neon. That moment of "yeah I just changed the world by editing four bytes" never gets old. That was supposed to be the end. But AI coding tools are annoyingly fast at running tools and reading Ghidra decompilation, so we kept going. The seven mystery sections at the end of the SRT file fell next. I'd cracked three last week. Cross-referencing per-track entry counts gave huge hints. Section 4 was always exactly 360 entries, section 9 always exactly 51, regardless of track. That's the smell of fixed system tables. We pulled the readers out of Ghidra one by one. Section 4 is a 360-point camera spline for the race intro/outro flyby. Section 8 is the rank-checkpoint loop. Section 9 is some 50-frame animation curve I think drives the start-grid rev animation. The fun one was section 3. 543 entries on Resort Island, smooth XYZ trajectory data, looks like a real curve. Except no game-logic function reads it. The loader copies it into memory every time you load a track and then nothing touches it ever again. It's vestigial. Somebody on the 1996 Saturn build used it, the 1998 PC porters didn't strip it, and the 2004 retail rebuild is still shipping dead bytes in every track file. Twenty-eight years of nobody noticing. While we were grepping the binary for symbols I noticed SonicR.exe has a bunch of suspicious uppercase strings. UNLOCKGAME, IGNORECD, WINDOWED, ALLOWMODESWAP. Following the xrefs found an argv walker. They're command-line flags. SonicR.exe UNLOCKGAME unlocks the full secret roster. Tails Doll, Metal Sonic, Super Sonic, Eggman, all of them. There's also a complete software renderer code path still compiled in, and a folder called BIN/OBJECTS/old/ full of pre-release character animations from September 1997 that retail just never cleaned up. By 8pm every format was decoded and I had no real excuse not to build the editor. I told the LLM "Qt6 app, 2D paint on the left, 3D OpenGL on the right, auto-find all the track files." It did. We iterated for a couple of hours. I'd race the game, find a thing that broke, describe it, get a fix, save, race again. The current shape is one window. Paint playfield textures by clicking cells. Sculpt terrain with a 3D brush, pick a shape (dome, cone, plateau, crater, ridge), drag in 3D. Both the collision mesh and the visible mesh get lifted in matched falloff so hills are walkable AND visible. Stamp decorations from a dropdown of 234 existing scenery objects, auto-named by bounding-box ratio so I know which one is the palm tree vs the sign vs the rock. Translucent green ghost preview at the cursor. Click to drop. The longest bug of the night was decoration placement. The first version stamped objects fine, except they only rendered from certain camera angles. Stared at it for a while before realising each deco's file header has TWO XYZ slots. Bytes 0-11 are a frustum-cull reference point ("is this on-screen?"), bytes 16-27 are the actual render origin ("draw it here"). I was updating only the second one. The engine was asking "is the original location visible?" while drawing the new copy at the new spot. Update both, and the temple I dropped on the beach renders from every angle. Most existing decos have those two slots set to the same value, which is why naive cloning usually works. But occasionally one differs, probably an LOD anchor vs render anchor split that the original artists never noticed, and those are the ones you can drive through until you fix it. By around midnight I had about 1500 lines of Python, three formats decoded, and a working editor. Six hours, give or take. I sculpted a hill, dropped a mini temple on it, painted a sand path leading up, raced over it. Next, I want to design an original track from scratch. A brand-new layout, my own racing line. So so close! Pick a slot to overwrite, sketch a route, sample a centre line, lay down track parts, paint the playfield, place trees, generate an AI line. Some of the writers (from-scratch SRT especially) need building rather than just round-tripping. The thing that struck me tonight is that this evening's work would have been a months-long project pre-LLMs. The LLM reads decompilation and spots patterns faster than I do, and it doesn't get bored running the same Ghidra script eleven times. I'm still the one who notices "wait, why does this only render from one angle" and points at the right thread to pull. But the iteration loop between hypothesis and "ok let me actually try it" is so much shorter that you do five times more experiments. That's the part that feels different. Childhood dream half ticked. Other half this week if I can find the time.
English
1
0
1
319
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Reverse-engineering Sonic R (1997) on a Mac - what I found and how anyone can do it I bought Sonic R on disc when I was a teenager. This weekend I got it running natively on my Mac, traced its physics through Ghidra, and patched out the tank-like turning everyone has complained about for two decades. Here's the path, in case it's useful to anyone else. Step 1: Run a Win98 game on Apple Silicon CrossOver does this in one bottle. Install via the original setup.exe and the game runs (it'll still expect a CD, which is its own problem to solve). From there you drop in the open-source Sonic R Mod Loader (sonicretro/sonicr-mod-loader). The loader is a d3d9.dll shim that lets you inject custom DLLs with Init, OnFrame and a list of byte patches. That mechanism alone is enough to do almost anything to the running game. Step 2: Crack the track format Sonic R's .srt files are undocumented. I sat with a hex editor for a couple of evenings and built a parser and writer that round-trips all five tracks byte-for-byte. The layout is sections: track parts have integer XYZ vertices at 12 bytes each plus face indices, deco parts use u8 RGB vertex colours, and track parts use i16 RGB tints with a -200 "ignore tint" sentinel. Once you can round-trip, the visual mods open up. Editing vertex colours, placing new objects, sunset reskins, OBJ↔SRT pipelines. None of it needed a decompiler, just patience and a tape measure. Step 3: Reverse engineering with Ghidra headless The interesting stuff lives in SonicR.exe, which is a 512KB PE32 with image base 0x400000. Ghidra has a headless mode driven from PyGhidra, perfect for a CLI workflow. I wrote about six small scripts: find functions that reference an address, find users of a string, decompile by entry point, and so on. Then it's iteration. Dump candidate function, read decompilation, find the next breadcrumb. Some highlights from the map I built up: * Players[] array at 0x7B7388, sizeof 0x71C per player, hard-coded to 5 slots * The screen state machine is a giant switch in MainGameLoop at 0x43AA60 * Track data pointer at 0x752478 is null until level load, which explains why naive menu-skip patches crash * Sin/cos lookup tables at 0x7AA038 and PTR_0047b964 * Fog floats MIN_FOG_Z (0x46152C) and MAX_FOG_Z (0x461530), defaulting to 0.7 and 0.9. Bumping them to 20 and 50 literally extends the draw distance Step 4: The tank-controls fix Every Sonic R review for 25 years says the same thing about the turning feeling like a tank and the cars skidding like an ice rink. I traced the per-frame physics tick to FUN_0042c430 and found it pulls 10 scalars per character from a table at 0x45e300. The fields are unmistakable once you see them: * +0x00 top speed (Sonic 208896, Amy 147456, Super Sonic 245760) * +0x04 forward acceleration impulse * +0x08 turn rate (yaw delta per frame) * +0x0C lateral friction (the weather code multiplies this down in rain, which confirmed it without me having to guess) * +0x10 forward friction * +0x14..+0x24 jump and per-character misc I changed one number. Field +0x08, the turn rate, multiplied by 1.5x for every character. Per-character ratios preserved, so Tails still turns sharper than Sonic and Tails Doll remains the worst character in the game by design. That's the entire patch. I tried more aggressive combinations first. Two-times turn rate plus doubled friction made it feel floaty. Adding forward friction to fix the floatiness over-rotated. At one point I had a field semantic wrong and crippled the throttle entirely. What worked was the boring change of picking one knob and turning it, which is probably a wider lesson about modding old games than I'd like to admit. Step 5: Texture export and AI upscaling The other half of the weekend was textures. Sonic R stores them as raw RGB24 with no header, and the engine just looks up dimensions by file size. I wrote a generic exporter that auto-detects format from byte count and bulk-exported all 224 PNGs in one pass. Then I started feeding them through Nano Banana Pro to upscale and restyle them. The originals are 256x256, and you can completely change the mood of a track by re-importing higher-resolution versions with different style transfers applied. The engine doesn't notice because the loader still expects raw bytes at fixed dimensions, and the resampled textures slot back in. Step 6: Make it reproducible The whole pipeline is a few hundred lines of Python plus one C++ DLL: * texture_io.py for generic raw export and import with format auto-detection * srt_roundtrip.py for the track format parser and writer * parallax_io.py for sky textures, with stretch/cover/fit/tile import modes * mod-src/AutoBoot.cpp for the loader DLL with all the binary patches * ghidra-scripts/*.py for the PyGhidra recipes I keep reaching for What I haven't cracked The .ply collision and heightfield format is still opaque, which blocks proper drivable custom terrain. Nobody on PC has hooked DirectInput to give Sonic R proper analog stick support either. Both are interesting projects for someone with more time. Closing thought The barrier to this kind of work is lower than it seems especially using LLMs. Pick a 1990s game with an existing fan mod loader and learn one tool (Ghidra headless). Start reading decompilation until the function names mean something. I am greatly enjoying this! Feels like im not too far from creating my own courses - a childhood dream come true.
Adrian Raudaschl tweet mediaAdrian Raudaschl tweet mediaAdrian Raudaschl tweet media
English
0
0
0
201
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
On sycophancy, retrieval, and Karpathy's wiki Two things have been on my mind this month. The first is Karpathy's recent post arguing that the most useful way to think about an LLM is as a wiki you curate, query, and think with. I think the architectural claim is broadly right. gist.github.com/karpathy/442a6… The second is a paper out of MIT in February showing that personalising an LLM with a memory profile makes it up to 45% more agreeable on Gemini 2.5 Pro. The current frame for this is sycophancy: a model behaviour, to be trained out of the weights. Anthropic, OpenAI, and Google are all working on it from that angle. arxiv.org/pdf/2509.12517 I think the sycophancy conversation is happening one layer too low. The retrieval inheritance Most of the people now using LLMs every day learned how through a decade of retrieval systems that rewarded confirmation. Search ranks by relevance to what you typed. Recommenders surface things next to what you've already engaged with. Personalisation amplifies the pattern. The implicit promise of every consumer-grade discovery tool over the last decade has been: I will give you more of what you already wanted. That isn't a model property. It's a user expectation, trained at industrial scale. Ten years ago I worked on an academic search product optimised for relevance. Users said the results were excellent, and quietly stopped coming back. So we re-ranked papers by accelerating readership instead of citation count. Our relevance score dropped. Almost everything else we cared about, return visits, breadth of reading, time spent on unfamiliar work, moved in the right direction. The metric we'd been chasing was actively obscuring the thing we wanted. I've come to think this pattern, more than any architectural choice, is what's now being inherited by RAG, by agentic retrieval, and by most of the "AI assistant for X" products being built on top of LLMs. Why an agentic wiki on its own doesn't get us out Karpathy's frame depends on a specific kind of user behaviour. "You curate sources, ask questions, and think" is the load-bearing line. Inside the post it reads as design intent. In the field, after a decade of confirmation-optimised tools, I think it reads as an assumption that doesn't hold for most users. If the person querying the model has been taught to treat agreement as quality, an agentic wiki becomes a more elaborate confirmation engine. The architecture gets cleaner and the outputs more polished, while the epistemic problem stays exactly where it was. Training sycophancy out of the weights helps at the margin. It doesn't address the upstream loop, which is that the people querying the model are doing so with a decade of conditioning that punishes any system pushing back. Building 20 as a counter-example qz.com/emails/quartz-… MIT's Building 20 went up as temporary war research housing in 1943 and stayed up for fifty-five years. It was famously ugly, badly heated, and forced unrelated departments to share corridors. Radar work next to linguistics. Acoustics next to plasma physics. It produced more Nobel-adjacent work per square foot than almost any structure of its era. The reason I keep coming back to it is that almost none of the design choices that made it productive would survive a modern user satisfaction review. Cold rooms, awkward layouts, encounters with people working on things you wouldn't have walked over to ask about. By every measure of polished UX, Building 20 was a bad product. The interesting question is whether retrieval can host that kind of design at all under current market incentives. The piece breakingproduct.substack.com/p/the-relevanc… The full argument is here, including a sketch of what a retrieval system built to introduce productive friction might actually look like. The genuine question I'm sitting with, and would value pushback on: is friction-as-feature viable when every release gets graded on a satisfaction score? The market answer right now is clearly no.
English
0
0
0
55
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Model context protocol (MCP) is going to become as essential as API's for services and websites in an AI Agent first internet.
English
0
0
1
105
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Recursive intelligence has arrived. And nobody noticed.
English
0
1
1
106
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Three years later, on Midjourney...
Adrian Raudaschl tweet media
English
0
0
0
65
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
A photograph of a presenter from Sony on stage unveiling the iPhone, 2007 [Midjourney]
Adrian Raudaschl tweet media
English
1
0
0
229
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
We don't really want AI to be intelligent. We want it to be stupid in exactly the right way.
English
0
0
0
86
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
I reckon the true AI revolution will not come when machines can think like humans, but we humans realise we've always thought like machines.
English
1
0
1
111
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
@CyberKevin_FR Translation: METAL SONIC Size: 765.4 mm Weight: 125.2 kg MAIN CPU: LISP A. I. EGGMAN CUSTOM CHIP The CPU, connected via neurotransmitters to the central memory, allows for a response speed of physico-motor skills never matched by any other Eggman-type robot.
English
0
0
2
84
Under the Surface of Classic Sonic
Under the Surface of Classic Sonic@SCDDeconstruct·
Issue 20 of the French gaming magazine Mega Force features a build of Sonic CD between the v0.51 and 712 prototypes that interestingly has a signpost sprite that isn't seen in any of the dumped prototypes.
Under the Surface of Classic Sonic tweet media
English
14
233
1.2K
82.7K
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
Gpt4o is spectacular! @sama @OpenAI Played with it a bit on a new project that’s particularly complex and I’m just blown away. Been trying tons of options, different models, different prompting even Groq LPUs on llama3. Months of my work just got validated. Thank you.
English
0
0
0
217
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
I did it! I made it to a thousand successful days of #readwise daily reflections.
Adrian Raudaschl tweet media
English
0
0
0
213
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
The true challenge of 2024 won’t be getting to smarter LLMs, but more scalable ones.
English
0
0
1
148
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
It’s the holidays and you know what that means. It’s time to play with new AI great stuff! Repurposed that “make a fake influencer” tech to turn myself into a #Schiaparelli model - finally it happened. Mixture of epic real SD and pose estimation models. Pretty cool.
Adrian Raudaschl tweet media
English
0
0
2
210
Adrian Raudaschl
Adrian Raudaschl@Raudaschl·
How long until we see the first llm baked into the web browser?
English
0
0
0
157