Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Setting up VS Code for PICO-8

Pico² is releasing on Feb 9th 2025! Follow on itch.io for updates!

See the Pico² Design Document!


I don’t use the built-in PICO-8 code editor as I find it far too limiting. Here’s a breakdown of my VS Code setup when I’m coding for PICO-8.


Prerequisites

The pico8-ls Extension adds a language server for PICO-8 Lua. This means you get auto-complete snippets, syntax highlighting, definition on hover and even jump to definition across Lua files. Highly recommended!

I use Material Theme.

Python for the pre-processor script.


Set-up

I work directly in the projects folder, since PICO-8 launches here automatically.

Removing Comments

I made a script which removes all single- and multi-line comments, but leaves new lines where applicable. This means any traceback errors in PICO-8 will show you the right line numbers!

Before:

After:

This obviously still uses characters, so ideally use a better script if you actually want to minify your script for export.

Open your project folder in VS Code. You should have a .p8 main PICO-8 file in there. On the same level as this .p8 file, make:

  • A folder called output
  • A Python file called remove_comments.py
  • A duplicate of the .p8 file (call it whatever you want)
- my_game
	- output
	my_game.p8
	my_game_copy.p8
	remove_comments.py

Copy and paste the following code into the Python file.

import re
import sys
import os, shutil

def remove_comments(file_path, output_path):
    with open(file_path, 'r') as file:
        code = file.read()

    # Regex to remove single-line and multi-line comments

    # -- matches two dashes at start
    # \[\[ matches the opening [[ of multiline
    # [\s\S]* matches any character, including newlines
    #         * is lazy match, stops at first ]]
    # \]\] matches closing ]]
    no_comments = re.sub(r'--\[\[[\s\S]*?\]\]--', replace_with_empty_lines, code)

    # (?<!\[) negative lookbehind ensures -- is not preceded by [
    # -- matches two dashes at start
    # [^\[] matches any character that is NOT [
    # .* matches the rest of the line after --, up to end of line
    no_comments = re.sub(r'(?<!\[)--[^\[].*', '', no_comments)

    with open(output_path, 'w') as output_file:
        output_file.write(no_comments)

# Function to replace each match
def replace_with_empty_lines(match):
    comment = match.group(0)            # Extract the comment content
    line_count = comment.count('\n')    # Count lines in the comment block
    return '\n' * line_count            # Replace with that many newlines

if __name__ == "__main__":
    folder = './output'

    # Empty the output folder
    for filename in os.listdir(folder):
        file_path = os.path.join(folder, filename)
        try:
            if os.path.isfile(file_path) or os.path.islink(file_path):
                os.unlink(file_path)
            elif os.path.isdir(file_path):
                shutil.rmtree(file_path)
        except Exception as e:
            print('Failed to delete %s. Reason: %s' % (file_path, e))

    # Get arguments after current file
    files = sys.argv[1:]

    """
    files = [
        "file1.lua", "file1_out.lua",
        "file2.lua", "file2_out.lua",
        "file3.lua", "file3_out.lua",
        ...
    ]
    """

    # Clean up all files
    while len(files)!=0:
        file_in = files.pop(0)
        file_out = files.pop(0)
        remove_comments(file_in, f"./output/{file_out}")

Next, go to Terminal > Configure Tasks... > Create tasks.json file from template > Others.

You’ll find that file in your project directory, in the .vscode folder. Open tasks.json and copy and paste the following code there.

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Remove Comments",
            "type": "shell",
            "command": "python",
            "args": [
                "remove_comments.py",
                "file1.lua", "file1_out.lua",
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
	         "reveal": "silent"
	     }
        }
    ]
}

Go to Terminal > Configure Default Build Task > Remove Comments.

Finally, go to View > Command Palette > Preferences: Open User Settings (JSON).

Find "[pico-8-lua]" and change it to this:

"[pico-8-lua]": {  
        "editor.suggest.showSnippets": false
    },

Usage

Running PICO-8

First, open the Terminal/Command Prompt (a separate app, not the built-in one for VS Code).

Open PICO-8 by typing: /System/Volumes/Data/Applications/PICO-8.app/Contents/MacOS/pico8

This is for MacOS, but it’s probably similar for other operating systems - just write the path to the executable.

This lets you use printh() in your code, which prints to that terminal window. Invaluable for debugging!

Making New Files

All your code will be written in separate .lua files instead of the .p8 cart itself.

For example, see this file structure after the set-up:

- my_game
	- .vscode
		tasks.json
	- output
	my_game.p8
	my_game_copy.p8
	remove_comments.py
        main.lua

Let’s say I want to add a file called main.lua.

When you want to make a new file, follow these steps:

  1. Make the .lua file in the main directory (already done in structure above).
  2. In the my_game.p8 file, write the following: #include ./output/main_out.lua
  3. In the my_game_copy.p8 file, write the following: #include ./main.lua
  4. In .vscode/tasks.json, add the following arguments (in order):
    • "main.lua"
    • "main_out.lua"
      • An example for file1.lua can be seen in the code you copied and pasted. You should remove that example.
  5. Open the new .lua file, and in the bottom right, set the editor to use tabs instead of spaces.
    • I prefer having big tabs to see indentation, but using 4 spaces will increase character count dramatically.

Processing and Running the Cart

When you want to run your code and test your game:

  1. Click into VS Code and press Shift+Cmd+B or Shift+Ctrl+B
  2. Click into PICO-8 and press Cmd+R or Ctrl+R

Explanation

The regex file is commented if you’re curious - it seems to break if you put -- in a string, so don’t do that! I don’t know much about regex so I can’t be bothered to fix it.

The pico8-ls extension works very well even across separate .lua files. However, our my_game.p8 cart now only includes the _out.lua cleaned files. This means when you open the commented .lua files, the languages server doesn’t pick them up.

I fixed this by including the duplicate my_game_copy.p8, which includes the commented files and tricks the language server into thinking it’s the real files!

Also the task could probably be simplified, but again I don’t want to spend forever making it perfect, it’s good enough for me!

Finally, I changed that setting because the extension would often autocomplete do and end to random Japanese characters which is super annoying. That line removes the autocomplete.


There’s the full set-up; hope it helps!


Follow on Twitter @wsasaki01 Follow on Bluesky at wsasaki.bsky.social

Support this post

Did you like this post? Tell us

Leave a comment

Log in with your itch.io account to leave a comment.