Log In  
[ :: Read More :: ]

ChatGPT 4o seems pretty good at writing Pico-8 code. (At least for simple games).

I asked it:
"Can we try something different? Like a simple Space Invaders or Galaxians style game?
I have 4 sprites in slots 1,2,3,4 with a player ship, alien invader, player bullet and enemy bullet respectively. Could you make a simple game where the aliens move left and right in formation, and the player moves left to right along the bottom of the screen?"

I got this.

I pasted the gif into the chat window, and it said:

"Awesome! It looks like the basic mechanics are working. Let's add a few more features to make the game more interesting:

Enemy Bullets: Add bullets fired by the aliens.
Player Lives: Track the player's lives and end the game when they run out.
Score: Add a scoring system for each alien destroyed."

Then gave me an updated version that looks like this:

Then I got worried that AI is doing all the work and I'm going to turn into the spaceship inhabitants in WAL-E. So I asked it to quiz me on the code and check my answers.

It came up with questions like:

"Bullet Mechanics:

Q3: How does the player fire bullets? What happens when a bullet is fired?
Q4: How are player bullets updated and removed when they move off-screen?
Alien Movement:

Q5: How do the aliens move left and right in formation? What happens when they reach the edge of the screen?
Q6: How do the aliens move downwards after reaching the screen edge?"

P#148655 2024-05-19 23:16

[ :: Read More :: ]

Here's a little profiler you can drop into an existing program - if you have 313 tokens to spare.
It instruments the global functions to count the number of calls and measure the CPU time spent inside them. Then it dumps it to a CSV file you can open in a spreadsheet viewer, and hopefully get some insight into where your program is spending the most time.

Instructions are in the comments at the top.


  • Count fn calls in a single 32bit integer (thanks @freds72).
  • Use "..." arguments syntax to support more than 9 arguments (thanks @Siapran)
  • Save uninstrumented fns to avoid calling the instrumented ones when dumping stats.
-- profiler

-- usage:
-- run your program
-- press esc to break
-- > _prof.begin()
-- > resume
-- run your program some more (to gather data)
-- press esc to break
-- > _prof.dump()
-- this will dump a profile.csv file to the cart's folder

-- notes:
-- profiling for more than 2-3 minutes could cause cpu measurements 
-- to overflow, and give incorrect results.
-- measures the amount of cpu spent in each function, where 1 is one whole frame
-- so divide by frame rate to get seconds (30, or 60 if using _update60).
-- profiling will slow down your program somewhat.

    -- list of global functions to *not* instrument
    -- original uninstrumented functions

-- start profiling.
-- if called multiple times, will reset stats
    -- clear stats

    -- instrument functions
    if not _prof.instr then
        for n,v in _prof.pairs(_ENV) do
            if _prof.type(v)=="function" and not _prof.donttouch[n] then
                -- wrap function
                    -- run and get cpu timing
                    local cpuin=_prof.stat(1)
                    return (function(...)
                        -- update stats
                        local cpuout=_prof.stat(1)
                        local st=_prof.stats[n] or {ct=0,cpu=0}
                        return ...  

-- dump profile stats to file
-- order is field to order by (name,ct,cpu,avg)
-- defaults to "cpu"
-- dst is printh destination
-- defaults to "profile.csv"
    order = order or "cpu"
    dst = dst or "profile.csv"
    local rpt={}
    for n,v in _prof.pairs(_prof.stats) do
        local cpu,ct,sh=v.cpu,v.ct,16

        -- average is cpu/(ct<<16), except that ct<<16 could
        -- overflow, in which case shift ct left as many bits 
        -- as possible and shift cpu right the remaining bits.
        while sh>0 and ct<0x4000 do       -- can't exceed 0x7fff as it would be treated as negative
            ct<<=1 sh-=1

        -- create stat      
        local st={name=n,ct=v.ct,cpu=v.cpu,avg=cpu/ct}

        -- insert into rpt in order
        local i=#rpt+1
        while i>1 and (rpt[i-1][order]>st[order])==(order=="name") do

    -- print rpt
    for st in _prof.all(rpt) do

Here's an example of my 2D transforms demo.
For example you can see it spends a large amount of time in the "map" function (which would normally be suspicious except that the "2D transforms" replaces the standard "map" function with a custom version).

P#142589 2024-03-08 11:03 ( Edited 2024-03-09 01:51)

[ :: Read More :: ]

Cart #mot_rendertest-0 | 2024-02-07 | Code ▽ | Embed ▽ | No License

A little experiment with rendering directly from Pico-8 RAM using "peek".
Trying to use as few tokens as possible.

P#141243 2024-02-07 04:13

[ :: Read More :: ]

Cart #mot_animsys2-0 | 2024-01-16 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This has been sitting on my drive for a year or so. I was meaning to write up some documentation for it, but I'm throwing it up as is for now. (Until I can remember how to use it.)

Basically it's a sequel to Mot's Animation System built on top of the 2D transforms library. The main improvement being that it supports rotation.

The basic idea is you create "sprite" animations based on frames on your tilemap. You can then combine them into "timeline" animations where position, rotation etc can be set at different points by creating keyframes.
There's also a "storyboard" animation type that simply plays other animations in order.

You can import gfx and tilemaps from other carts, save/load your projects. You can also export your animations to embed in your own projects if you wish. It's about 1700 tokens, although 1000 of that is the 2D transforms system. (I can post an example of this if anyone is interested.)

I'd write up some more, but I need to remember how it works myself :).

Maybe someone wants to have a play with it anyway.


Here's an example cart playing an exported image.
It uses tabs 2,3,4 of the editor, except I recovered about 200 tokens by stripping out some unused bits.

Cart #mot_animsys2_test-0 | 2024-01-16 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#140172 2024-01-16 00:34 ( Edited 2024-01-16 09:26)

[ :: Read More :: ]

Cart #mot_taxi-7 | 2024-01-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

UPDATE: Fixed suspension to lean towards the outside of turns, not the inside.

Welcome to the Whiplash Taxi Company, where our motto is "The slower you're there, the lower the fare!"

As a valued employee and taxi driver, your job is to pick up passengers and deliver them to their destination as fast as possible, by any means necessary.

Passengers are easy to spot, just look for the big red arrows over their heads.

Simply stop next to them so they can jump in!
Then follow the red destination indicator to the destination and stop when it says "stop!".

Repeat this as many times as possible in 5 minutes, and see how much $$$ you can bring in.

But beware, sometimes the direct route isn't the quickest.
To make it easier we have provide this giant map of Motsville. You may want to spend some time in "Free Explore" to get the layout. Or try some of the fully legitimate and not just driving-around-random-streets-way-too-fast street circuits, and maybe set a few lap records.

Remember, at Whiplash Taxis when we say "Break neck speeds", we mean it!
(Hopefully not literally. Hopefully.)

P#132559 2023-07-30 10:31 ( Edited 2024-01-26 21:58)

[ :: Read More :: ]

Cart #mot_taxi-0 | 2023-07-08 | Code ▽ | Embed ▽ | No License

This is basically a Wolfenstein-3D style ray-caster with floor tiles.
There's no gameplay or even collision detection so far.

The top right of the Pico-8 map region is used to layout the game, using the sprites in tab 3.

The sprites correspond to 8x8 regions in the top left of the map area, which represent the "texture" to draw.

P#131761 2023-07-08 23:12

[ :: Read More :: ]

Cart #mot_raymarch2-3 | 2023-02-09 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

I updated my ray marcher to use RGB colours internally and random dither back to 16 colours.
This should allow me to add things like partially transparent surfaces, or atmospheric fog at some point.

P#125495 2023-02-08 00:34 ( Edited 2023-02-09 03:19)

[ :: Read More :: ]

Cart #mot_chopper-2 | 2022-12-27 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

WARNING: This game attempts to emulate old 8-bit flight simulators from the 80s and 90s. The flight model leans towards realism rather than easy-to-pickup arcade gameplay (even if it's somewhat primitive compared to serious modern-day flight simulators). As such it's not an easy to pickup game - controlling the helicopter is challenging and takes practice. In combat, even more so.

Welcome to Combat Chopper, an 80s helicopter combat flight simulator for Pico-8!
Pilot your P8 64k Apachi armored attack helicopter on a series of missions destroying key targets in enemy territory.

Getting started

Training mode

Use the "Training" mode to practice controlling the helicopter before trying to take on any missions. You will need to be comfortable with keeping low, stopping and hovering, and landing, before attempting to engage in combat.
Training mode is exactly like career mode, except there are no objectives, and you cannot be shot down.

Flight controls

The helicopter and weapon systems can be fully controlled using a single controller.

When no button is held:

  • Up/down -> Pitch
  • Left/right -> Roll

When the circle button (Z) is held:

  • Up/down -> Collective
  • Left/right -> Tail rotor

To take off, hold circle (Z) and press the up arrow until the helicopter starts climbing.
A little bit of collective will make the helicopter hover just above the ground (due to the "ground cushion effect"). Adding more collective will cause the helicopter to continue climbing.

Once airborne, press the arrow keys (without holding circle) to tilt the helicopter, which will cause it to accelerate in that direction.

The cockpit gauges help you control your flight:

Player 2 controls (optional)

Although the game can be played with just one controller you can use a second controller for extra precision.
The player 2 arrow keys control the collective (up/down) and tail rotor (left/right).


Being able to stop and hover is a useful skill.
Essentially this involves raising the nose and tilting backwards until your speed reduces to zero.
However, keep in mind that the helicopter has momentum and it takes some distance to brake from 100mph down to zero.
Also tilting backwards at speed will cause the helicopter to climb rapidly making you an easy target for SAM launchers. To avoid this, drop the collective down first before lifting the nose. Try to balance the collective and pitch angle to keep the vertical speed as close to zero as possible. When your speed is close to zero, quickly add collective to avoid dropping quickly.


Landing is tricky to master, but is an essential skill.

Use the map view to locate your base.

It will be at the coordinates you took off from! Alternatively look for the orange dot on the map.

Come to a hover next to your base, then turn to face it using the tail rotor controls.

Approach the the helipad slowly (~10mph) using the collective and vertical speed indicator to control the rate of descent.

As you reach the helipad, tilt the nose up slightly to come to a hover and lower the collective until you touch down onto the helipad.


As well as piloting your helicopter, you will also need to destroy enemy units.
This involves locating the enemy, targeting them, and selecting and firing the appropriate weapon.

Weapons and targeting

Hold cross (X) to access the weapon systems.
While held:

  • Up/down -> Cycles through available targets.
  • Left/right -> Select the weapon/countermeasure to fire.

Tap X to fire the selected weapon at the targeted unit.

From left-to-right the weapons are:
- No weapon. (I.e. safety on)
- Cannon. Effective against all unit types, but has limited range.
- Laser guided missile. Seeks the targeted unit. Ineffective against camps and outposts.
- Rockets. Fly straight forward. Effective against camps and outposts , but not other targets.
- Countermeasures. Used to counter surface to air missiles (SAMs).

In order to be targeted, an enemy unit must be visible (i.e. in front of you) and in range.
Range depends on your altitude - the higher up you are the greater your targeting range. Beware that this works both ways - enemies can also target you from further away when you are higher up.

When a unit is targeted a square reticle is displayed around it, and the unit is displayed in the targeting camera view. Enemy units have a red reticle and an "E" displayed in the bottom left corner of the target camera view. Friendly units have a blue/gray reticle and an "F" displayed.

Enemy fire

The main threat will be surface-to-air missiles (SAMs). Most units will fire these at you when they spot you.
Beware of SAM launchers as they fire more quickly and their missiles do greater damage.

The IR and SAM dashboard lights tell you when an enemy is aiming and firing at you.

If the IR light is lit an enemy is targeting you and getting ready to fire.
The SAM light means a missile has been fired and is actively seeking you, and you should take action to avoid being hit.
This might mean:

  • Dropping a countermeasure. This is the most effective way to avoid getting hit, but you only have a limited supply. Each countermeasure lasts for 10 seconds.
  • Dropping behind a hill is occasionally effective, if you have enough time.
  • Attempting to evade by turning tightly or rapidly dropping altitude. This is risky but can work.

The other threat is anti-aircraft (AA) guns.
These fire shells at you which, unlike SAMs, do not seek and have a shorter range. However there is no warning indicator for AA guns and they are particularly dangerous if they catch you at close range moving slowly, or if you try to take them head on.


Damage is displayed in the mission objective display as a red bar. If the bar is fully red then you have been shot down, and your helicopter will crash to the ground.
Damage also affects your engine and the amount of lift your rotors can generate.

You can repair your helicopter by landing at a friendly helipad, and dropping the collective down to zero. This will also restock your weapons.


In career mode you will be given missions.
Each involves destroying one or more enemy units at a specific location, then returning to and landing safely at your base.

The mission objective is displayed at the top of the dashboard.
Use the map to find your way to the objective coordinates. The objective is displayed as a red dot.

Once enough units have been destroyed at, or close to, the mission coordinates, the mission objective will change to "Return to Base", and display the base coordinates.


Some tips to help keep you in the air.

Keep low

Flying low is challenging. However keeping under 100 feet prevents you from being lit up like a Christmas tree to every SAM capable enemy unit.

Friendly space is to the west

If you need to retreat, head west.

Use the mountains

This is particularly important for missions deeper into enemy territory.
The basic approach is:

  1. Fly to a mountain, keeping low, and come to a hover beside it. Ideally keeping it between you and enemy units.
  2. "Pop up" to 200-300 feet and look around for enemy units. Then drop down again before they can fire at you.
  3. Choose the next mountain.
  4. Decide which enemy units to destroy or avoid in order to reach the next mountain.
  5. Destroy the chosen units.

Repeat the process until you are within range of your objective.

Watch out for AA guns

Getting close to an anti-aircraft gun can quickly spoil your day.
Destroy them from range or avoid.

P#123143 2022-12-29 00:01

[ :: Read More :: ]

Cart #mot_chopper-1 | 2022-12-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Update: Updated cart to latest version. This is probably close to what will be released.

A work-in-progress helicopter combat flight simulation. Loosely based on my memories of playing Gunship on C64 a few decades ago.

The heli can be controlled with player 1 input:

  • By default the arrow keys control the cyclic stick.
  • Hold down circle (z) to switch to collective (up/down) and tail rotor (left/right).
  • Hold down cross (x) for weapons mode, where up/down cycles between targets, and left/right selects the weapon.
  • Tap cross (x) quickly to fire.

So to take off, hold down circle (z) and up.

Alternatively you can use player 2 input (E,S,D,F in keyboard) for collective and tail rotor.

From left to right the weapons are:

  • None (i.e. safety on)
  • Cannon - auto aims. Effective against all unit types. Limited range.
  • Lazer guided missile - Seeks current target. Effective against tanks.
  • Unguided rockets - Fly straight ahead. Effective against infantry camps.
  • Countermeasures - Drop one of these to divert incoming missiles.
P#120362 2022-11-09 05:22 ( Edited 2022-12-24 02:11)

[ :: Read More :: ]

Cart #mot_walksim-1 | 2022-09-25 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

A little texture-mapped graphics engine with BSP-tree models and fog shading.
Doesn't even try to maintain 30 FPS consistently :-)

  • Player one controls aim.
  • Player two controls strafe.
  • X/O moves up and down.

I still don't have a plan for this cart.

P#117935 2022-09-25 10:06 ( Edited 2022-09-25 10:31)

[ :: Read More :: ]

Cart #mot_asteriods-0 | 2022-08-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This game is a little demo of a 2D transformation library I put together.
I chose a simple Asteroids clone because it is a good example of rotation and scaling.
The first tab contains the game. The second tab contains the library.

The library adds commands that affect 2D drawing commands, allowing you to rotate, scale and translate output, similar to the transformation commands in HTML Canvas or the old OpenGL 1.1 matrix stack.

It affects the following Pico-8 drawing commands:

  • pset
  • line
  • rect/rectfill
  • circ/circfill
  • map

Note: spr and sspr are not affected.

The transformation commands are:


Resets all transformations (to the "identity").
Essentially cancelling all scaling, rotation and translation.
Typically this should be used at the top of _draw()


Translate (move) by (x,y)


Rotate output by a turns (anticlockwise)



Scale output by factor. You can also scale x and y axis independently.


Save the current transformation (to the transformation stack).


Restore the last saved transformation.

P#116309 2022-08-26 04:30 ( Edited 2022-08-26 04:39)

[ :: Read More :: ]

Add an instant replay to your game!

(Shown here: OMEGA ZONE by @kometbomb)

New from the mind that brought you Instant 3D! and still hasn't apologized, Instant Replays!

Paste this snippet into the end of your game and be amazed at your new replay capabilities!!! Or it could fail completely! That's the mystery of it!!!

 local prev={

 local bstate,pstate,addr,isplay={},{},0x8000,false

 local function updatebtns()
  for i=0,5 do
  if isplay then
   local mask=peek(addr) addr+=1
   for i=0,5 do
   local mask=0
   for i=0,5 do
    if(bstate[i]) mask|=1<<i
   if addr<0x8000+0x42ff then
       poke(addr,mask) addr+=1

 local function doreplay()

 cartdata=function() end
 if not isplay then
  local seed=rnd(0xffff.ffff)
  local seed=peek4(addr)addr+=4
  menuitem(5,"end replay",function()dset(63,0)run()end)

 if _update then

 if _update60 then

  return bstate[i]

  return bstate[i] and not pstate[i]

  if isplay then 

Okay, I've exceeded by exclamation point quota.

This is a little experiment in capturing the player's input and replaying it exactly as before in order to make the game play out exactly the same way - assuming everything goes to plan.

To use, paste the snippet into the end of you cart, after the existing code. Then play the game for a minute and select "Replay" from the pause menu. The replay will continue looping until you select "End replay" from the pause menu.

Note - There are a bunch of requirements/caveats for this to actually work:

  • Your game must be controlled by the player 1 gamepad only. Player 2 controls, mouse, keyboard etc is not captured.
  • Pico-8 must be able to read/write to an external cart (named "mot_replay.p8"). I don't think this will work in binary/web exports.
  • Your game must not use:
    • Pico-8 memory above 0x8000
    • Menu item slot 5
    • Cart data slot 63
  • The snippet will hijack your cart data and use cartdata("replay") instead
  • Replays cut off after 10 minutes or so due to limited storage space.

And there's probably other ways it can fail that I haven't thought of :-). Try it and see..

A few games it seems to work with:

Harold's Bad Day by @biovoid

Phoenix by @pahammond
(Had to remove the cartdata() call from the snippet)

Ninja Cat by @cubee
(Had to remove the cartdata() call from the snippet)

Super Disc Box by @Farbs

P#106415 2022-02-06 08:55 ( Edited 2022-02-07 07:38)

[ :: Read More :: ]

Cart #mot_grandprix_editor-2 | 2021-10-09 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This is the track editor for Mot's Grand Prix

I don't recommend running this in browser as you cannot save/load tracks - anything you build will be lost.
Rather download the file and run it in Pico-8 itself.

You will also need to download the main game and run it in Pico-8 in order to race on any tracks you create.

This editor requires a keyboard and mouse.

Existing tracks

You can download the tracks from the existing game from this Google Drive folder. Place them in your carts folder (next to the editor) then select "Load" from the editor hamburger menu (top right) to load them.

Basic usage

IMPORTANT: There are known bugs that will crash the editor, so save often!

  • Use the arrow keys to scroll along the track.
  • Use the hamburger menu (top right) to load save and export tracks.
  • The "New" menu creates new stages, curves and items (described in detail further down).
  • Click "Drive" to drive on the track (select "Editor" from the pause menu to return to the editor).
  • Select things by clicking on them. You can then edit their properties, or delete them by clicking "-".
  • After making a change you usually have to click "Update" (bottom right) to update the visual model (I didn't have enough tokens to make this automatic).

Track format

The basic components of a race track are:

  • Stages
  • Curves
  • Items


Are used to partition the race track. Every track must have at least one stage.
The advantage of having multiple stages is that their curves and items are stored independently of the other stages, so if you modify the curves in a stage you only need to fixup the positions of the background items within that stage. Also they can help you keep track of what part of the track you are working on.

Click "New->Stage" to add a new stage. The new stage will be inserted immediately after the current stage.

The current stage is displayed top-left underneath the menu bar.

You can click on the name to edit it. Or click "-" to delete it.
Deleting a stage deletes all its curves and background items, so be careful.


Curves define the shape of the race track, i.e. the corners, straights, hills, valleys etc.
Note: Despite the name a "curve" doesn't have to actually curve. It can be completely straight.

Click on the race track itself to select a curve.

Click "New->Curve" to add a new curve.
If a curve is already selected, the new curve will be inserted immediately before it in the current stage.
If no curve is selected, the new curve will be added to the end of the current stage.
To delete the curve, select it and click the "-" button next to the curve (NOT the one next to the stage!)

Edit the curves properties to modify it.
Most properties are edited using sliders. Drag with the left mouse for small increments and right mouse for large.
Remember to click "Update" to see the result of a change.

  • Length = Length of the curve in units (units are about 4-10 meters long - scale isn't very accurate in this game)
  • Turn = How sharply the road turns. 0 is straight, negative values turn left, positive turn right.
    For reference the hairpin turn in "Suzuka" is -0.32, which is close to the limit of how sharply cars can corner in this game.
  • Pitch = Vertical gradient. 0 is flat, -1 is up 45 degrees, 1 is down 45 degrees.
    Pitch is an optional property. Tick the tick-box to enable it. If omitted the pitch from the previous curve will be used.
    Pitch is linearly interpolated. The value you set is actually the pitch at the end of the current curve. It will smoothly transition from the previous pitch to that value across the curve.
  • Left/Right = Define the horizontal range, i.e. how far left/right cars can go without crashing into a barrier.
    The left and right barriers are visually represented by the "L Barrier" and "R Barrier" settings below. It's a good idea to set these - otherwise the player will simply crash into an invisible barrier.
    The road is 8 units wide, so the "Left" usually is -4 or less, and right 4 or greater, although they can be set to -3/3 to clip into the gravelly region of the road. The AI cars expect the full width of the road to be available though, so be careful when doing this.
    Left/right are also optional, linearly interpolated properties.
  • L Barrier/R Barrier = Define the visual left and right barriers. Each one is a list of item types that will be repeated. Tick the tick box to specify the barrier type, then click "[New]" to add an item type.
    Select the item type from the list (use the mouse wheel to scroll). Make sure to only select item types starting with "Barrier_" (I didn't have enough tokens to automatically filter the list).
    Generally it makes sense to use just one barrier types, or combine "Barrier_Fence" with one of the other types.
    L Barrier/R Barrier are optional.
  • Trees = Generate random trees on the left/right side of the map.
    This is a list of horizontal positions to place the trees at trees' horizontal positions vary randomly by a few units as well.
    Trees are optional.


Items are background items, like stadiums, buildings, signs. They don't affect gameplay, but make the track look more alive.
Click on a background item to select it.
You can also use the "<" and ">" buttons to cycle through the items in a stage (useful if you accidentally place one in a position where it is never visible and can't be selected normally).
Click "New->Item" to create a new item, then select the item type from the list (mouse wheel to scroll).
The item will be created in the current stage, a few units in front of the camera.
To delete the item, click the "-" button next to it.

Background items have 3 properties representing their position relative to the race track.

  • X = Horizontal position relative to the race track (negative = left, positive = right)
  • Y = Vertical position relative to the ground (negative = up, positive = down)
  • Z = Distance along track from start of stage.

Other properties

You can also edit the sky and ground colours by selecting "Properties" in the hamburger menu.

Generated content

The following items are generated automatically and cannot be edited:

  • Race track shoulder things (I tried to Google for the proper name, but only found things that stop horses from biting your shoulders...)
  • Distance to turn signs
  • Racing line markers


To race on your track in the actual game, you need to export it:

  1. Click "Export" in the hamburger menu. This will copy a string to the clipboard.
  2. Open up "Mot's Grand Prix" in Pico-8.
  3. Open tab 8.
  4. Choose a track to replace (there isn't enough compressed space left to add any more).
  5. Replace the string for one of the existing tracks. Be sure to switch to "Puny font" mode (press Ctrl+P) before pasting from the clipboard.
  6. Optionally edit the "finline" variable to set the finish line distance.
  7. If you want to change the track name on the start screen, edit the "tracknames" variable in tab 1.

Your track should now be in the game.

P#97963 2021-09-30 23:37 ( Edited 2021-10-09 11:58)

[ :: Read More :: ]

Cart #mot_grandprix2-0 | 2022-04-22 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Title screen artwork by Marco Vale

Update: The track editor is now available here.

Update 2: Added Autodromo Nazionale di Monza circuit

Update 3: Added last two tracks (Hockenheim and Spa Francorchamps) plus championship mode. The BBS version now plays identically to the itch.io multi-cart version.

Update 4: Minor update to add some side-textures to buildings. (No more boring gray boxes.)

Step back in time to an era when folk were real folk and racecar steering wheels were real steering wheels.
Mot's Grand Prix is a pseudo 3D Formula 1 racer inspired by Grand Prix Circuit, Continental Circus and a bunch of other 80s/90s racers I've forgotten :).

Strap into your single seater and blast around 6 classic race courses:

  • Brands Hatch
  • Hockenheim (old layout)
  • Autodromo Nazionale Monza
  • Silverstone
  • Spa Francorchamps
  • Suzuka

Or enter the championship and try to be top of the points table at the end of the season.

The game has 4 difficulty levels plus a practice mode to learn the courses without the pressure of racing.


  • Left/Right = Steer
  • Z/Up = Accelerate
  • X/Down = Brake

Mouse control

You can also enable mouse control in the pause menu. It has 3 settings:

  • Off = No mouse control. Keys/gamepad only.
  • Steering = Mouse controls steering (left/right axis). Keys/gamepad controls acceleration/braking.
  • Full = Mouse controls steering (left/right axis) and acceleration/braking (up/down axis).

"Steering" mode can be quite playable if you use a large window size or full-screen mode. Use the keyboard keys to accelerate/brake as usual.
"Full" mode is not really playable unless you're some kind of robot, but can be useful for other input devices if they can be configured to output mouse movements (e.g. a Steam controller).


This is a game where you have to slow down for the corners!
Use the colour of the racing line to judge your speed.

  • Green -> You are fine
  • Yellow -> You are close to the limit, but should be able to make the turn
  • Red -> You are likely going too fast for the corner

If you're really having trouble, you can switch on "Auto Brake" in the pause menu. Auto-brake automatically slows you down for corners, but not to avoid crashing into other cars.

Don't be timid about muscling through traffic
There is no damage model. Your car is indestructible. Be fearless! :-)

Hope you enjoy this game.

P#97606 2021-09-21 12:36 ( Edited 2022-09-12 07:32)

[ :: Read More :: ]

Just a suggestion, but for modern controllers it would be really nice if the extra controls could be mapped like:

  • Right trigger = X
  • Left trigger = O
  • Right thumbstick = Mouse

That would allow FPS games like Poom, Sorcerer to be played like a twin stick shooter on capable input devices, without actually changing Pico-8's input model.

P#96136 2021-08-17 12:48

[ :: Read More :: ]

This is a cut down version of the variable inspector I wrote a while ago. It's a bit more limited, but a lot more light weight. And there's a way to use it even if you have no tokens to spare (described below).

You use it to view Lua table variables:

  1. Run your game
  2. Press Esc to break into it
  3. Type: dinsp(variable)

Then use the mouse to expand values and scroll wheel to scroll up/down.

Code snippet follows (for some reason I can't use the code formatting tags):

poke(0x5f2d,3)cursor()pal()clip()function dadd(n,v,i,p)add(lines,{n=n,v=v,x=type(v)=="table"and"+"or" ",i=i},p) end function dexp(l,p)if l.x=="+" then for n,v in pairs(l.v) do p+=1 dadd(n,v,l.i.." ",p)end l.x="-"end end

function dinp()local x,y,b,w=stat(32),stat(33),stat(34),stat(36)line(x,y,x,y+2,10)if btnp(❎) then local i=(y-10)\6+1 local p=s+i local l=lines[p]if l and (x-10)\4==#l.i then dexp(l,p)end end s=max(min(s-stat(36),#lines-18),0)end

function dui()while true do rectfill(10,10,118,118,1)for i=1,18 do local l=lines[i+s]if l then print(l.i..l.x..l.n..":"..tostr(l.v),10,(i-1)*6+10,7)end end dinp()flip() end end function dinsp(v)lines,s={},0 dadd("value",v,"",#lines+1)dui()end

The snippet is 246 tokens.
If you don't have 246 spare tokens, you can still use it as follows:

  1. Run your game
  2. Press Esc to break into it
  3. Paste in each of the 3 snippet lines one at a time, pressing enter after each.
  4. Type: dinsp(variable)

The snippet must be entered as 3 separate lines because Pico-8 has a 255 character limit for lines in immediate mode.

P#95305 2021-07-26 07:12 ( Edited 2021-07-26 07:13)

[ :: Read More :: ]

This is a suggestion, not a bug obviously.

The ability to toggle on a metronome tick/beep every 4 beats in the sfx editor would be quite helpful for composing tunes.

P#95021 2021-07-18 08:41

[ :: Read More :: ]

Cart #mot_sorcerer-11 | 2022-04-10 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

UPDATE: The dungeon generation logic has been revamped. Rooms are not always rectangular, and can often have a bit more cover (or hiding places for monsters). Also added a couple of new enemy types. Gold has been removed (I needed the extra tokens), but it didn't really do anything anyway.

Grab your magic staff and venture deep into the demon realm to defeat Bahmott and his evil servants!

Trial of the Sorcerer is a procedurally generated 3D first person shooter inspired by Wolfenstein 3D and Catacomb Abyss.

Shoot monsters, collect loot, find keys to unlock doors, and try to find the exit to the next level.
And don't forget to pickup the power crystals to level-up your magic staff along the way.


Arrows = Move
X = Shoot
Z = Hold to strafe

Or use player 2 controls (E,S,D,F) to move/strafe and player 1 controls to turn.

Mouse input can be enabled via the pause menu (once in game), but only when playing via the Pico-8 application as mouse locking doesn't currently work in the browser version.


Doors with a small black keyhole require keys.
Each door requires a specific key, so if one won't open it means you don't have the right key yet.

P#94900 2021-07-16 05:45 ( Edited 2022-04-10 02:42)

[ :: Read More :: ]

Cart #mot_crypt-1 | 2021-07-02 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Still needs quite a bit of finishing off.
I'm posting it now mainly so I can play it on my phone :-)

Levels are randomly generated. Shoot monsters, collect loot, find keys to unlock doors and reach the exit.

P#94197 2021-06-29 09:35 ( Edited 2021-07-02 08:23)

[ :: Read More :: ]

Cart #mot_formula1-4 | 2021-02-19 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Strap into one of the world's fastest race cars and blast around the legendary Bronzerock circuit like it's 1988!
...or something - there's not a lot of physical or historical accuracy in this game :)


Driving off road slows you down. Driving too fast around corners causes you to slide.

You can use the pause menu to view your last/best lap times (my best so far is 1:43.23)

This is work-in-progress, so some caveats:

  • There are no other cars yet.
  • Lots of things need tweaking/adjusting.
P#87611 2021-02-14 03:01 ( Edited 2021-02-19 23:18)

View Older Posts