Skip to content

What is Munos?

Munos is the language you write MultiNostalgia mods in. A mod is a small program that rides along with a retro game — it can read the game's memory, draw on top of the screen, and talk to other players over the network, all while the original game keeps running underneath.

If you've ever wanted to add multiplayer ghosts to a single-player NES game, build a pause menu the cartridge never had, or paint a live map over the action, that's what Munos is for.

What it looks like

munos
var score = 0

function add_points(n: i32) {
    score = score + n
}

add_points(100)
print("score: ", score)   // score: 100

If you've written a little JavaScript or TypeScript, you can already read this: curly braces, if/while/for, // comments, and name: type annotations. A Munos program is variables, conditionals, loops, and function calls — there are no closures, no classes, no this, and no dynamic objects to learn. The language is small on purpose: it's the part of a mod you should spend the least time thinking about, and this tutorial covers all of it.

What a script can do

A Munos mod has exactly four powers:

  1. Read and write game memory. The console's RAM is an address space you reach through builtins like read_u8(0x0086). This is how you find out where the player is, how many lives are left, which level is loaded.
  2. Draw overlays. You can paint indexed-color images onto the framebuffer on top of whatever the game is rendering.
  3. Send and receive messages. send() and receive are built into the language. Your mod talks to its server with no socket code.
  4. React to events. The runtime calls your code when a frame is drawn, a message arrives, or a button is pressed.

Everything else the language omits on purpose — there's no file system, no arbitrary networking, no way to escape the sandbox. That's what makes mods safe to share: running someone's script can affect your game, and nothing else.

One file, two roles

Most mods are single-player and run entirely in the player — for those you just write code at the top level, with no roles to think about. When a mod goes multiplayer, one .munos file carries both the client and the server. The same file is compiled for each side and run in two places — in every player's browser, and on a shared server that relays messages between them.

You separate the two with client and server blocks. Anything outside those blocks is common, compiled into whichever side uses it. Each side is built separately, so it's one source file but two single-role programs.

munos
// Shared by both sides — a memory address constant.
const PLAYER_X: u32 = 0x0086

client {
    event frame(frame_num: i32) {
        var x = read_u8(PLAYER_X)   // read where the player is
        // ...draw, send updates...
    }
}

server {
    event tick(tick_num: i32) {
        // ...relay player positions to everyone...
    }
}

Because both halves live in one file, the wire format between them is just shared knowledge — you decide how to pack a message on the client and unpack it on the server, and you can declare that layout once, in the shared part of the file, so both sides use the same one.

We'll build up to a real client/server mod over the next few chapters. For now, the takeaway is: client code and server code are two sections of the same program.

What the language leaves out

A few things you might reach for aren't there. Each is a deliberate constraint with a practical reason, and you'll meet all of them again in context:

  • No floating-point numbers. Munos has only integers (i8/i16/i32 and their unsigned u* counterparts). Retro consoles are integer machines, and integer-only math keeps every player's client computing bit-identical results — which matters when players must agree on what happened.
  • No first-class functions. A function name isn't a value you can pass around; you call it, and that's all.
  • Static types, checked ahead of time. Every variable has a type the compiler knows, and nothing converts implicitly — you'll write casts like i32(x) often. That's normal Munos style.

How a script runs

You don't compile Munos by hand. When the MultiNostalgia player loads your mod, it compiles the source once, up front, and runs the result alongside the emulator. By the time the game is moving, your event frame handler is compiled code, not an interpreted script — doing real work sixty times a second is the normal case, not something to optimize around. The server half is compiled the same way on its host.

Next

You've got the shape of the language. Time to run something.

Your first script → — draw a block on the screen and see it appear over a real game.

Part of the MultiNostalgia project.