Skip to content

prjctimg/p5.nvim

Repository files navigation

Sketchspace screenshot

p5.nvim 🌸

Better editor support for p5.js sketchspaces in Neovim.

Release Tests

On this page


Features ✨

  • Live Server πŸš€ - Auto-reload preview in browser
  • Package Management πŸ“¦ - Install contributor libraries
  • Sketchspace πŸ“ - Minimal project setup
  • GitHub Gist πŸ”— - Share sketches (synced to sketchspace)
  • CDP DevTools πŸ› οΈ - Full Chrome DevTools Protocol panel: Console, Network, Eval, Debugger, Performance, Info tabs
  • Console πŸ“Ί - View browser logs in Neovim (deprecated β€” use CDP panel)
  • p5.js Docs πŸ“– - Built-in reference via snacks.picker
  • Snippets βœ‚οΈ - 100+ p5.js code snippets (VS Code JSON format, compatible with luasnip, blink.cmp, nvim-cmp)

Requirements πŸ“‹

  • nvim >= 0.11.0
  • Python 3.7+ (for development server)
  • websockets Python package (python3-websockets on Debian/Ubuntu, or sudo pipx install websockets)
  • curl (for console streaming)
  • lsof (checking ports)

Installation πŸ’Ύ

-- lazy.nvim (installs latest release)
{
  "prjctimg/p5.nvim",
  dependencies = {
    "nvim-lua/plenary.nvim",
  },
  config = function()
    require("p5").setup({})
  end
}

What's a sketchspace ?

A directory that has a p5.json file is called a sketchspace. The file looks like this:

{
  "version": "2.0.0",
  "major": 2,
  "libs": {},
  "includes": ["sketch.js"],
  "gist": {
    "url": "username/gistId",
    "title": "My Sketch",
    "description": "Description from gist comment"
  }
}
  • version: p5.js version to use
  • major: p5.js major version (1 or 2)
  • libs: Object with library names as keys and their versions as values
  • includes: Files to include in the Gist (default: ["sketch.js"])
  • gist: Gist metadata object (optional) with url ("user/gistId"), title, and description

Important

This file is needed for setting up and running sketchspaces.

It currently only works with this plugin.


Quick Start πŸš€

:P5 create my-sketch
:P5 server
:P5 cdp

Commands πŸ“–

:P5 (interactive menu)

Open an interactive menu with all available commands. This is the default when :P5 is called without arguments.

:P5              # Open interactive menu

The menu shows context-aware labels (e.g. "Stop server" when the server is running vs "Start server" when it's not).


:P5 create [name]

Create a new sketchspace.

:P5 create my-sketch
:P5 create

When prompted for a version, selecting Latest (2.x) will skip TypeScript type definitions until the p5.js 2.x type declarations are officially released. The project is created immediately with everything else β€” you can start coding right away. Run :P5 setup later to copy types once they become available.


:P5 setup

Setup assets in current sketchspace.

Downloads files from gist (if configured), creates default sketch.js if missing, copies assets, generates libs.js, and installs configured libraries.

:P5 setup

:P5 install [libs...]

Install contributor libraries. Use picker or specify directly.

:P5 install ml5
:P5 install ml5 rita p5play
:P5 install

:P5 uninstall [libs...]

Remove installed libraries.

:P5 uninstall ml5
:P5 uninstall

:P5 server [port]

Start/stop the development server (toggle). Opens browser automatically and enables live reload.

:P5 server
:P5 server 8080

:P5 console (deprecated)

⚠️ Deprecated β€” use :P5 cdp instead. The CDP panel's Console tab provides richer output with stack traces, object previews, and structured log data.

Toggle browser console to view console.log, errors, and warnings in Neovim.

:P5 console     # Opens CDP panel on Console tab (with deprecation notice)
:P5 cdp         # Open CDP panel (6 tabs: Console, Network, Eval, Debug, Perf, Info)

:P5 cdp [subcommand]

Open the Chrome DevTools Protocol panel β€” a full-featured debugging dashboard for your p5.js sketch with 6 tabs:

Tab Key What it shows
Console 1 console.log/warn/error/info with stack traces, timestamps, and level filtering
Network 2 HTTP requests: method, status, duration, URL with color-coded status codes
Eval 3 Evaluate arbitrary JS expressions in the browser context
Debug 4 Set breakpoints, step through code, inspect call stack
Perf 5 Live FPS (instant/1s/10s avg), JS heap, DOM nodes, FPS sparkline
Info 6 Project info, canvas state, LSP document symbols for current buffer
:P5 cdp                # Toggle CDP panel
:P5 cdp connect        # Connect to Chrome debugger
:P5 cdp disconnect     # Disconnect
:P5 cdp status         # Show connection status
:P5 cdp eval <expr>    # Evaluate JS expression
:P5 cdp break <loc>    # Set breakpoint (e.g., sketch.js:12)
:P5 cdp continue       # Resume execution
:P5 cdp step           # Step over
:P5 cdp stepIn         # Step into
:P5 cdp stepOut        # Step out
:P5 cdp perf           # Open Performance tab

CDP panel keymaps (context-aware per tab):

Key Console Network Eval Debug Perf Info
1-6 Switch tab Switch tab Switch tab Switch tab Switch tab Switch tab
q/<Esc> Close Close Close Close Close Close
c Clear Clear Clear Clear Clear β€”
r Refresh Refresh β€” β€” Toggle rec Refresh LSP
<CR> β€” β€” Enter expr Set BP β€” Jump to sym
f Filter β€” β€” β€” β€” β€”
/ Search Search β€” β€” β€” β€”
s β€” β€” β€” Step over β€” β€”
i β€” β€” β€” Step into β€” β€”
o β€” β€” β€” Step out β€” β€”
x β€” β€” β€” Continue β€” β€”
b β€” β€” β€” Breakpoint β€” β€”
D β€” Clear all β€” β€” β€” β€”
K/J β€” β€” β€” β€” β€” Nav symbols
g/G Top/Bot Top/Bot Top/Bot Top/Bot Top/Bot Top/Bot

Keyboard shortcuts example:

vim.keymap.set("n", "<leader>pd", ":P5 cdp<CR>", { desc = "Toggle CDP DevTools" })

Browser flags: When CDP is enabled, Chrome launches with graphics-debugging flags: --enable-gpu-rasterization, --disable-frame-rate-limit, --enable-precise-memory-info, and more. Configure via setup({ cdp = { browser_flags = { ... } } }).


:P5 gist [desc|sync|edit]

Create, sync, or edit a GitHub Gist from your sketchspace.

:P5 gist "My awesome sketch"     # Create gist with title
:P5 gist                         # Prompt for title then create
:P5 gist sync                    # Bidirectional sync (title, description, files)
:P5 gist edit                    # Edit gist title or first comment

On creation, stores gist as an object in p5.json with url, title, and description (from the gist's first comment).

When syncing, compares remote vs local state and prompts per difference: title, description (first comment), and each source file. Files existing on only one side are auto-accepted.

Use :P5 gist edit to change the title or first comment β€” changes sync both to the remote gist and the local p5.json.


:P5 update [libs...]

Update all installed libraries or specific ones.

:P5 update                       # Update all installed addons
:P5 update ml5 p5play            # Update specific libraries

:P5 skchbk [list]

Clone all gists from a GitHub user into a local skchbk/ directory. Each gist is saved in its own subdirectory named after the gist description.

Requires a dedicated GitHub account whose gists are all valid p5.js sketches.

:P5 skchbk                # Clone all gists from configured user
:P5 skchbk list           # Browse local sketches or browse/list remotely

If skchbk/ doesn't exist or is empty, :P5 skchbk list prompts you to clone all gists or browse them remotely and clone individual ones.

The skchbk/ directory is automatically excluded from gist uploads.


:P5 list

Open a picker of recently used sketchspaces and change directory to the selected one.

:P5 list

:P5 docs

Open p5.js documentation via snacks.picker.

:P5 docs

Snippets βœ‚οΈ

p5.nvim ships with 100+ p5.js code snippets in VS Code JSON format. All snippets use a p5- prefix to avoid conflicts with other snippet packs.

Installation

Snippets are auto-discovered from runtimepath. Just add a snippet loader:

LuaSnip:

require("luasnip.loaders.from_vscode").lazy_load()

blink.cmp (default preset): Auto-discovered, zero configuration.

blink.cmp (luasnip preset):

-- Already using luasnip? snippets are auto-discovered via luasnip
sources = {
  default = { "lsp", "path", "snippets", "buffer" },
}

nvim-cmp:

cmp.setup({
  snippet = {
    expand = function(args)
      require("luasnip").lsp_expand(args.body)
    end,
  },
  sources = {
    { name = "luasnip" },
  },
})

Trigger Convention

Type p5- followed by the snippet name in a .js file to trigger:

Category Example Trigger Expands To
Lifecycle p5-sketch, p5-setup, p5-draw, p5-preload Full sketch skeleton or function
Paired constructs p5-push, p5-beginshape, p5-loadpixels, p5-creategraphics Block with open/close calls
Vertex calls p5-vertex, p5-curvevertex, p5-beziervertex Single vertex() inside shape
Basic shapes p5-canvas, p5-circle, p5-rect, p5-line Common 2D primitives
Color & style p5-fill, p5-stroke, p5-nofill, p5-colormode-hsb Color and attribute setters
Transformations p5-translate, p5-rotate, p5-scale Coordinate transforms
Math & vector p5-map, p5-constrain, p5-random, p5-vector Math utilities
Typography p5-text, p5-textsize, p5-loadfont, p5-textalign Text rendering
Images p5-loadimage, p5-pixels, p5-tint, p5-filter Image loading and processing
Events p5-mousepressed, p5-keypressed, p5-mousedragged Input event handlers
3D / WebGL p5-box, p5-sphere, p5-orbitcontrol, p5-texture 3D primitives and lights
DOM p5-createslider, p5-createbutton, p5-createselect UI elements
Sound p5-loadsound, p5-fft, p5-oscillator Audio playback and analysis
IO p5-loadjson, p5-loadstrings, p5-savecanvas Data loading and saving
Common idioms p5-forgrid, p5-forpolar, p5-particles, p5-bounce Multi-line patterns

Example

Typing p5-sketch and expanding gives:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

Typing p5-beginshape and expanding gives:

beginShape();
  vertex(x, y)
endShape(CLOSE);

All tab stops ($1, $2, etc.) are navigable; press <Tab> to jump between them (requires luasnip or blink.cmp luasnip preset).


Configuration ⚑

require("p5").setup({
  -- Server settings
  server = {
    port = 8000,                    -- Server port
    auto_start = false,             -- Auto start server when opening sketch.js
    auto_open_browser = true,      -- Open browser automatically

    -- Live reload settings
    live_reload = {
      enabled = true,               -- Enable live reload
      port = 12002,                -- Live reload port
      debounce_ms = 300,           -- Debounce delay
      watch_extensions = {".js", ".css", ".html", ".json"},  -- Files to watch
      exclude_dirs = {".git", "node_modules", "dist", "build"}  -- Exclude directories
    }
  },

  -- Console settings
  console = {
    enabled = true,                 -- Enable console integration
    position = "below",             -- Window position: below, above, left, right
    height = 10,                    -- Window height (lines)
  },

  -- Library settings
  libraries = {
    auto_update = false            -- Auto update libraries on setup
  },

  -- Sketchbook settings
  sketchbook = {
    user = ""                      -- GitHub username whose gists form the sketchbook
  },

  -- CDP DevTools settings
  cdp = {
    enabled = false,               -- Enable CDP (auto-enabled when panel opens)
    remote_debugging_port = 9222,  -- Chrome remote debugging port
    browser_flags = {              -- Extra Chrome flags for graphics debugging
      "--no-first-run",
      "--no-default-browser-check",
      "--enable-gpu-rasterization",
      "--disable-frame-rate-limit",
      "--disable-gpu-driver-bug-workarounds",
      "--enable-precise-memory-info",
      "--disable-software-rasterizer",
    },
  },
})

Auto Commands πŸ”Œ

Auto-start server when opening a sketch.js file:

-- Auto-start server when opening sketch.js
vim.api.nvim_create_autocmd({ "BufEnter" }, {
  pattern = "sketch.js",
  callback = function()
    vim.cmd("P5 server")
  end
})

-- Auto-open CDP panel when server starts
vim.api.nvim_create_autocmd({ "User", "P5ServerStarted" }, {
  callback = function()
    vim.cmd("P5 cdp")
  end
})

Keyboard Shortcuts ⌨️

Example keybindings using <leader>p prefix:

-- General
vim.keymap.set("n", "<leader>p5", ":P5<CR>", { desc = "Open p5.nvim picker" })

-- Project
vim.keymap.set("n", "<leader>pc", ":P5 create ", { desc = "Create project" })
vim.keymap.set("n", "<leader>ps", ":P5 setup<CR>", { desc = "Setup project" })

-- Server
vim.keymap.set("n", "<leader>pss", ":P5 server<CR>", { desc = "Toggle server" })
vim.keymap.set("n", "<leader>pso", ":P5 console<CR>", { desc = "Toggle console (deprecated)" })
vim.keymap.set("n", "<leader>psd", ":P5 cdp<CR>", { desc = "Toggle CDP DevTools" })

-- Libraries
vim.keymap.set("n", "<leader>pi", ":P5 install ", { desc = "Install library" })
vim.keymap.set("n", "<leader>pu", ":P5 uninstall ", { desc = "Uninstall library" })
vim.keymap.set("n", "<leader>pU", ":P5 sync libs<CR>", { desc = "Update libraries" })

-- Gist
vim.keymap.set("n", "<leader>pg", ":P5 gist ", { desc = "Create gist" })
vim.keymap.set("n", "<leader>pgg", ":P5 gist sync<CR>", { desc = "Sync gist" })

-- Docs
vim.keymap.set("n", "<leader>pd", ":P5 docs<CR>", { desc = "Open p5.js docs" })

Troubleshooting πŸ”§

Server Won't Start

Symptoms: Running :P5 server shows an error or nothing happens.

Solutions:

  1. Ensure Python 3 is installed:

    python3 --version
  2. Check if the port is already in use:

    lsof -i :8000
  3. Try a different port:

   :P5 server 8080
  1. Check Neovim notifications for specific error messages

Downloads Not Working

Library installation fails or downloads timeout.

Solutions:

  1. Ensure curl is installed:

    curl --version
  2. Check internet connection:

    curl -I https://cdnjs.cloudflare.com
  3. Verify firewall isn't blocking localhost connections

  4. Check that you're in a valid sketchspace (has p5.json)

Gist Upload/Sync Fails

:P5 gist or :P5 sync gist shows an error.

Solutions:

  1. Ensure GitHub CLI is installed:

    gh --version
  2. Authenticate with GitHub:

    gh auth login
  3. Verify gist URL in p5.json is valid:

    :edit p5.json
  4. For sync failures, the gist may have been deleted - run :P5 gist to create a new one

Library Install/Uninstall Fails

:P5 install or :P5 uninstall shows an error.

Solutions:

  1. Verify you're in a sketchspace (directory with a p5.json file):

    ls p5.json
  2. Check assets/libs directory is writable:

    ls -la assets/libs
  3. Run setup first to initialize:

    :P5 setup

License πŸ“œ

(c) 2026, prjctimg

This is free software, released under the GPL-3.0 license.



About

Better editor support for p5.js 🌸 sketchspaces in Neovim

Topics

Resources

License

Stars

Watchers

Forks

Contributors