Technical Documentation: kitao/pyxel
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
[](https://kitao.dev/pyxel/)
A retro game engine for Python
<a href="https://kitao.dev/pyxel/user-examples/"
></a>
<a href="https://gihyo.jp/book/2025/978-4-297-14657-3"
></a>
<a href="https://kitao.dev/pyxel/showcase/examples/02-jump-game.html">
</a>
<a href="https://kitao.dev/pyxel/showcase/examples/10-platformer.html">
</a>
<a href="https://kitao.dev/pyxel/showcase/apps/30sec-of-daylight.html">
</a>
<a href="https://kitao.dev/pyxel/showcase/apps/megaball.html">
</a>
<a href="https://kitao.dev/pyxel/showcase/tools/image-editor.html">
</a>
<a href="https://kitao.dev/pyxel/showcase/tools/sound-editor.html">
</a>
<a
href="https://kitao.dev/pyxel/showcase/examples/c04-mesh-and-motion.html"
>
</a>
<a
href="https://kitao.dev/pyxel/showcase/examples/c05-3d-collision.html"
>
</a>
<a href="https://kitao.dev/pyxel/showcase/examples/c06-3d-physics.html">
</a>Api Reference (`docs/api-reference.md`)
Pyxel API Reference
This document was auto-generated from the Pyxel API Reference web page, which also offers multilingual support.
System
`width` โ variable
The width of the screen.
- Type:
int
`height` โ variable
The height of the screen.
- Type:
int
`frame_count` โ variable
The number of elapsed frames.
- Type:
int
`init(width, height, title="Pyxel", fps=30, quit_key=KEY_ESCAPE, display_scale=None, capture_scale=2, capture_sec=10, headless=False)` โ function
Initialize the Pyxel application with the screen size (width, height).
Parameters:
width(int) โ Screen widthheight(int) โ Screen heighttitle(str) โ Window title. Defaults to "Pyxel".fps(int) โ Frame rate. Defaults to 30.quit_key(int) โ Key to quit the application. Defaults to KEY_ESCAPE.display_scale(int) โ Display scale factor. If omitted, automatically determined.capture_scale(int) โ Screen capture scale factor. Defaults to 2.capture_sec(int) โ Maximum recording time for screen capture video. Defaults to 10.headless(bool) โ Run without a window. Defaults to False.
Example:
pyxel.init(
160,
120,
title="My Pyxel App",
fps=60,
quit_key=pyxel.KEY_NONE,
capture_scale=3,
capture_sec=0,
)`run(update, draw)` โ function
Start the Pyxel application and call the update function for frame update and the draw function for drawing.
Parameters:
update(callable) โ Function to update game logic each framedraw(callable) โ Function to draw the screen each frame
`show()` โ function
Show the screen and wait until the quit key is pressed.
`flip()` โ function
Refresh the screen by one frame. The application exits when the quit key is pressed. This function is not available in the web version.
`quit()` โ function
Quit the Pyxel application.
`reset()` โ function
Restart the Pyxel application from the beginning.
`title(title)` โ function *(Advanced)*
Set the window title.
Parameters:
title(str) โ Window title
`icon(data, scale, colkey=None)` โ function *(Advanced)*
Set the application icon. Specify the icon image as a list of strings.
Parameters:
data(list[str]) โ Icon image as a list of stringsscale(int) โ Scale factorcolkey(int/None) โ Transparent color. If omitted, no transparency.
`fullscreen(enabled)` โ function *(Advanced)*
Set whether to run in fullscreen mode.
Parameters:
enabled(bool) โ Enable fullscreen
`resize(width, height)` โ function *(Advanced)*
Change the screen size at runtime.
Parameters:
width(int) โ New screen width in pixelsheight(int) โ New screen height in pixels
`screen_mode(scr)` โ function *(Advanced)*
Set the screen mode (0: crisp, 1: smooth, 2: retro).
Parameters:
scr(int) โ Screen mode number (0: crisp, 1: smooth, 2: retro)
`perf_monitor(enabled)` โ function *(Advanced)*
Show or hide the performance monitor.
Parameters:
enabled(bool) โ Enable the performance monitor
`integer_scale(enabled)` โ function *(Advanced)*
Enable integer scaling for the display.
Parameters:
enabled(bool) โ Enable integer scaling
Resource
`load(filename, exclude_images=False, exclude_tilemaps=False, exclude_sounds=False, exclude_musics=False)` โ function
Load the resource file (.pyxres). If an option is set to True, the corresponding resource will be excluded from loading.
Parameters:
filename(str) โ Resource file nameexclude_images(bool) โ Exclude image banks. Defaults to False.exclude_tilemaps(bool) โ Exclude tilemaps. Defaults to False.exclude_sounds(bool) โ Exclude sounds. Defaults to False.exclude_musics(bool) โ Exclude music tracks. Defaults to False.
Note: If a palette file (.pyxpal) with the same name exists, the palette display colors will also be updated.
`user_data_dir(vendor_name, app_name)` โ function *(Advanced)*
Return the user data directory created based on vendor_name and app_name. If the directory does not exist, it will be created automatically.
Parameters:
vendor_name(str) โ Vendor nameapp_name(str) โ Application name
Returns: str โ Path to the user data directory
Example:
pyxel.user_data_dir("Takashi Kitao", "Pyxel Shooter")`save(filename, exclude_images=False, exclude_tilemaps=False, exclude_sounds=False, exclude_musics=False)` โ function *(Advanced)*
Save the resource file (.pyxres). If an option is set to True, the corresponding resource will be excluded from saving.
Parameters:
filename(str) โ Resource file nameexclude_images(bool) โ Exclude image banks. Defaults to False.exclude_tilemaps(bool) โ Exclude tilemaps. Defaults to False.exclude_sounds(bool) โ Exclude sounds. Defaults to False.exclude_musics(bool) โ Exclude music tracks. Defaults to False.
`screenshot(filename=None, scale=2)` โ function *(Advanced)*
Take a screenshot.
Parameters:
filename(str/None) โ File name. If omitted, saved to desktop.scale(int/None) โ Scale factor. Defaults to capture_scale.
`screencast(filename=None, scale=2)` โ function *(Advanced)*
Save the screen recording as a GIF file.
Parameters:
filename(str/None) โ File name. If omitted, saved to desktop.scale(int/None) โ Scale factor. Defaults to capture_scale.
`reset_screencast()` โ function *(Advanced)*
Reset the screen recording buffer.
`load_pal(filename)` โ function *(Advanced)*
Load a palette file (.pyxpal).
Parameters:
filename(str) โ Palette file name
`save_pal(filename)` โ function *(Advanced)*
Save a palette file (.pyxpal).
Parameters:
filename(str) โ Palette file name
Input
`mouse_x` โ variable
The current x position of the mouse cursor.
- Type:
int
`mouse_y` โ variable
The current y position of the mouse cursor.
- Type:
int
`mouse_wheel` โ variable
The current value of the mouse wheel.
- Type:
int
`input_keys` โ variable *(Advanced)*
List of keys input in the current frame.
- Type:
list[int]
`input_text` โ variable *(Advanced)*
Text input in the current frame.
- Type:
str
`dropped_files` โ variable *(Advanced)*
List of files dropped in the current frame.
- Type:
list[str]
`btn(key)` โ function
Return True if the key is pressed, otherwise return False.
Parameters:
key(int) โ Key code
Returns: bool โ True if pressed
`btnp(key, hold=0, repeat=0)` โ function
Return True if the key is pressed in that frame. When hold and repeat are specified, after holding the key for hold frames, return True every repeat frames.
Parameters:
key(int) โ Key codehold(int) โ Frames to hold before repeat starts. Defaults to 0.repeat(int) โ Repeat interval in frames. If 0, no repeat.
Returns: bool โ True if pressed in that frame
`btnr(key)` โ function
Return True if the key is released in that frame, otherwise return False.
Parameters:
key(int) โ Key code
Returns: bool โ True if released in that frame
`mouse(visible)` โ function
Show the mouse cursor if visible is True, and hide it if False. The cursor position continues to update even when hidden.
Parameters:
visible(bool) โ Show or hide the cursor
`btnv(key)` โ function *(Advanced)*
Return the analog value of the specified key (e.g., gamepad axis value).
Parameters:
key(int) โ Key code
Returns: int โ Analog value of the key
`set_btn(key, state)` โ function *(Advanced)*
Set the press/release state of the specified key. Mainly for headless mode input simulation.
Parameters:
key(int) โ Target keystate(bool) โ True for press, False for release
`set_btnv(key, val)` โ function *(Advanced)*
Set the analog value of the specified key. Mainly for headless mode input simulation.
Parameters:
key(int) โ Target keyval(int) โ Analog value to set
`set_mouse_pos(x, y)` โ function *(Advanced)*
Set the mouse cursor position. Mainly for headless mode input simulation.
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate
`set_input_text(text)` โ function *(Advanced)*
Set the text input for the current frame. Replaces any existing text. Mainly for headless mode input simulation.
Parameters:
text(str) โ Text input
`set_dropped_files(files)` โ function *(Advanced)*
Set the dropped file list for the current frame. Replaces any existing list. Mainly for headless mode input simulation.
Parameters:
files(list[str]) โ List of file paths
Key Constants
Special Keys:
KEY_UNKNOWN KEY_RETURN KEY_ESCAPE KEY_BACKSPACE KEY_TAB KEY_SPACE KEY_NONE
Letters:
KEY_A KEY_B KEY_C KEY_D KEY_E KEY_F KEY_G KEY_H KEY_I KEY_J KEY_K KEY_L KEY_M KEY_N KEY_O KEY_P KEY_Q KEY_R KEY_S KEY_T KEY_U KEY_V KEY_W KEY_X KEY_Y KEY_Z
Numbers:
KEY_0 KEY_1 KEY_2 KEY_3 KEY_4 KEY_5 KEY_6 KEY_7 KEY_8 KEY_9
Symbols:
KEY_EXCLAIM KEY_QUOTEDBL KEY_HASH KEY_PERCENT KEY_DOLLAR KEY_AMPERSAND KEY_QUOTE KEY_LEFTPAREN KEY_RIGHTPAREN KEY_ASTERISK KEY_PLUS KEY_COMMA KEY_MINUS KEY_PERIOD KEY_SLASH KEY_COLON KEY_SEMICOLON KEY_LESS KEY_EQUALS KEY_GREATER KEY_QUESTION KEY_AT KEY_LEFTBRACKET KEY_BACKSLASH KEY_RIGHTBRACKET KEY_CARET KEY_UNDERSCORE KEY_BACKQUOTE
Function:
KEY_F1 KEY_F2 KEY_F3 KEY_F4 KEY_F5 KEY_F6 KEY_F7 KEY_F8 KEY_F9 KEY_F10 KEY_F11 KEY_F12 KEY_F13 KEY_F14 KEY_F15 KEY_F16 KEY_F17 KEY_F18 KEY_F19 KEY_F20 KEY_F21 KEY_F22 KEY_F23 KEY_F24
Navigation:
KEY_INSERT KEY_HOME KEY_PAGEUP KEY_DELETE KEY_END KEY_PAGEDOWN KEY_RIGHT KEY_LEFT KEY_DOWN KEY_UP
Modifiers:
KEY_CAPSLOCK KEY_LCTRL KEY_LSHIFT KEY_LALT KEY_LGUI KEY_RCTRL KEY_RSHIFT KEY_RALT KEY_RGUI KEY_SHIFT KEY_CTRL KEY_ALT KEY_GUI
Numpad:
KEY_NUMLOCKCLEAR KEY_KP_DIVIDE KEY_KP_MULTIPLY KEY_KP_MINUS KEY_KP_PLUS KEY_KP_ENTER KEY_KP_1 KEY_KP_2 KEY_KP_3 KEY_KP_4 KEY_KP_5 KEY_KP_6 KEY_KP_7 KEY_KP_8 KEY_KP_9 KEY_KP_0 KEY_KP_PERIOD KEY_KP_EQUALS KEY_KP_COMMA KEY_KP_EQUALSAS400 KEY_KP_00 KEY_KP_000 KEY_KP_LEFTPAREN KEY_KP_RIGHTPAREN KEY_KP_LEFTBRACE KEY_KP_RIGHTBRACE KEY_KP_TAB KEY_KP_BACKSPACE KEY_KP_A KEY_KP_B KEY_KP_C KEY_KP_D KEY_KP_E KEY_KP_F KEY_KP_XOR KEY_KP_POWER KEY_KP_PERCENT KEY_KP_LESS KEY_KP_GREATER KEY_KP_AMPERSAND KEY_KP_DBLAMPERSAND KEY_KP_VERTICALBAR KEY_KP_DBLVERTICALBAR KEY_KP_COLON KEY_KP_HASH KEY_KP_SPACE KEY_KP_AT KEY_KP_EXCLAM KEY_KP_MEMSTORE KEY_KP_MEMRECALL KEY_KP_MEMCLEAR KEY_KP_MEMADD KEY_KP_MEMSUBTRACT KEY_KP_MEMMULTIPLY KEY_KP_MEMDIVIDE KEY_KP_PLUSMINUS KEY_KP_CLEAR KEY_KP_CLEARENTRY KEY_KP_BINARY KEY_KP_OCTAL KEY_KP_DECIMAL KEY_KP_HEXADECIMAL
System & Media:
KEY_PRINTSCREEN KEY_SCROLLLOCK KEY_PAUSE KEY_APPLICATION KEY_POWER KEY_EXECUTE KEY_HELP KEY_MENU KEY_SELECT KEY_STOP KEY_AGAIN KEY_UNDO KEY_CUT KEY_COPY KEY_PASTE KEY_FIND KEY_MUTE KEY_VOLUMEUP KEY_VOLUMEDOWN KEY_ALTERASE KEY_SYSREQ KEY_CANCEL KEY_CLEAR KEY_PRIOR KEY_RETURN2 KEY_SEPARATOR KEY_OUT KEY_OPER KEY_CLEARAGAIN KEY_CRSEL KEY_EXSEL KEY_THOUSANDSSEPARATOR KEY_DECIMALSEPARATOR KEY_CURRENCYUNIT KEY_CURRENCYSUBUNIT
Mouse Constants
Cursor & Wheel:
MOUSE_POS_X MOUSE_POS_Y MOUSE_WHEEL_X MOUSE_WHEEL_Y
Buttons:
MOUSE_BUTTON_LEFT MOUSE_BUTTON_MIDDLE MOUSE_BUTTON_RIGHT MOUSE_BUTTON_X1 MOUSE_BUTTON_X2
Gamepad Constants
Gamepad 1:
GAMEPAD1_AXIS_LEFTX GAMEPAD1_AXIS_LEFTY GAMEPAD1_AXIS_RIGHTX GAMEPAD1_AXIS_RIGHTY GAMEPAD1_AXIS_TRIGGERLEFT GAMEPAD1_AXIS_TRIGGERRIGHT GAMEPAD1_BUTTON_A GAMEPAD1_BUTTON_B GAMEPAD1_BUTTON_X GAMEPAD1_BUTTON_Y GAMEPAD1_BUTTON_BACK GAMEPAD1_BUTTON_GUIDE GAMEPAD1_BUTTON_START GAMEPAD1_BUTTON_LEFTSTICK GAMEPAD1_BUTTON_RIGHTSTICK GAMEPAD1_BUTTON_LEFTSHOULDER GAMEPAD1_BUTTON_RIGHTSHOULDER GAMEPAD1_BUTTON_DPAD_UP GAMEPAD1_BUTTON_DPAD_DOWN GAMEPAD1_BUTTON_DPAD_LEFT GAMEPAD1_BUTTON_DPAD_RIGHT
Gamepad 2:
GAMEPAD2_AXIS_LEFTX GAMEPAD2_AXIS_LEFTY GAMEPAD2_AXIS_RIGHTX GAMEPAD2_AXIS_RIGHTY GAMEPAD2_AXIS_TRIGGERLEFT GAMEPAD2_AXIS_TRIGGERRIGHT GAMEPAD2_BUTTON_A GAMEPAD2_BUTTON_B GAMEPAD2_BUTTON_X GAMEPAD2_BUTTON_Y GAMEPAD2_BUTTON_BACK GAMEPAD2_BUTTON_GUIDE GAMEPAD2_BUTTON_START GAMEPAD2_BUTTON_LEFTSTICK GAMEPAD2_BUTTON_RIGHTSTICK GAMEPAD2_BUTTON_LEFTSHOULDER GAMEPAD2_BUTTON_RIGHTSHOULDER GAMEPAD2_BUTTON_DPAD_UP GAMEPAD2_BUTTON_DPAD_DOWN GAMEPAD2_BUTTON_DPAD_LEFT GAMEPAD2_BUTTON_DPAD_RIGHT
Gamepad 3:
GAMEPAD3_AXIS_LEFTX GAMEPAD3_AXIS_LEFTY GAMEPAD3_AXIS_RIGHTX GAMEPAD3_AXIS_RIGHTY GAMEPAD3_AXIS_TRIGGERLEFT GAMEPAD3_AXIS_TRIGGERRIGHT GAMEPAD3_BUTTON_A GAMEPAD3_BUTTON_B GAMEPAD3_BUTTON_X GAMEPAD3_BUTTON_Y GAMEPAD3_BUTTON_BACK GAMEPAD3_BUTTON_GUIDE GAMEPAD3_BUTTON_START GAMEPAD3_BUTTON_LEFTSTICK GAMEPAD3_BUTTON_RIGHTSTICK GAMEPAD3_BUTTON_LEFTSHOULDER GAMEPAD3_BUTTON_RIGHTSHOULDER GAMEPAD3_BUTTON_DPAD_UP GAMEPAD3_BUTTON_DPAD_DOWN GAMEPAD3_BUTTON_DPAD_LEFT GAMEPAD3_BUTTON_DPAD_RIGHT
Gamepad 4:
GAMEPAD4_AXIS_LEFTX GAMEPAD4_AXIS_LEFTY GAMEPAD4_AXIS_RIGHTX GAMEPAD4_AXIS_RIGHTY GAMEPAD4_AXIS_TRIGGERLEFT GAMEPAD4_AXIS_TRIGGERRIGHT GAMEPAD4_BUTTON_A GAMEPAD4_BUTTON_B GAMEPAD4_BUTTON_X GAMEPAD4_BUTTON_Y GAMEPAD4_BUTTON_BACK GAMEPAD4_BUTTON_GUIDE GAMEPAD4_BUTTON_START GAMEPAD4_BUTTON_LEFTSTICK GAMEPAD4_BUTTON_RIGHTSTICK GAMEPAD4_BUTTON_LEFTSHOULDER GAMEPAD4_BUTTON_RIGHTSHOULDER GAMEPAD4_BUTTON_DPAD_UP GAMEPAD4_BUTTON_DPAD_DOWN GAMEPAD4_BUTTON_DPAD_LEFT GAMEPAD4_BUTTON_DPAD_RIGHT
Graphics
`colors` โ variable
List of the palette display colors. Specified by 24-bit numerical value. Supports Python list operations.
- Type:
list[int]
Example:
old_colors = list(pyxel.colors)
pyxel.colors[15] = 0x112233`images` โ variable
Image banks (Image instances) (0-2).
- Type:
list[Image]
Example:
pyxel.images[0].load(0, 0, "title.png")`tilemaps` โ variable
Tilemaps (Tilemap instances) (0-7).
- Type:
list[Tilemap]
`screen` โ variable *(Advanced)*
The screen image (Image class instance).
- Type:
Image
`cursor` โ variable *(Advanced)*
The cursor image (Image class instance).
- Type:
Image
`font` โ variable *(Advanced)*
The font image (Image class instance).
- Type:
Image
`clip(x, y, w, h)` โ function
Set the drawing area of the screen from (x, y) with a width of w and a height of h. Call clip() to reset to full screen.
Parameters:
x(float) โ X coordinate of the upper-left cornery(float) โ Y coordinate of the upper-left cornerw(float) โ Width of the clipping areah(float) โ Height of the clipping area
`clip()` โ function
Reset the drawing area to full screen.
`camera(x, y)` โ function
Set the drawing offset to (x, y). All subsequent drawing operations will be shifted by (-x, -y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate
`camera()` โ function
Reset the drawing offset to (0, 0).
`pal(col1, col2)` โ function
Replace color col1 with col2 when drawing.
Parameters:
col1(int) โ Color to replacecol2(int) โ Replacement color
`pal()` โ function
Reset the palette to the initial state.
`dither(alpha)` โ function
Apply dithering (pseudo-transparency) when drawing. Set alpha in the range 0.0-1.0.
Parameters:
alpha(float) โ Opacity (0.0: transparent, 1.0: opaque)
`cls(col)` โ function
Clear the screen with color col.
Parameters:
col(int) โ Color
`pget(x, y)` โ function
Get the color of the pixel at (x, y). The coordinates are absolute and not affected by the camera offset.
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate
Returns: int โ Color of the pixel
`pset(x, y, col)` โ function
Draw a pixel of color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatecol(int) โ Color
`line(x1, y1, x2, y2, col)` โ function
Draw a line of color col from (x1, y1) to (x2, y2).
Parameters:
x1(float) โ Start X coordinatey1(float) โ Start Y coordinatex2(float) โ End X coordinatey2(float) โ End Y coordinatecol(int) โ Color
`rect(x, y, w, h, col)` โ function
Draw a filled rectangle of width w, height h, and color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatew(float) โ Widthh(float) โ Heightcol(int) โ Color
`rectb(x, y, w, h, col)` โ function
Draw the outline of a rectangle of width w, height h, and color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatew(float) โ Widthh(float) โ Heightcol(int) โ Color
`circ(x, y, r, col)` โ function
Draw a filled circle of radius r and color col at (x, y).
Parameters:
x(float) โ Center X coordinatey(float) โ Center Y coordinater(float) โ Radiuscol(int) โ Color
`circb(x, y, r, col)` โ function
Draw the outline of a circle of radius r and color col at (x, y).
Parameters:
x(float) โ Center X coordinatey(float) โ Center Y coordinater(float) โ Radiuscol(int) โ Color
`elli(x, y, w, h, col)` โ function
Draw a filled ellipse of width w, height h, and color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatew(float) โ Widthh(float) โ Heightcol(int) โ Color
`ellib(x, y, w, h, col)` โ function
Draw the outline of an ellipse of width w, height h, and color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatew(float) โ Widthh(float) โ Heightcol(int) โ Color
`tri(x1, y1, x2, y2, x3, y3, col)` โ function
Draw a filled triangle with vertices (x1, y1), (x2, y2), (x3, y3) and color col.
Parameters:
x1(float) โ Vertex 1 Xy1(float) โ Vertex 1 Yx2(float) โ Vertex 2 Xy2(float) โ Vertex 2 Yx3(float) โ Vertex 3 Xy3(float) โ Vertex 3 Ycol(int) โ Color
`trib(x1, y1, x2, y2, x3, y3, col)` โ function
Draw the outline of a triangle with vertices (x1, y1), (x2, y2), (x3, y3) and color col.
Parameters:
x1(float) โ Vertex 1 Xy1(float) โ Vertex 1 Yx2(float) โ Vertex 2 Xy2(float) โ Vertex 2 Yx3(float) โ Vertex 3 Xy3(float) โ Vertex 3 Ycol(int) โ Color
`fill(x, y, col)` โ function
Fill the area connected with the same color as (x, y) with color col.
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatecol(int) โ Fill color
`blt(x, y, img, u, v, w, h, colkey=None, rotate=0, scale=1)` โ function
Copy the region of size (w, h) from (u, v) of image bank img (0-2 or Image instance) to (x, y). Negative w/h flips the image. colkey sets the transparent color. rotate and scale apply transformations.
Parameters:
x(float) โ Destination Xy(float) โ Destination Yimg(int/Image) โ Image bank number (0-2) or Image instanceu(float) โ Source X in the image bankv(float) โ Source Y in the image bankw(float) โ Width (negative to flip)h(float) โ Height (negative to flip)colkey(int/None) โ Transparent color. If omitted, no transparency.rotate(float) โ Rotation angle in degrees (centered on the copy region). Defaults to 0.scale(float) โ Scale factor (centered on the copy region). Defaults to 1.
`bltm(x, y, tm, u, v, w, h, colkey=None, rotate=0, scale=1)` โ function
Copy the region of size (w, h) from (u, v) of tilemap tm (0-7 or Tilemap instance) to (x, y). Each tile is 8x8 pixels stored as (image_tx, image_ty). Negative w/h flips the image. colkey sets the transparent color. rotate and scale apply transformations.
Parameters:
x(float) โ Destination Xy(float) โ Destination Ytm(int/Tilemap) โ Tilemap number (0-7) or Tilemap instanceu(float) โ Source X in the tilemapv(float) โ Source Y in the tilemapw(float) โ Width (negative to flip)h(float) โ Height (negative to flip)colkey(int/None) โ Transparent color. If omitted, no transparency.rotate(float) โ Rotation angle in degrees (centered on the copy region). Defaults to 0.scale(float) โ Scale factor (centered on the copy region). Defaults to 1.
`blt3d(x, y, w, h, img, pos, rot, fov=60, colkey=None)` โ function *(Advanced)*
Draw the image bank img (0-2 or Image instance) with perspective projection onto the screen rectangle (x, y, w, h). pos is the camera position where x, y match 2D coordinates and z is height. rot is the rotation in degrees. fov sets the field of view in degrees. colkey sets the transparent color.
Parameters:
x(float) โ Destination Xy(float) โ Destination Yw(float) โ Display widthh(float) โ Display heightimg(int/Image) โ Image bank number (0-2) or Image instancepos((float, float, float)) โ Camera position (x, y, z). x, y match 2D coordinates, z is heightrot((float, float, float)) โ Rotation in degrees. rot_x is vertical, rot_y is horizontal, rot_z is tiltfov(float) โ Field of view in degrees. Defaults to 60.colkey(int/None) โ Transparent color. If omitted, no transparency.
`bltm3d(x, y, w, h, tm, pos, rot, fov=60, colkey=None)` โ function *(Advanced)*
Draw the tilemap tm (0-7 or Tilemap instance) with perspective projection onto the screen rectangle (x, y, w, h). pos is the camera position where x, y match 2D coordinates and z is height. rot is the rotation in degrees. fov sets the field of view in degrees. colkey sets the transparent color.
Parameters:
x(float) โ Destination Xy(float) โ Destination Yw(float) โ Display widthh(float) โ Display heighttm(int/Tilemap) โ Tilemap number (0-7) or Tilemap instancepos((float, float, float)) โ Camera position (x, y, z). x, y match 2D coordinates, z is heightrot((float, float, float)) โ Rotation in degrees. rot_x is vertical, rot_y is horizontal, rot_z is tiltfov(float) โ Field of view in degrees. Defaults to 60.colkey(int/None) โ Transparent color. If omitted, no transparency.
`text(x, y, s, col, font=None)` โ function
Draw a string s in color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinates(str) โ String to drawcol(int) โ Colorfont(Font) โ Custom font. If omitted, the standard font is used.
Color Constants
COLOR_BLACKโ 0 โ Black (#000000)COLOR_NAVYโ 1 โ Navy (#2b335f)COLOR_PURPLEโ 2 โ Purple (#7e2072)COLOR_GREENโ 3 โ Green (#19959c)COLOR_BROWNโ 4 โ Brown (#8b4852)COLOR_DARK_BLUEโ 5 โ Dark Blue (#395c98)COLOR_LIGHT_BLUEโ 6 โ Light Blue (#a9c1ff)COLOR_WHITEโ 7 โ White (#eeeeee)COLOR_REDโ 8 โ Red (#d4186c)COLOR_ORANGEโ 9 โ Orange (#d38441)COLOR_YELLOWโ 10 โ Yellow (#e9c35b)COLOR_LIMEโ 11 โ Lime (#70c6a9)COLOR_CYANโ 12 โ Cyan (#7696de)COLOR_GRAYโ 13 โ Gray (#a3a3a3)COLOR_PINKโ 14 โ Pink (#ff9798)COLOR_PEACHโ 15 โ Peach (#edc7b0)
Resource Constants
NUM_COLORSโ 16 โ Number of palette colorsNUM_IMAGESโ 3 โ Number of image banks (0-2)IMAGE_SIZEโ 256 โ Image width and heightNUM_TILEMAPSโ 8 โ Number of tilemaps (0-7)TILEMAP_SIZEโ 256 โ Tilemap width and heightTILE_SIZEโ 8 โ Tile size in pixelsFONT_WIDTHโ 4 โ Built-in font widthFONT_HEIGHTโ 6 โ Built-in font height
Audio
`channels` โ variable *(Advanced)*
Audio channels (Channel instances) (0-3).
- Type:
list[Channel]
`tones` โ variable *(Advanced)*
Tone definitions (Tone instances) (0-3).
- Type:
list[Tone]
`sounds` โ variable
Sounds (Sound instances) (0-63).
- Type:
list[Sound]
Example:
pyxel.sounds[0].speed = 60`musics` โ variable
Music tracks (Music instances) (0-7).
- Type:
list[Music]
`play(ch, snd, sec=0, loop=False, resume=False)` โ function
Play the sound snd on channel ch (0-3). snd can be a sound number (0-63), a list of numbers, a Sound instance, a list of Sounds, or an MML string.
Parameters:
ch(int) โ Channel number (0-3)snd(int/list/Sound/str) โ Sound number (0-63), list of numbers, Sound instance, list of Sounds, or MML stringsec(float) โ Playback start position in seconds. Defaults to 0.loop(bool) โ Loop playback. Defaults to False.resume(bool) โ Resume previous sound after playback ends. Defaults to False.
`playm(msc, sec=0, loop=False)` โ function
Play the music msc (0-7).
Parameters:
msc(int) โ Music number (0-7)sec(float) โ Playback start position in seconds. Defaults to 0.loop(bool) โ Loop playback. Defaults to False.
`stop(ch)` โ function
Stop playback of the specified channel ch (0-3).
Parameters:
ch(int) โ Channel number (0-3)
`stop()` โ function
Stop playback of all channels.
`play_pos(ch)` โ function
Get the sound playback position of channel ch (0-3) as a tuple of (sound_index, sec). Return None when playback has stopped.
Parameters:
ch(int) โ Channel number (0-3)
Returns: tuple[int, float]/None โ (sound_index, sec) or None
`gen_bgm(preset, transp, instr, seed, play=False)` โ function
Generate a BGM MML list using an algorithm. preset (0-7) selects the preset, instr (0-3) selects the instrumentation.
Parameters:
preset(int) โ Preset number (0-7). 0-1: title, departure (medium tempo), 2-3: town, peaceful (slow tempo), 4-5: field, adventure (medium tempo), 6-7: battle, crisis (fast tempo)transp(int) โ Transpose in semitones (-5 to +5).instr(int) โ Instrumentation (0-3). 0: melody+reverb+bass (3ch), 1: melody+bass+drums (3ch), 2: melody+sub+bass (3ch), 3: melody+sub+bass+drums (4ch).seed(int) โ Random seedplay(bool) โ Play the generated MML. Defaults to False.
Returns: list[str] โ List of MML strings
Tone & Effect Constants
Tones:
TONE_TRIANGLEโ 0 โ Triangle waveTONE_SQUAREโ 1 โ Square waveTONE_PULSEโ 2 โ Pulse waveTONE_NOISEโ 3 โ Noise
Effects:
EFFECT_NONEโ 0 โ No effectEFFECT_SLIDEโ 1 โ SlideEFFECT_VIBRATOโ 2 โ VibratoEFFECT_FADEOUTโ 3 โ Fade outEFFECT_HALF_FADEOUTโ 4 โ Half fade outEFFECT_QUARTER_FADEOUTโ 5 โ Quarter fade out
Resource Constants
NUM_CHANNELSโ 4 โ Number of audio channels (0-3)NUM_TONESโ 4 โ Number of tone types (0-3)NUM_SOUNDSโ 64 โ Number of sounds (0-63)NUM_MUSICSโ 8 โ Number of music tracks (0-7)
Math
`ceil(x)` โ function
Return the smallest integer greater than or equal to x.
Parameters:
x(float) โ Value
Returns: int โ Smallest integer >= x
`floor(x)` โ function
Return the largest integer less than or equal to x.
Parameters:
x(float) โ Value
Returns: int โ Largest integer <= x
`clamp(x, lower, upper)` โ function
Return x clamped between lower and upper.
Parameters:
x(float) โ Value to clamplower(float) โ Minimum valueupper(float) โ Maximum value
Returns: float โ Clamped value
`sgn(x)` โ function
Return 1 when x is positive, 0 when it is 0, and -1 when it is negative.
Parameters:
x(int/float) โ Value
Returns: int/float โ Sign of the value (1, 0, or -1)
`sqrt(x)` โ function
Return the square root of x.
Parameters:
x(float) โ Value
Returns: float โ Square root of x
`sin(deg)` โ function
Return the sine of deg degrees.
Parameters:
deg(float) โ Angle in degrees
Returns: float โ Sine value
`cos(deg)` โ function
Return the cosine of deg degrees.
Parameters:
deg(float) โ Angle in degrees
Returns: float โ Cosine value
`atan2(y, x)` โ function
Return the arctangent of y/x in degrees.
Parameters:
y(float) โ Y valuex(float) โ X value
Returns: float โ Angle in degrees
`rseed(seed)` โ function
Set the seed of the random number generator.
Parameters:
seed(int) โ Seed value (non-negative integer)
`rndi(a, b)` โ function
Return a random integer from a to b (inclusive).
Parameters:
a(int) โ Minimum value (inclusive)b(int) โ Maximum value (inclusive)
Returns: int โ Random integer from a to b
`rndf(a, b)` โ function
Return a random float from a to b (inclusive).
Parameters:
a(float) โ Minimum value (inclusive)b(float) โ Maximum value (inclusive)
Returns: float โ Random float from a to b
`nseed(seed)` โ function
Set the seed of Perlin noise.
Parameters:
seed(int) โ Seed value (non-negative integer)
`noise(x, y=0, z=0)` โ function
Return the Perlin noise value for the specified coordinates.
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate. Defaults to 0.z(float) โ Z coordinate. Defaults to 0.
Returns: float โ Perlin noise value
Font Class
`Font(filename, font_size=10.0)` โ class *(Advanced)*
Create a Font instance from a font file (BDF/OTF/TTF/TTC).
Parameters:
filename(str) โ Font file name (BDF/OTF/TTF/TTC)font_size(float) โ Font size. Defaults to 10.0. Not used for BDF.
Returns: Font โ New Font instance
`Font.text_width(s)` โ function *(Advanced)*
Return the display width of the string s in this font.
Parameters:
s(str) โ String to measure
Returns: int โ Width in pixels
Image Class
`Image(width, height)` โ class *(Advanced)*
Create a new Image instance with the specified size.
Parameters:
width(int) โ Image widthheight(int) โ Image height
Returns: Image โ New Image instance
`Image.from_image(filename, include_colors=False)` โ class *(Advanced)*
Create an Image instance from an image file.
Parameters:
filename(str) โ Image file nameinclude_colors(bool) โ Include palette colors from file. Defaults to False.
Returns: Image โ Image instance from file
`Image.width` โ variable
The width of the image.
- Type:
int
`Image.height` โ variable
The height of the image.
- Type:
int
`Image.set(x, y, data)` โ function
Set the image at (x, y) using a list of hex-digit strings. Each character represents a color index (0-f).
Parameters:
x(int) โ X coordinatey(int) โ Y coordinatedata(list[str]) โ Image data as a list of strings
Example:
pyxel.images[0].set(10, 10, ["0123", "4567", "89ab", "cdef"])`Image.load(x, y, filename, include_colors=False)` โ function
Load an image file (PNG/GIF/JPEG) at (x, y).
Parameters:
x(int) โ X coordinatey(int) โ Y coordinatefilename(str) โ Image file name (PNG/GIF/JPEG)include_colors(bool) โ Include palette colors from file. Defaults to False.
`Image.pget(x, y)` โ function
Get the color of the pixel at (x, y). The coordinates are absolute and not affected by the camera offset.
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate
Returns: int โ Color of the pixel
`Image.pset(x, y, col)` โ function
Draw a pixel with the color col at (x, y).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatecol(int) โ Color
`Image.{cls, line, rect, rectb, circ, circb, elli, ellib, tri, trib, fill, blt, bltm, blt3d, bltm3d, text, clip, camera, pal, dither}` โ function
Image instances support all drawing functions from the Graphics section. They work the same way but draw on the image instead of the screen.
`Image.data_ptr()` โ function *(Advanced)*
Return the raw data pointer of the image as a ctypes c_uint8 array.
Returns: Any โ Raw data pointer
`Image.save(filename, scale)` โ function *(Advanced)*
Save the image to a file.
Parameters:
filename(str) โ Output file namescale(int) โ Scale factor
Tilemap Class
`Tilemap(width, height, img)` โ class *(Advanced)*
Create a new Tilemap instance.
Parameters:
width(int) โ Tilemap widthheight(int) โ Tilemap heightimg(int/Image) โ Image bank number (0-2) or Image instance
Returns: Tilemap โ New Tilemap instance
`Tilemap.from_tmx(filename, layer)` โ class *(Advanced)*
Create a Tilemap instance from a TMX file.
Parameters:
filename(str) โ TMX file namelayer(int) โ Layer number (0-)
Returns: Tilemap โ Tilemap instance from TMX file
`Tilemap.width` โ variable
The width of the tilemap.
- Type:
int
`Tilemap.height` โ variable
The height of the tilemap.
- Type:
int
`Tilemap.imgsrc` โ variable
The image bank (0-2) or Image instance referenced by the tilemap.
- Type:
int/Image
`Tilemap.set(x, y, data)` โ function
Set the tilemap at (x, y) using a list of strings. Each tile is a 4-digit hex value representing (image_tx, image_ty), separated by spaces.
Parameters:
x(int) โ X coordinatey(int) โ Y coordinatedata(list[str]) โ Tilemap data as a list of strings
Example:
pyxel.tilemaps[0].set(0, 0, ["0000 0100 a0b0", "0001 0101 a1b1"])`Tilemap.load(x, y, filename, layer)` โ function
Load the layer (0-) from the TMX file at (x, y).
Parameters:
x(int) โ X coordinatey(int) โ Y coordinatefilename(str) โ TMX file namelayer(int) โ Layer number (0-)
`Tilemap.pget(x, y)` โ function
Get the tile at (x, y). The coordinates are absolute and not affected by the camera offset. A tile is a tuple of (image_tx, image_ty).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinate
Returns: tuple[int, int] โ (image_tx, image_ty)
`Tilemap.pset(x, y, tile)` โ function
Set a tile at (x, y). A tile is a tuple of (image_tx, image_ty).
Parameters:
x(float) โ X coordinatey(float) โ Y coordinatetile(tuple[int, int]) โ Tile as (image_tx, image_ty)
`Tilemap.{cls, line, rect, rectb, circ, circb, elli, ellib, tri, trib, fill, blt, clip, camera}` โ function
Tilemap instances support drawing functions from the Graphics section. They work the same way but draw tiles on the tilemap instead of pixels on the screen. Use a tile tuple (image_tx, image_ty) instead of a color value.
`Tilemap.collide(x, y, w, h, dx, dy, walls)` โ function
Resolve collisions after applying pixel movement (dx, dy) to the pixel rectangle at (x, y) with pixel size (w, h), and return the adjusted (dx, dy). walls is a list of tile coordinates that act as obstacles.
Parameters:
x(float) โ Rectangle X positiony(float) โ Rectangle Y positionw(float) โ Rectangle widthh(float) โ Rectangle heightdx(float) โ Movement in Xdy(float) โ Movement in Ywalls(list[tuple[int, int]]) โ List of wall tiles (image_tx, image_ty)
Returns: tuple[float, float] โ Adjusted (dx, dy)
`Tilemap.data_ptr()` โ function *(Advanced)*
Return the raw data pointer of the tilemap as a ctypes c_uint16 array (4 bytes per tile: image_tx, image_ty).
Returns: Any โ Raw data pointer
Sound Class
`Sound()` โ class *(Advanced)*
Create a new Sound instance.
Returns: Sound โ New Sound instance
`Sound.notes` โ variable
List of notes (0-59). Higher values produce higher pitches. 33 = 'A2' (440 Hz). Rests are -1.
- Type:
list[int]
`Sound.tones` โ variable
List of tones (0: Triangle, 1: Square, 2: Pulse, 3: Noise).
- Type:
list[int]
`Sound.volumes` โ variable
List of volumes (0-7).
- Type:
list[int]
`Sound.effects` โ variable
List of effects (0: None, 1: Slide, 2: Vibrato, 3: FadeOut, 4: Half-FadeOut, 5: Quarter-FadeOut).
- Type:
list[int]
`Sound.speed` โ variable
Playback speed. 1 is the fastest, and the larger the number, the slower the playback speed. At 120, one note equals 1 second.
- Type:
int
`Sound.set(notes, tones, volumes, effects, speed)` โ function
Set notes, tones, volumes, and effects using strings. If the tones, volumes, or effects string is shorter than the notes, it repeats from the beginning.
Parameters:
notes(str) โ Note stringtones(str) โ Tone stringvolumes(str) โ Volume stringeffects(str) โ Effect stringspeed(int) โ Playback speed
`Sound.set_notes(notes)` โ function
Set the notes using a string made of note names (CDEFGAB), optional sharp (#) or flat (-), octave (0-4), and rests (R). Case-insensitive, whitespace is ignored.
Parameters:
notes(str) โ Notes string
Example:
pyxel.sounds[0].set_notes("g2b-2d3r rf3f3f3")`Sound.set_tones(tones)` โ function
Set the tones with a string of TSPN (or 0-9 for custom tone numbers). Case-insensitive, whitespace is ignored.
Parameters:
tones(str) โ Tones string
Example:
pyxel.sounds[0].set_tones("ttss pppn")`Sound.set_volumes(volumes)` โ function
Set the volumes with a string of 01234567. Whitespace is ignored.
Parameters:
volumes(str) โ Volumes string
Example:
pyxel.sounds[0].set_volumes("7777 7531")`Sound.set_effects(effects)` โ function
Set the effects with a string of NSVFHQ. Case-insensitive, whitespace is ignored.
Parameters:
effects(str) โ Effects string
Example:
pyxel.sounds[0].set_effects("nfnf nvvs")`Sound.mml(code)` โ function
Switch to MML mode with the given MML string. In MML mode, normal parameters such as notes and speed are ignored. For available MML commands, see the Pyxel MML Commands page.
Parameters:
code(str) โ MML string
Example:
pyxel.sounds[0].mml("T120 Q90 @1 V100 O5 L8 C4&C<G16R16>C.")`Sound.mml()` โ function
Exit MML mode and return to normal mode.
`Sound.pcm(filename)` โ function
Load an audio file (WAV/OGG) for playback.
Parameters:
filename(str) โ Audio file name (WAV/OGG)
Example:
pyxel.sounds[0].pcm("sounds/bgm.ogg")`Sound.pcm()` โ function
Exit PCM mode and return to normal mode.
`Sound.save(filename, sec, ffmpeg=False)` โ function *(Advanced)*
Create a WAV file from the sound with the specified duration in seconds.
Parameters:
filename(str) โ Output WAV file namesec(float) โ Duration in secondsffmpeg(bool) โ Also create MP4 file (requires FFmpeg). Defaults to False.
`Sound.total_sec()` โ function *(Advanced)*
Return the playback time in seconds. Return None for infinite loops.
Returns: float/None โ Playback time in seconds, or None for infinite loops
Music Class
`Music()` โ class *(Advanced)*
Create a new Music instance.
Returns: Music โ New Music instance
`Music.seqs` โ variable
A two-dimensional list of sounds (0-63) across multiple channels.
- Type:
list[list[int]]
`Music.set(seq0, seq1, seq2, ...)` โ function
Set the lists of sounds (0-63) for each channel. An empty list means the channel is not used.
Parameters:
seq0, seq1, ...(list[int]) โ Sound lists for each channel. Empty list = unused.
Example:
pyxel.musics[0].set([0, 1], [], [3])`Music.save(filename, sec, ffmpeg=False)` โ function *(Advanced)*
Create a WAV file from the music with the specified duration in seconds.
Parameters:
filename(str) โ Output WAV file namesec(float) โ Duration in secondsffmpeg(bool) โ Also create MP4 file (requires FFmpeg). Defaults to False.
Channel Class
`Channel()` โ class *(Advanced)*
Create a new Channel instance.
Returns: Channel โ New Channel instance
`Channel.gain` โ variable *(Advanced)*
The gain (volume) of the channel. Defaults to 0.125.
- Type:
float
`Channel.detune` โ variable *(Advanced)*
Pitch detune in cents (100 cents = 1 semitone). Defaults to 0.
- Type:
int
`Channel.play(snd, sec=0, loop=False, resume=False)` โ function *(Advanced)*
Play the sound snd on this channel. snd can be a sound number, a list, a Sound instance, a list of Sounds, or an MML string.
Parameters:
snd(int/list/Sound/str) โ Sound number (0-63), list of numbers, Sound instance, list of Sounds, or MML stringsec(float) โ Playback start position in seconds. Defaults to 0.loop(bool) โ Loop playback. Defaults to False.resume(bool) โ Resume previous sound after playback ends. Defaults to False.
`Channel.stop()` โ function *(Advanced)*
Stop playback on this channel.
`Channel.play_pos()` โ function *(Advanced)*
Get the playback position as a tuple of (sound_index, sec). Return None when playback has stopped.
Returns: tuple[int, float]/None โ (sound_index, sec) or None
Tone Class
`Tone()` โ class *(Advanced)*
Create a new Tone instance.
Returns: Tone โ New Tone instance
`Tone.mode` โ variable *(Advanced)*
Tone mode (0: Wavetable, 1: ShortPeriodNoise, 2: LongPeriodNoise).
- Type:
int
`Tone.sample_bits` โ variable *(Advanced)*
Sample bits for the wavetable (1-16). Defaults to 4.
- Type:
int
`Tone.wavetable` โ variable *(Advanced)*
Wavetable data as a list of sample values. Each value must be in range 0 to (2^sample_bits - 1).
- Type:
list[int]
`Tone.gain` โ variable *(Advanced)*
Tone gain. Defaults to 1.0.
- Type:
float
Coding Policy Audit (`docs/coding-policy-audit.md`)
Coding Policy Audit Procedure
This file defines how to run an exhaustive audit againstdocs/coding-policy.md. It does not define coding standards, add exceptions, or
weaken the policy. If this procedure and the policy disagree, the policy wins
and this procedure must be corrected before the audit is accepted.
An auditor reads both files in this order:
docs/coding-policy.md: the source of truth for standards, scope, and
examples.docs/coding-policy-audit.md: the execution protocol used to prove that the
policy was checked completely and evenly.
Operating Rules
No sampling. Every in-scope file, normative criterion, applicable subject,
cross-file relation, hot-path surface, and required verification gate is
represented by an artifact row.No cherry-picking. A local fix is incomplete until every comparable subject
and affected relation is checked to the same depth.No unstated memory. Previous conversations, old audit notes, prior summaries,
and repository prevalence may suggest probes, but they are not evidence until
rechecked against the frozen target and recorded in the current artifacts.No majority rule. Explicit policy determines departures from the relevant
language's established idiom; otherwise that idiom determines the correct
form. Existing repetition is used only to discover related subjects and uneven
application.No example criteria. An example illustrates its parent rule and is recorded
as example coverage; matching or differing from the example alone never
determines a verdict.No summary-only evidence. Counts, search results, formatter success, test
success, and reviewer summaries do not prove a check unless its row names what
was inspected and why the verdict follows.Use precise result labels. A run is an exhaustive audit only when the
Completion Gate is satisfied. Until then, or when the requested scope is
intentionally narrower, report the work as a targeted review, fix pass, gate
check, or pending audit according to the artifacts actually produced.The worktree under review is the audit target. Start from
git ls-files, add
intended untracked files, and apply the policy's Scope section to that combined
set.The frozen target is immutable within a run. If its files, intended additions,
policy, or procedure change, preserve the run and start another. Regenerate an
artifact when only one of its recorded in-run inputs changes; a stale row ispending, never reused as proof. The final report names every preserved run
that led to the completed one.
When to Run
Run this procedure:
- when an exhaustive coding-policy audit is explicitly requested;
- before a release tag, as part of the release checklist;
- after a substantive revision of
docs/coding-policy.md, on every subject
whose verdict may change because of the revision; - after a substantive revision of this procedure, on this procedure and every
affected audit artifact or subject.
Artifact Rules
Each run writes artifacts to one directory named in the final report. Every TSV
has a header, uses one row per declared unit, and has the declared column count
on every row. Text artifacts use UTF-8 without a BOM, LF line endings, and one
terminal LF. JSON objects use the declared key order and no insignificant
whitespace. TSV fields contain no literal tabs or newlines. Lists are compact
JSON arrays with no duplicate logical entries; an aligned value list retains one
value per key even when values are equal. Reference lists preserve the defining
artifact's row order, enum lists preserve this procedure's declaration order,
and other lists are sorted bytewise unless a recorded source command defines
their order.
Path values encode repository-relative Git path bytes: / and ASCII letters,
digits, ., _, and - remain literal; every other byte is %HH with uppercase
hex digits. Plural TSV fields are JSON arrays unless their schema says otherwise;policy_line is one policy source reference and policy_lines is an array of
them. Artifact rows are sorted bytewise by their identifier.
Every data row has the explicit identifier declared by its artifact. Except for
the separately defined file and artifact IDs, an ID is its column name without_id, followed by - and the lowercase SHA-256 of its natural-key JSON array.
That array uses the key values below in listed order, with no whitespace, only
required JSON escapes, and literal non-ASCII characters. Each
verdict-independent row ID is assigned before that row's verdict; finding and
review IDs are computed when those rows are created. IDs use the path-encoding
alphabet and never contain :.
Completeness of verdict-independent sets is validated from natural keys, never
from IDs or observed verdicts; post-verdict sets follow their declared
derivations. Natural keys are: policy source lines and normalized rule text for
criteria; policy line for policy coverage; artifact path for the manifest;path for target files and scope; kind and family for relations; family for hot
paths; cwd, command, and trigger for commands; criterion and subject for
applicability and checks; source and target references plus finding text for
findings; criterion and subject family for balance rows; and review kind and
subject key for independent-review rows.
Missing or duplicate identifiers or natural keys, unknown criteria or subjects,
invalid enum values, empty required fields, and column-count errors are artifact
failures.
An evidence reference is one of:
source::<line>orsource::<first>-<last>;source:for a whole-file check;row:<artifact>:<row_id>for a TSV row;artifact:<artifact>, optionally followed by:<line>or:<first>-<last>, for whole-artifact or raw-line evidence.
Source lines are one-based and ranges are inclusive. Paths use the encoding above;artifact is a required artifact filename. A deleted path is cited through its
hunk in current-diff.patch, not as current source.
Every reference resolves to exactly one current source location, artifact
location, or row. The evidence graph is acyclic and terminates in current source,
a frozen-target root artifact, or a successful target-bound command row. Broken,
cyclic, or unterminated evidence blocks completion.
manifest.tsv binds manifested artifacts to their exact inputs and the frozen
target. A manifested artifact is stale when its current hash, input hashes, ortarget_sha256 differs from the manifest. The independent review is stale when
its target or manifest hash differs; the summary is stale when any of its three
hashes differs. Immediately before completion, the target snapshot and diff are
independently re-derived from the live worktree; comparing stored artifacts with
one another is insufficient. No artifact hash, fingerprint, or verdict is an
input to its own computation. Identifiers only locate units derived from natural
keys; an observed identifier set never proves its own completeness.
Required Artifacts
target_files.tsv- Columns:
file_id,path,source,git_mode,content_sha256. - Contains every tracked path not deleted by the frozen diff, plus every
intended untracked file, whether the policy later includes or excludes it.
A missing sparse- or skip-worktree path blocks the freeze rather than being
treated as a deletion.sourceistrackedoruntracked_intended. file_idequals the encodedpath.git_modeis the six-digit mode the
frozen target tree would record.content_sha256hashes the working-tree
bytes, the link-target bytes for a symlink, or the hexadecimal bytes of the
recorded commit ID for a gitlink.
- Columns:
freeze.json- Contains exactly:
schema_version,branch,base_commit,head_commit,policy_sha256,procedure_sha256,target_files_sha256,diff_sha256,target_sha256, andartifact_dir. schema_versionis the integer1for this schema and increments whenever a
required artifact's fields or meaning change.branchis the short branch
name using the path-byte encoding above, or null; commits are full object
IDs; digests are lowercase SHA-256 strings; andartifact_diris the absolute
run-directory path.base_commitis the previous release commit for a release audit; otherwise
it is the explicitly requested comparison base, the merge base ofHEADand
its configured upstream when no base was requested, orHEADwhen no
upstream exists.target_sha256is the SHA-256 of a UTF-8 JSON array containing, in order,schema_version,branch,base_commit,head_commit,policy_sha256,procedure_sha256, andtarget_files_sha256. The serialization uses no
whitespace and only required JSON escapes.- The object records the target before any verdict is written.
- Contains exactly:
current-diff.patch- Contains the exact diff against
base_commit, including intended untracked
files as added-file patches, in Git's binary-capable full-index format.
The tracked diff comes first; added-file patches follow in encoded-path order. - Its SHA-256 equals
freeze.json.diff_sha256.
- Contains the exact diff against
manifest.tsv- Columns:
artifact_id,path,sha256,input_artifact_ids,input_sha256s,target_sha256. - Contains one row for every required artifact except itself,
independent_review.tsv, andaudit_summary.json. artifact_idis the artifact filename andpathis its path relative to the
run directory.- Input ID and hash arrays have equal length and preserve dependency order.
- The dependency graph is acyclic and contains these direct edges:
target_files.tsvandcurrent-diff.patchare roots;freeze.jsondepends on both roots;criteria.tsvandpolicy_coverage.tsvdepend onfreeze.json;scope.tsvdepends ontarget_files.tsv,criteria.tsv, andpolicy_coverage.tsv;relations.tsv,hot_paths.tsv, andcommands.tsvdepend oncriteria.tsvandscope.tsv, with change-driven inventories also
depending oncurrent-diff.patch;applicability.tsvdepends oncriteria.tsv,scope.tsv,relations.tsv,hot_paths.tsv, andcommands.tsv;checks.tsvdepends onapplicability.tsvandcommands.tsv;coverage_balance.tsvdepends oncriteria.tsv,applicability.tsv, andchecks.tsv;findings.tsvdepends onchecks.tsvandcoverage_balance.tsv.
- Each row also names every additional direct artifact input it actually uses.
- Columns:
criteria.tsv- Columns:
criterion_id,policy_lines,subject_types,surface_kinds,file_selector,rule_text. - Contains one row for each top-level rule bullet and each normative
introductory paragraph indocs/coding-policy.md. - Nested authoritative enumerations belong to their parent criterion.
e.g.bullets and hypothetical anti-patterns never create criteria. subject_typesis a non-empty JSON array drawn fromfile,relation,hot_path,process, andcommand.filegoverns a file surface;relationcompares files;hot_pathgoverns
a policy-listed performance family;processgoverns a repository-wide or
audit obligation with no narrower subject; andcommandrequires execution.
Every applicable type is listed.surface_kindsis a JSON array used only byfilecriteria and drawn
frompath,source,test,prose,translation,release_notes,policy,configuration, andstructured_data.
It is non-empty exactly whensubject_typescontainsfile.file_selectoris empty for a non-file criterion. Otherwise it states the
rule-derived predicate that selects governed content within the candidate
surface kinds. It isallonly where the rule governs every candidate file;
examples and hand-picked repository paths cannot define it.rule_textis the normative text with internal whitespace collapsed to one
ASCII space. Any text change changes the criterion ID; a semantic addition,
removal, split, or merge changes the criterion set.
- Columns:
policy_coverage.tsv- Columns:
coverage_id,policy_line,line_text,coverage_kind,criterion_ids,rationale. - Contains exactly one row for every non-blank policy line;
line_textis the
exact line content. coverage_kindiscriterion,example, orstructural.
Criterion and example rows name their parent criteria. Structural rows have
an emptycriterion_idsarray and explain why the line imposes no
requirement.
- Columns:
scope.tsv- Columns:
file_id,path,source,scope_status,surface_kinds,reason,policy_lines. - Contains exactly the files in
target_files.tsv, with the same file IDs,
paths, and sources. sourceistrackedoruntracked_intended;scope_statusisincludedorexcluded.- Every included file's
surface_kindscontainspathplus every applicable
kind. Excluded files have an empty surface list. Every row cites the governing
policy lines and explains its inclusion or exclusion. pathapplies to every included file;sourceto syntax, structure,
identifiers, comments, or other non-prose content;testto verification
code or data;proseto documentation, descriptive metadata, or user-facing
natural language other than code comments;translationto content with
language variants;release_notesto changelog entries;policyto these
two policy documents;configurationto configuration content; andstructured_datato machine-parsed non-code data. Kinds overlap and follow
content and role, not filename extension alone.
- Columns:
relations.tsv- Columns:
relation_id,relation_kind,family,member_file_ids,criterion_ids,policy_lines,rationale,derivation_refs. - Expands every cross-file concern before checking begins. A file may belong
to any number of relations. member_file_idscontains unique IDs from includedscope.tsvrows. It is
empty only for a policy-mandated family with no current member, proved byderivation_refs.relation_kindissibling,mirror,translation,exception, orchange_dependency.criterion_idscontains every relation criterion governing the family;policy_linescites those rules.- Required relations include applicable naming and error-message families,
API/binding/stub mirrors, translated content, policy exception groups,
release notes against code changes, and tests against changed behavior. - A change-dependency relation cites deleted or renamed inputs through the
frozen diff; its member IDs still name only current included files. - An exception relation cites the exact policy lines, convention, and reason.
Repository prevalence is not a rationale.
- Columns:
hot_paths.tsv- Columns:
hot_path_id,family,member_file_ids,entry_points,criterion_ids,cost_risks,derivation,derivation_refs. - Contains exactly one row for every policy-listed hot-path family and
aggregates every implementation surface in that row. criterion_idscontains every hot-path criterion governing the family.member_file_idscontains unique IDs from included scope rows and is empty
only in an absence row.cost_risksnames every concrete cost implied by the rule and inspected
implementation; it is not limited to examples or a fixed category list.entry_pointsandderivation_refscontain evidence references;derivationexplains how they establish completeness.- A family with no implementation surface has an explicit absence row with
repository-wide derivation evidence.
- Columns:
commands.tsv- Columns:
command_id,criterion_ids,cwd,command,trigger,target_sha256,exit_status,key_output. - Declares every required and targeted command before it runs.
cwdis.or an encoded repository-relative directory;commandrecords
the exact non-interactive invocation.criterion_idscontains every command criterion the invocation checks. It
may be empty only for a procedure-level validation command; such a command
remains subject to its trigger and the Completion Gate.exit_statusis a non-negative integer ornot_run; zero passes and any
other integer fails. Anot_runrow records the blocker and cannot clear a
command criterion.- A successful command is evidence only when its target digest matches
freeze.json.target_sha256.
- Columns:
applicability.tsv- Columns:
check_id,criterion_id,subject_ref,derivation_refs. - Contains the complete expected check set, derived before verdicts.
subject_refisfile:<file_id>,relation:<relation_id>,routing:<criterion_id>,hot_path:<hot_path_id>,process:<criterion_id>,command:<command_id>, orabsence:<criterion_id>:<subject_type>.- File candidates are the intersections of criterion and included-file surface
kinds. The selector produces the file checks from those candidates, and every
file criterion also produces one routing check whose derivation proves that
the selector was applied exhaustively. Relation, hot-path, and command checks
come from the correspondingcriterion_ids; each process criterion produces
one process check. - Each declared non-file subject type with no concrete subject produces one
absence check. Its derivation proves the absence; it passes only when absence
satisfies the rule. A criterion missing any required applicability row, or a
row not produced by these rules, is an artifact failure.
- Columns:
checks.tsv- Columns:
check_id,criterion_id,subject_ref,verdict,evidence,evidence_refs. - Contains exactly one row for every
applicability.tsvrow, with the same
ID, criterion, and subject. - A local check does not replace a relation or hot-path check, and one
subject's pass does not override another subject's non-pass. - A routing check proves selection completeness only; it never proves that a
selected file satisfies the criterion.
- Columns:
findings.tsv- Columns:
finding_id,source_ref,severity,target_ref,criterion_ids,finding,proposed_fix. - Contains one or more rows for every current
fixverdict inchecks.tsvorcoverage_balance.tsv, one row per distinct target defect, and no rows from
any other verdict. source_refnames the originating fix row;target_refnames the defective
source or artifact; andcriterion_idsincludes the source criterion and any
other directly violated criterion.severityisblocker,high,medium, orlow; severity never
changes whether a policy finding must be resolved.
- Columns:
coverage_balance.tsv- Columns:
balance_id,criterion_id,subject_family,check_ids,comparator_balance_ids,verdict,rationale,evidence_refs. - Contains one row for every criterion and subject family represented in
applicability.tsv. Subject families arefile:<surface_kind>,routing,relation:<relation_kind>,hot_path:<family>,process, andcommand, plusabsence:<subject_type>. verdictispass,fix,review, orpending.- Comparators are other families for the same criterion and structurally
analogous criterion-family rows. The comparator list is empty only when no
such row exists and the rationale proves why. - Fix counts need not match. A zero-fix family passes only when its
checks and evidence show depth comparable to its named comparator rows.
- Columns:
independent_review.tsv- Columns:
review_id,reviewer,review_kind,subject_key,source_ref,target_sha256,manifest_sha256,verdict,evidence_refs. review_kindisexpected_key,check,balance, orartifact;subject_keyis a compact JSON array beginning with the artifact filename,
followed by that unit's natural-key values. The whole-manifest key is["manifest.tsv"]; each manifest-row key adds its artifact path.- Contains one row for every independently expected natural key in target
files, policy extraction, scope, subject inventories, and applicability; one
row for every check and balance row; and artifact rows for the manifest as a
whole and for every manifest row. source_refresolves to the corresponding current row or artifact. It is
empty only when an expected unit is missing, which requires a non-pass
verdict.- Every row names the independent reviewer and the reviewed target and manifest
hashes.verdictispass,fix, orpending.
- Columns:
audit_summary.json- Contains exactly:
schema_version,target_sha256,manifest_sha256,review_sha256,expected_checks,actual_checks,verdict_counts,finding_counts,command_counts,balance_counts,review_counts,validation_errors,stale_artifacts, andcompletion_status. schema_versionandtarget_sha256equal the freeze;manifest_sha256andreview_sha256are the lowercase SHA-256 hashes of the current files.verdict_countshas exactlypass,fix,review, andpending;finding_countshasblocker,high,medium, andlow;command_countshaspassed,failed, andnot_run;balance_countshaspass,fix,review, andpending;
andreview_countshaspass,fix, andpending.validation_errorshas exactlyschema,identifier,enum,reference,expected_key,dependency,evidence_cycle, andevidence_termination.expected_checks,actual_checks, every count member, and every validation
member are non-negative integers.stale_artifactsis an array of artifact
IDs.completion_statusiscompleteorpendingand is derived from the
source artifacts; it never overrides them.
- Contains exactly:
Verdicts and Evidence
Every checks.tsv.verdict is one of:
pass: the governed check obligation is satisfied, with substantive current
evidence;fix: the governed policy or procedure obligation is violated;review: semantic judgment is required;pending: required evidence, execution, or review is incomplete.
Coverage-balance verdicts use the same four meanings for their audit obligation.
Do not use not applicable. Applicability is decided before verdicts, and only
applicable criterion/subject pairs enter applicability.tsv.
Evidence is substantive only when it:
- names the exact subject and surface inspected;
- explains why the verdict follows from the rule rather than an example;
- records measured or mechanical support where the rule requires it;
- names peers or dependencies for relation verdicts;
- avoids bare phrases such as "no issue", "checked", or "matches policy".
Search output, inventories, formatter success, test success, finding counts, and
reviewer summaries are probes or command evidence, not findings by themselves. A
finding identifies the current source or artifact row, criterion, actionable
defect, and relevant peer or dependency evidence.
Phases
Run phases in order. Missing expected rows, invalid references, stale artifacts,
or schema errors block the current phase. Non-pass verdicts proceed through
balance and internal resolution, but block independent review and final
validation until resolved.
Freeze the target.
- Record every target file's mode and content digest, the branch, base and
head commits, policy and procedure digests, artifact directory, and exact
diff. - Write
target_files.tsv,freeze.json, andcurrent-diff.patchbefore
verdicts.
- Record every target file's mode and content digest, the branch, base and
Extract the policy.
- Build
criteria.tsvfrom normative units only. - Build
policy_coverage.tsv, classifying every non-blank line as criterion,
example, or structural.
- Build
Build scope.
- Classify every target snapshot row.
- Apply policy exclusions and assign all applicable surface kinds.
Build subject inventories.
- Expand all cross-file relations.
- Enumerate every hot-path surface.
- Declare required and targeted commands.
Derive applicability.
- Generate
applicability.tsvfrom criteria and subject inventories. - Validate the complete expected check set before writing verdicts.
- Generate
Perform checks and run commands.
- Inspect every applicable subject and write one
checks.tsvrow per
expected check. - Inspect source directly; searches and automation remain probes.
- Execute every triggered command and record its target-bound result.
- Run
make formatafter code or formatter-managed document changes. - Run
make lintandmake lint-wasmin every exhaustive run. - Run
make testafter code changes. - Run targeted parsers and validators for changed structured files, applicable
prose or documentation tests, andgit diff --check. - If a command changes the frozen target, preserve the run and start another.
- Inspect every applicable subject and write one
Check audit balance.
- Compare each criterion-family row with every comparator it names.
- Re-run the same probes on an unexplained zero-fix family and keep the
balance rowpendinguntil the difference is justified.
Resolve reviews and record findings.
- Resolve every
reviewaspassorfixfrom current evidence, without
inventing exceptions. Keep missing evidence or blocked executionpending. - Generate
findings.tsvfrom the resultingfixrows. - Correct an audit-evidence defect in place and regenerate every dependent
artifact. To correct the frozen target, preserve the current pending run and
start a new run against the changed target. - Repeat the affected phases until every check and balance row is
passandfindings.tsvis empty.
- Resolve every
Run independent review.
- A reviewer who produced none of the audited artifacts independently derives
policy, inventory, and applicability natural keys from the frozen source
before opening the run's verdicts or findings. - Give that reviewer both documents, the frozen target, complete inventories,
applicability, checks, findings, balance evidence, and manifest for
comparison and source review. Record every required review row inindependent_review.tsv. - The reviewer validates every expected key, verdict, and evidence chain;
review sampling cannot clear this gate. - Every actionable review result is
fixregardless of severity. Propagate
source defects to checks and findings, and artifact defects to validation
errors. - Correct audit evidence in place; for a target correction, preserve the run
and start another. Repeat review after either change. - If independent review is unavailable, completion remains
pending.
- A reviewer who produced none of the audited artifacts independently derives
Validate completion.
- Validate every schema, enum, identifier, natural key, reference, dependency,
evidence chain, count, and manifest hash from its source artifact. - Re-derive the target file snapshot and diff from the live worktree and
require exact equality with the freeze. - Require the independent-review set to be exact, every review verdict to be
pass, and every row to name the current target and manifest hashes. - Write
audit_summary.jsononly after the independent review is clean.
- Validate every schema, enum, identifier, natural key, reference, dependency,
Delegation Rules
When an audit is split, the lead auditor gives each auditor both documents, the
frozen target, complete subject inventories, exact assigned check IDs, and all
dependencies needed by those checks.
Delegated summaries are not evidence. The lead reads every returned row,
validates its references, rejects copied or shallow evidence, and resolves
conflicting verdicts by re-reading the subjects.
Completion Gate
The audit is complete only when:
- the live target snapshot and diff exactly match the freeze;
- every required artifact exists, every manifested artifact matches its schema
and manifest inputs, and every artifact is bound to the frozen target; - policy coverage, scope, subject inventories, and applicability contain exactly
their independently derived expected natural keys; checks.tsvcontains exactly the applicability set and every verdict ispass;- every
coverage_balance.tsvverdict ispass; findings.tsvis empty;independent_review.tsvcontains exactly its independently derived expected
natural keys, every verdict ispass, and its target and manifest hashes are
current;- every evidence reference resolves, the evidence graph is acyclic, and every
chain terminates in current source, a frozen-target root artifact, or successful
target-bound command evidence; - every triggered command succeeded against the frozen target;
audit_summary.jsonmatches the current target, manifest, and review hashes,
reports matching check counts, zero validation errors, zero stale artifacts, andcompletion_status: complete.
Do not claim completion before every condition is proved. If any condition is
uncertain, the verdict is pending.
Coding Policy (`docs/coding-policy.md`)
Pyxel Coding Policy
Principles
- Determinism. A rule produces the same verdict on the same frozen input regardless of who applies it or when. Taste alone never determines a verdict.
- Self-applicability. Every rule applies to every in-scope surface it governs (see Verification > Scope), including the corresponding parts of this document.
- Performance first. Subject to correctness, demonstrated hot-path cost overrides language conventions and idiomatic style.
- Cross-file consistency. Explicit policy determines required departures from language idiom; otherwise language idiom determines the correct form, which comparable sites use uniformly.
- Read naturally. Code reads concisely to a fluent reader of its language; the language's idioms are preferred over invented forms.
Standards
Source Code
Performance
Code on the hot paths eliminates avoidable cost. The hot paths are:
- per-pixel blit and primitive draws (line, circle, rect);
- per-pixel 3D rasterization (triangle fill and shading);
- per-sample voice synthesis;
- per-frame voice update for MML and BGM;
- per-frame 3D collision and BVH queries;
- the PyO3 FFI boundary (argument marshaling and return paths);
- SIMD or multi-threaded sections.
On hot paths, idiomatic patterns with a measured or mechanically demonstrated avoidable cost are not used.
- e.g., per-frame heap allocations (
Vec::new,format!,Box::newin inner loops); avoidable copies or type conversions; bounds checks in tight loops; missed SIMD, loop-unrolling, or inlining opportunities.
- e.g., per-frame heap allocations (
Outside hot paths, code stays idiomatic and readable. Micro-optimization is reserved for the listed hot paths.
- e.g.,
for x in xs { f(x) }in a config loader is preferred over a hand-unrolled alternative.
- e.g.,
Naming
Mechanical naming rules (the language's standard case conventions and lint-enforced patterns) apply first.
File and directory names use a policy-compliant, language-idiomatic base-name, separator, and role-suffix pattern uniformly within their sibling group. Public URLs, generated paths, and author-titled assets keep their established spelling unless every mirrored reference is renamed together.
- e.g.,
*_wrapper.rsfiles keep the wrapper suffix,web/*/index.htmlkeeps the route directory as the page identity, andlaser-jetman.htmlkeeps its author-chosen hyphenation.
- e.g.,
A symbol referenced from more than one file uses the same base name at every site (function and type names, CSS classes, HTML IDs, i18n keys, public API entries). Suffixed variants of the base name are allowed when each variant is exposed as a separate public entry. When mirrors disagree, the authoritative public surface wins; between a binding and the
.pyi, the.pyiwins. If no authoritative surface exists, the language-idiomatic name is chosen and every mirrored reference is updated together.- e.g., a
pyxel-corefunctiongen_bgmkeeps the same base name incrates/pyxel-binding/src/*_wrapper.rsandpython/pyxel/__init__.pyi; if it is split for separate exposure, the split uses suffixes (gen_bgm_mml,gen_bgm_json) rather than a renaming.
- e.g., a
A name is rewritten when it gives one concept a different base from its peers, breaks a symmetric verb family, repeats its owner or type without distinguishing meaning, or names an obsolete concept.
- e.g.,
titleBlockandtitleDivfor the same UI concept โ anti-pattern;Canvas.drawCanvas()โ anti-pattern (stutter).
- e.g.,
A language's idiomatic abbreviations are kept as-is.
- e.g., Python and Rust use
ifor a loop counter andefor an exception variable; JavaScript usesefor an event andelfor a DOM element.
- e.g., Python and Rust use
A locally reasonable name with no peer to harmonize with is left as-is. The rename rule above applies when peers exist; with no peer, taste alone is not grounds for renaming.
- e.g., a self-contained file using
titleDivstays as it is when no comparable sibling exists; the same name in a file with sibling files usingtitleBlockis renamed to match.
- e.g., a self-contained file using
Ordering
Definitions are ordered top-down: high-level structures and public types come before the free functions that consume them.
- e.g., a Rust file places
pub struct Foo { ... }and its impls before any free function consumingFoo.
- e.g., a Rust file places
Where the language requires forward declarations, they precede their use, overriding top-down ordering at the local level.
Configuration files follow each format's idiomatic grouping; within each group, entries are sorted alphabetically unless the format itself prescribes another order.
- e.g.,
Cargo.tomlkeeps dependencies, build dependencies, features, and release profiles in their conventional tables and sorts entries within each table.
- e.g.,
Comments
Every comment is in English.
A comment exists only when it adds intent that neither the code nor an existing comment shows; a shared rationale lives once, at the site that owns the decision, unless another rule requires the repetition. Required cases are mechanical or non-obvious operations (bit-twiddling, format-specific encoding) and non-local invariants.
- e.g.,
i += 1 # increment iโ anti-pattern;i += 1 # wrap at frame boundaryโ typical; the same workaround explained at its deciding and dependent sites โ anti-pattern.
- e.g.,
A comment is as short as its intent allows; comments expressing equally complex intent use comparable granularity.
- e.g., a five-line header on a short helper where sibling files use one-line headers โ anti-pattern (surplus wording); a widget's
# Variables:and# Events:blocks matching the convention across widget files โ typical.
- e.g., a five-line header on a short helper where sibling files use one-line headers โ anti-pattern (surplus wording); a widget's
A one-line separator comment identifies a meaningful group only when the language's structure does not make the group equally clear; no size threshold alone requires one. It uses the language's idiomatic single-line comment form, in sentence case, without decorative dashes or banners.
- e.g., Python
# Event handlers, Rust// Constructors, JavaScript// HTML helpers.
- e.g., Python
A label-style comment does not end with a period; a comment of two or more sentences punctuates every sentence, including the last. A single-sentence comment's terminal period is optional; either form is left as-is.
- e.g.,
// Constructors(label);// Playback has endedand// Playback has ended.โ both typical single-sentence forms.
- e.g.,
No documentation comments (Rust
//////!, Python docstrings, JSDoc/** */) anywhere exceptpython/pyxel/__init__.pyi. The.pyidocstrings are regenerated byscripts/generate_pyi_docstringsand are not hand-edited.Every comment is understandable at its site without historical or external context. No self-referential gloss, no tautological phrasing.
- e.g.,
the Pyxel API (the API of Pyxel)โ anti-pattern (gloss restates the term);// explanations to aid understandingโ anti-pattern (tautology).
- e.g.,
Formatting
Surface formatting (indentation, line wrapping, quoting) is delegated to
make formatfor the file types it covers; hand-written.mdis formatted by hand; every other file follows the standard conventions of its language or data format without unrelated reformatting.- e.g., a Rust match arm is not hand-aligned; a
Cargo.tomltable is not hand-reformatted.
- e.g., a Rust match arm is not hand-aligned; a
Exactly one blank line separates meaningful chunks unless
make formatprescribes otherwise. Runs of blank lines and blank lines inside a chunk are not used.- e.g., one blank line between class methods; no double blank between imports; no blank line between a function signature and its first statement.
Consistency
Each file participates in every structurally comparable sibling group identified by a common directory, naming pattern, or shared role. Consistency is judged within each group; codebase-wide prevalence does not determine correctness.
- e.g., sibling groups include
crates/pyxel-binding/src/*_wrapper.rs;python/pyxel/editor/widgets/*.py;python/pyxel/editor/*_editor.py; HTML pages underweb/*/index.html; language JSON files underweb/**/*.json.
- e.g., sibling groups include
A sibling group is an exception group only where this policy names the group, the convention it departs from, and the reason. The exception applies only to that convention; every other rule remains in force.
- The exception groups are:
crates/pyxel-binding/src/*_wrapper.rs: mirrors the Python API rather than following Rust conventions (snake_case names, Python-style argument ordering, and Pyxel-historical short names likeblt/cls/psetrather than the Rust-idiomatic counterparts inpyxel-core) and adopts the PyO3 binding conventions (#[new]for__init__,#[getter]/#[setter]for Python attributes);- SDL2 call sites: preserve the external SDL2 API's C-style names so calls remain recognizable against its documentation;
- samples in
python/pyxel/examples/: direct control flow and example-local names may stay when production-style decomposition or abstraction would make the sample harder to follow.
- The exception groups are:
Parallel mirrors โ shapes deliberately repeated across sibling files for API symmetry or data-structure parallelism โ preserve their shared structure. A correction is applied to every affected mirror rather than preserving a shared defect.
- e.g., binding wrappers mirror the Python API one-to-one; image and tilemap drawing primitives mirror each other; each i18n JSON file repeats the
languagesarray.
- e.g., binding wrappers mirror the Python API one-to-one; image and tilemap drawing primitives mirror each other; each i18n JSON file repeats the
Error and warning messages form codebase-wide families by failure kind rather than per-file groups: a message that mirrors a standard Python error keeps CPython's exact wording, a parameter constraint starts with the parameter as written, and any other message reuses its family's policy-compliant, language-idiomatic shape and casing rather than introducing a new form.
- e.g.,
fps must be greater than 0andscale must be greater than 0โ typical (one constraint family across files); a lonedraw: <message>prefix among sentence-style siblings โ anti-pattern.
- e.g.,
The
.pyiAPI stub records each parameter's effective default โ the value the implementation resolves to โ while its binding may takeNoneas a sentinel and resolve it internally. The.pyidefault and the binding-signature default may therefore differ; that divergence is intentional, not an inconsistency.- e.g., the
.pyiwritesinit(title="Pyxel", fps=30, ...)while the binding takesOptionsentinels and resolves them;Nonestays in the.pyionly whereNoneis itself the default behavior (display_scaleauto,colkey/fontnone).
- e.g., the
Testing
Tests cover the product in four layers: Rust unit tests for platform-independent pure logic; Python API tests for the public interface surface; reference regression of screenshots from the bundled examples, apps, and editor plus rendered audio; and a manual pass on running samples for look, sound, and feel. Test code itself is in scope for every Source Code rule.
A behavior is unit-tested when its breakage would not surface in the reference regression or the manual pass. These cases qualify:
- numeric boundaries and degenerate inputs (zero, empty, maximum, negative);
- rarely-taken branches (special syntax, edge inputs);
- determinism contracts whose silent change alters existing users' assets;
- compatibility surfaces (deprecated aliases keep working and warn);
- save/load and serialization roundtrips;
- error paths (exception type and message).
- e.g., the BGM generator's seed-determinism snapshot โ typical (a silent change rewrites existing users' music).
A behavior already exercised by the reference regression and the manual pass, whose breakage is plainly visible or audible there, is not duplicated by an internal unit test.
- e.g., a music mixing change is caught by the committed audio renders and the manual pass โ typical; a unit test re-asserting the same waveform sample-by-sample โ anti-pattern (duplicates the reference regression).
A test verifies what its name and comments claim; a test that cannot fail for the claimed reason is fixed or removed.
- e.g., a wraparound test whose inputs never wrap โ anti-pattern.
A deterministic outcome is pinned exactly. An assertion accepting several outcomes is reserved for genuine nondeterminism, with the source named in a comment.
- e.g.,
play_pos()may beNoneright afterplay()(audio-thread timing) โ typical; "level is 0.0 or 1.0" for a deterministic envelope โ anti-pattern.
- e.g.,
Every automated test executes in
make test.
Documentation
Prose
Documentation prose reads as natural technical writing in its own language, using the target language's standard conventions for compound-noun chains rather than literal translation from another language.
- e.g., English "package installation guide" โ typical; "installation of the package guide" โ anti-pattern (translationese).
Japanese text separates Japanese characters from adjacent alphanumeric tokens with a single half-width space, regardless of which file the text lives in; code spans keep their literal spacing.
- e.g., ใWeb ็ Pyxelใใ16 ่ฒใใ.pyxres ใใกใคใซใ โ typical; ใWeb็ใใ16่ฒใ โ anti-pattern (missing separation).
Japanese technical loanwords follow the project's adopted spelling rather than a mechanical English-suffix rule. Unlisted terms follow established usage in comparable developer documentation, then stay consistent across sibling documentation.
- Adopted spellings: ใใใฉใฆใถใใใจใใฃใฟใใใใฉใกใผใฟใใใใใใกใใใณใณในใใฉใฏใฟใใใฆใผใถใผใใใตใผใใผใใใณใณใใฅใผใฟใ.
- e.g., ใใใฉใฆใถไธใงๅฎ่กใ โ typical; mixing ใใใฉใฆใถใ and ใใใฉใฆใถใผใ for one concept in sibling pages โ anti-pattern.
Japanese text chooses parenthesis width by content: parentheses containing Japanese characters are full-width and sit flush; parentheses with ASCII-only content are half-width, separated by half-width spaces except when adjacent to punctuation.
- e.g., ใใคใกใผใธใใณใฏ๏ผImage ใฏใฉในใฎใคใณในใฟใณใน๏ผใฎใชในใ (0-2)ใ โ typical; ใใชในใ๏ผ0-2๏ผใ โ anti-pattern (full-width around ASCII-only content).
Translation
The maintainer writes in Japanese; Japanese is the source of truth for translation. Translations route through English first, then to every other language.
Each target language follows its own technical-writing conventions and retains established English loanwords where the target language conventionally uses them.
- e.g., German, Spanish, Italian, and Portuguese keep loanwords like "Editor" and "Gamepad" in English; French instead uses native forms such as "รฉditeur" and "manette", keeping only product names like "Pyxel Editor" in English.
A target-language translation is compared against the English version, not the Japanese source.
- e.g., a German
"Installation des Pakets Anleitung"mirrors a Japanese compound-noun chain and is rewritten as"Paket-Installationsanleitung".
- e.g., a German
Proper Nouns
The authoritative Pyxel product names are: Pyxel, Pyxel Cube, Pyxel Editor, Pyxel Showcase, Pyxel Code Maker, Pyxel MML Studio, Pyxel Web Launcher, Pyxel User Examples, and Pyxel Composer. The abbreviations Pyxel Web (the web version), Pyxel MML (the MML variant), and Pyxel API (the public API) may stand in for their full forms.
Listed product names are not translated and their casing is not altered.
- e.g.,
Pyxel Editorin every language โ neverpyxel editor,Pyxel-Editor, orใใฏใปใซใจใใฃใฟ.
- e.g.,
Every other proper noun retains the author's chosen representation, including hyphens, spacing, and casing.
- e.g.,
laser-jetman.htmlkeeps its hyphen; author-titled examples are not renamed to fit aPyxel-prefixed pattern.
- e.g.,
A descriptive label may stand in for a product name when the surrounding context establishes the reference and the label reads naturally there. Outside such contexts, the product name follows the casing rule above.
- e.g., a "Related Sites" section that introduces Pyxel Showcase as "the Pyxel community showcase" reads naturally; references to the same product elsewhere still write
Pyxel Showcase.
- e.g., a "Related Sites" section that introduces Pyxel Showcase as "the Pyxel community showcase" reads naturally; references to the same product elsewhere still write
Release Notes
A
CHANGELOG.mdentry exists when the change carries (a) a concrete user benefit, or (b) a debugger breadcrumb a future maintainer can follow. Changes that match neither are not recorded.- User benefits include: feature addition, bug fix, visible behavior change, performance improvement.
- Breadcrumbs include: dependency update; shipped runtime update; build-toolchain update that affects release artifacts; build-configuration change that alters compilation; feature flag addition; internal runtime change; scoped refactor or cleanup; public API rename; release-process change.
A breadcrumb names a concrete investigation surface; test-only, policy-only, and ignore-file changes are omitted unless they also change product, build, or release behavior.
- e.g.,
Updated pyo3 crate to version 0.29remains useful,Updated dependenciesis too broad, and adding tests or.gitignoreentries is not a breadcrumb by itself.
- e.g.,
Sub-changes within a single commit are evaluated separately under the rule above.
- e.g., a commit that fixes a bug and renames a public type produces two entries; a sub-change that is neither a user benefit nor a breadcrumb is omitted.
Entries describe the change relative to the previous release. A change to code that has not shipped folds into the entry that introduces that code and does not produce its own entry.
- e.g., a fix to a feature added earlier in the same unreleased version is absorbed by that feature's
Addedentry rather than gaining aFixedentry.
- e.g., a fix to a feature added earlier in the same unreleased version is absorbed by that feature's
Each entry uses a language-idiomatic verb, grammar form, and level of object specificity. It matches compliant prior entries of the same change category for consistency; prevalence does not determine the form.
Each entry fits a single line of at most 80 characters; entries typically run around 60 characters. An overlong entry is shortened without losing specificity and is split only when it contains independent sub-changes.
- e.g.,
Fixed Pyxel Editor color picker cursor shape across palette sizes(65 chars) fits the typical band; independent user-visible changes become separate entries, while an atomic change is tightened into one line.
- e.g.,
Each entry is verified against the actual code diff, not the commit message. Commit messages may understate or misstate the diff.
Documentation wording and translation touch-ups bundle into a single summary line.
- e.g.,
Update web titles and docs wordingcovers a commit touching many doc strings.
- e.g.,
Verification
Scope
This policy applies to every file present in the audit target that is git-tracked or an intended addition and that
.gitattributesdoes not mark asbinary, including this file.Files excluded because they are toolchain output:
*.tmx(Tiled tilemap editor output)*.bdf(font tooling output)Cargo.lockand*-lock.json(package-manager lockfiles)web/styles.css(a Tailwind CSS build artifact).mdfiles whose first line begins with<!-- This file is generated(output ofscripts/generate_docs)
A file's code-side aspects (structure, syntax, identifiers, non-prose elements) remain in scope even when its prose content is reviewed separately.
Format, Lint, and Test
After a code change,
make formatruns before the commit.make lint(native build) andmake lint-wasm(WebAssembly build) are warning-free at all times. The two builds use different feature sets and target environments; both pass.- Clippy warnings count as failures. Suppression with
#[allow(...)]requires that the suppression itself be justified.
- Clippy warnings count as failures. Suppression with
After a code change,
make testpasses before completion is claimed. A flaky failure does not waive the rule; the failure is reproduced and the underlying cause fixed.
Conventions of This File
A new concern joins an existing section before a new section is added. A new section is warranted only when no existing section fits.
- e.g., a wording guideline for CHANGELOG entries belongs under
Standards > Release Notes, not as a top-level section.
- e.g., a wording guideline for CHANGELOG entries belongs under
Individual past incidents are not recorded. An enduring lesson tightens the nearest existing rule; an example changes only when it clarifies a reusable boundary, replacing or rebalancing existing examples rather than accumulating another case.
- e.g., a one-off false-positive finding belongs in a commit message or the contributor's working notes, not as a named bullet here.
A section with an authoritative enumeration separates the list from the rules. The list appears either in the introductory prose, followed by rule bullets, or as sub-bullets or numbered items under the rule that needs the detail.
- e.g.,
Standards > Documentation > Proper Nounslists product names and abbreviations in its intro and uses bullets for casing rules;Standards > Source Code > Performanceenumerates hot paths as sub-bullets under the rule that introduces them.
- e.g.,
Each rule may be followed by at most one compact
e.g.,sub-bullet containing only the examples needed to clarify a reusable boundary.- Hypothetical anti-patterns read clearly as anti-patterns and are not asserted to exist in the code.
- An
e.g.line illustrates its rule and never substitutes for it; matching the example alone does not satisfy the rule. - A language-specific rule names the language in its rule statement.
After revising any section, the whole file is re-read and its balance is confirmed. Adding or splitting a rule or authoritative enumeration triggers a review of structurally comparable peers for parallel gaps; a change confined to wording or examples does not. Proportionality is checked by section length and bullet count.
Editor Manual (`docs/editor-manual.md`)
Pyxel Editor Manual
This document was auto-generated from the Pyxel Editor Manual web page, which also offers multilingual support.
Overview
Pyxel Editor is a built-in resource editing tool for Pyxel. It consists of four editors, which can be switched using the editor buttons at the top of the screen.
- Image Editor: Edit images (image banks) used for sprites and tiles
- Tilemap Editor: Arrange image bank images as tiles to compose maps
- Sound Editor: Edit sounds used for sound effects and melodies
- Music Editor: Arrange sounds in playback order to compose music such as BGM
Getting Started
Launch Pyxel Editor with the following command:
pyxel edit [PYXEL_RESOURCE_FILE]
If the specified Pyxel resource file (.pyxres) exists, it will be loaded. If it does not exist, a new file with the specified name will be created. If the filename is omitted, my_resource.pyxres will be created.
Common Operations
Operations common to all editors.
Menu Bar
The menu bar at the top of the screen contains four editor switching buttons, Undo/Redo buttons, and a Save button. The help message area on the right displays context-sensitive information based on the cursor position.
- Switch to Image Editor
- Switch to Tilemap Editor
- Switch to Sound Editor
- Switch to Music Editor
- Ctrl(Cmd)+Z โ Undo
- Ctrl(Cmd)+Y โ Redo
- Ctrl(Cmd)+S โ Save
Other Shortcuts
| Shortcut | Action |
|---|---|
| Alt(Option)+Left/Right | Switch between editor types |
| Shift+Ctrl(Cmd)+C | Copy the entire editing target |
| Shift+Ctrl(Cmd)+X | Cut the entire editing target (copy and clear) |
| Shift+Ctrl(Cmd)+V | Paste the copied target |
| Shift+Click ([+]/[-] buttons) | Change number or value in increments of ยฑ10 |
Using from Programs
The created resource file can be loaded and used in a Pyxel application with the pyxel.load() function.
Switching Resource Files
While the editor is running, you can drag and drop another .pyxres file onto the window to load its contents. This operation overwrites all current edits, so be careful if you have unsaved changes.
Image Editor
A mode for editing images in each image bank. You can create pixel art for sprites and tiles.
Specifications
- Image Banks: 0โ2 (3 banks)
- Size: 256ร256 pixels each
- Coordinate System: Origin (0,0) at top-left, X+ rightward, Y+ downward
Screen Layout
Image Canvas
The editing area selected in the image bank view is displayed magnified. Click and drag with the mouse to draw.
| Shortcut | Action |
|---|---|
| Right Click | Pick the color at the cursor position (color pick) |
| Right Drag | Pan the view |
Image Bank View
A thumbnail view of the entire image bank. The white frame indicates the current editing area.
| Shortcut | Action |
|---|---|
| Arrow Keys | Move the editing area (white frame) |
| Click | Move the editing area to the clicked position |
| Right Drag | Pan the view |
Tool Buttons
Select a tool for drawing.
- S โ Select a rectangular area
- P โ Draw freehand. Hold Shift for straight lines
- R โ Draw a rectangle outline. Hold Shift for a square
- Shift+R โ Draw a filled rectangle. Hold Shift for a square
- C โ Draw an ellipse outline. Hold Shift for a circle
- Shift+C โ Draw a filled ellipse. Hold Shift for a circle
- B โ Fill a connected region of the same color
Selection Tool Shortcuts
The following shortcut keys are available while using the selection tool.
| Shortcut | Action |
|---|---|
| Ctrl(Cmd)+A | Select the entire canvas |
| Ctrl(Cmd)+C | Copy the selection |
| Ctrl(Cmd)+X | Cut the selection (copy and clear) |
| Ctrl(Cmd)+V | Paste the copied area |
| H | Flip the selection horizontally |
| V | Flip the selection vertically |
Color Palette
Select a drawing color from the 16-color palette.
| Shortcut | Action |
|---|---|
| 1โ8 | Select colors 0โ7 |
| Shift+1โ8 | Select colors 8โ15 |
Bank Number
Switch the target image bank (0โ2).
Loading External Files
Drag and drop an image file such as PNG or JPG onto the Image Editor to load the image at the editing area position. The original image colors are automatically converted to Pyxel's color palette, and any parts exceeding the image bank boundaries are clipped.
Tilemap Editor
A mode for arranging image bank images as tile patterns and editing tilemaps.
Specifications
- Tilemaps: 0โ7 (8 maps)
- Size: 256ร256 tiles each
- Tile Image: 8ร8 pixel region of the image bank
- Reference Image Bank: One per tilemap
Screen Layout
Tilemap Canvas
The editing area selected in the tilemap view is displayed magnified. Place tile images selected in the tile image view. Drawing tools and selection shortcuts are shared with the Image Editor. Note that all cells default to tile (0,0), so it is recommended to keep image bank position (0,0) empty.
| Shortcut | Action |
|---|---|
| Right Click | Pick the tile at the cursor position (tile pick) |
| Right Drag | Pan the view |
Tilemap View
A thumbnail view of the entire tilemap. The white frame indicates the current editing area.
| Shortcut | Action |
|---|---|
| Arrow Keys | Move the editing area (white frame) |
| Click/Drag | Move the editing area to the clicked position |
Tile Image View
Displays the referenced image bank. Select tile images with the white frame.
| Shortcut | Action |
|---|---|
| Shift+Arrow Keys | Move the selection |
| Drag | Select multiple tiles in a rectangle |
| Right Drag | Pan the view |
Tilemap Number
Switch the target tilemap (0โ7).
Ref. Image Bank Number
Switch the image bank (0โ2) referenced for tile images.
Tool Buttons
Select a tool for drawing.
- S โ Select a rectangular area
- P โ Draw freehand. Hold Shift for straight lines
- R โ Draw a rectangle outline. Hold Shift for a square
- Shift+R โ Draw a filled rectangle. Hold Shift for a square
- C โ Draw an ellipse outline. Hold Shift for a circle
- Shift+C โ Draw a filled ellipse. Hold Shift for a circle
- B โ Fill a connected region of the same color
Placing Multiple Tiles
When you draw with multiple tile images selected by dragging in the tile image view, the selected tiles are placed as a repeating pattern. For example, if you select two tiles vertically and draw with the pen, the two tiles are placed alternately in a repeating pattern. The same applies when selecting multiple tiles both horizontally and vertically. The drawing start position corresponds to the top-left of the selection.
Loading TMX Files
Drag and drop a TMX file created with Tiled Map Editor (Tiled) onto the Tilemap Editor to load the contents of layer 0 at the editing area position.
Sound Editor
A mode for editing sounds used for melodies and sound effects.
Specifications
- Sounds: 0โ63 (64 sounds)
- Pitch Range: C0โB4
- Max Length: 48 notes
- Polyphony: 1 note (or rest)
- Per-Note Settings: Tone, volume, effect
Screen Layout
Sound Number
Switch the target sound (0โ63).
Playback Speed
Sets the playback duration per note. This is a common setting for all notes, specified in the range 1โ99. Smaller values result in faster playback (1 speed unit = 1/120 second; e.g., speed 60 = 0.5 seconds per note). For sound effects, 1โ9 is typical; for melodies, 10 or higher is recommended.
Play / Stop / Loop
- Space โ Play
- Space โ Stop (press Space during playback to stop)
- L โ Toggle loop playback
Piano Roll
Click to input note pitch. Red squares represent notes, blue squares represent rests. During piano roll editing, a blue cursor is displayed; during property area editing, a different cursor shape appears. Notes are played from left to right, and rests are automatically inserted in empty positions. Clicking an already-filled position overwrites it. Dragging inputs notes continuously with linear interpolation.
| Shortcut | Action |
|---|---|
| Up/Down | Switch between piano roll and property area |
| Left/Right | Move the cursor |
| Delete(fn+delete) | Delete the note at the current position |
| Backspace(delete) | Delete the note before the current position |
| Shift+Space | Play from the cursor position |
| Ctrl(Cmd)+A | Select the entire range |
| Shift+Left/Right | Start range selection |
Range Selection
| Shortcut | Action |
|---|---|
| Ctrl(Cmd)+C | Copy the selection |
| Ctrl(Cmd)+X | Cut the selection (copy and clear) |
| Ctrl(Cmd)+V | Paste the copied area |
| Ctrl(Cmd)+U | Raise the pitch of the selection by 1 |
| Ctrl(Cmd)+D | Lower the pitch of the selection by 1 |
Octave Bar
Displays the starting octave (0โ3) for keyboard input. The keyboard covers two octaves from the selected octave.
| Shortcut | Action |
|---|---|
| PageUp(fn+Up) | Raise the octave by 1 |
| PageDown(fn+Down) | Lower the octave by 1 |
Keyboard Input
You can input notes using the PC keyboard. The upper row (QWE row + number row) and the lower row (ZXC row + ASD row) each correspond to one octave of piano keys, covering two octaves simultaneously. White keys are assigned to natural notes and gray keys to sharps. Select the starting octave (0โ3) with the octave bar.
Upper Octave (QWE row + number row)
| Note | Key |
|---|---|
| C | Q |
| C# | 2 |
| D | W |
| D# | 3 |
| E | E |
| F | R |
| F# | 5 |
| G | T |
| G# | 6 |
| A | Y |
| A# | 7 |
| B | U |
Lower Octave (ZXC row + ASD row)
| Note | Key |
|---|---|
| C | Z |
| C# | S |
| D | X |
| D# | D |
| E | C |
| F | V |
| F# | G |
| G | B |
| G# | H |
| A | N |
| A# | J |
| B | M |
| Rest | A |
| Shortcut | Action |
|---|---|
| Keyboard Key โ Enter | Input the pressed keyboard note into the piano roll |
| 1 | Cycle the preview tone for keyboard input (4 types) |
Property Area (TON / VOL / EFX)
Set the tone (TON), volume (VOL), and effect (EFX) for each note. Press the โ key or click the TON row during piano roll editing to move to the property area. Cursor movement, range selection, copy & paste, and other operations are shared with the piano roll. Press a key on each row to input the corresponding value. For example, pressing P on the TON row sets Pulse. To change the tone partway through, set the value for all notes from the desired position onward. The same applies to VOL and EFX.
Tone
With the cursor on the TON row, press the following keys to set the tone. The default when not set is T (Triangle).
| Key | Name | Description |
|---|---|---|
T |
Triangle | Triangle wave. Soft and gentle tone. Similar to a flute |
S |
Square | Square wave. Electronic and clear tone. Similar to a clarinet or organ |
P |
Pulse | Pulse wave. Bright and flashy tone. Similar to a trumpet |
N |
Noise | Noise. Unpitched sound. Suitable for percussion and explosion effects |
Volume
With the cursor on the VOL row, press number keys 0โ7 to set the volume (0 = silent, 7 = maximum). The default when not set is 7. Using maximum volume on multiple channels simultaneously may result in excessive loudness.
Effect
With the cursor on the EFX row, press the following keys to set the effect. The default when not set is N (None).
| Key | Name | Description |
|---|---|---|
N |
None | No effect |
S |
Slide | Smoothly glide the pitch from the previous note |
V |
Vibrato | Periodically oscillate the pitch |
F |
FadeOut | Gradually decrease the volume over the entire note. Also used to separate notes of the same pitch |
H |
Half-FadeOut | Gradually decrease the volume in the second half of the note. Longer sustain than F |
Q |
Quarter-FadeOut | Gradually decrease the volume in the last quarter of the note. Longer sustain than H |
Music Editor
A mode for arranging sounds in playback order to compose music tracks.
Specifications
- Music Tracks: 0โ7 (8 tracks)
- Channels: 4
- Sounds per Channel: Max 32
Screen Layout
Music Number
Switch the target music (0โ7).
Play / Stop / Loop
- Space โ Play
- Space โ Stop (press Space during playback to stop)
- L โ Toggle loop playback
Sequence Editor (CH0โCH3)
Place sound numbers in playback order across four channels (CH0โCH3). Copy and paste between channels is also supported.
| Shortcut | Action |
|---|---|
| Up/Down | Switch the editing channel |
| Left/Right | Move the editing cursor |
| Delete(fn+delete) | Delete the sound at the current position |
| Backspace(delete) | Delete the sound before the current position |
| Shift+Space | Play from the cursor position |
| Ctrl(Cmd)+A | Select the entire range of the current channel |
| Shift+Arrow Keys | Select a range within the channel |
| Ctrl(Cmd)+C | Copy the selection |
| Ctrl(Cmd)+X | Cut the selection (copy and clear) |
| Ctrl(Cmd)+V | Paste the selection (also across channels) |
| Ctrl(Cmd)+U | Increment the sound number of the selection by 1 |
| Ctrl(Cmd)+D | Decrement the sound number of the selection by 1 |
Sound Buttons (0โ63)
Buttons for inserting sound numbers (0โ63). Pressing a button inserts the sound number at the editing cursor position. Created sounds are shown in blue, uncreated ones in gray. Hovering over a button previews the sound.
Faq Ja (`docs/faq-ja.md`)
Pyxel ใใใใ่ณชๅ
Pyxel ใฎๅญฆใณๆน
Pyxel ใๅญฆ็ฟใใใซใฏใฉใใใๅงใใใฐใใใงใใ๏ผ
Pyxel ใฎใตใณใใซใณใผใใไปฅไธใฎ้ ใซ่ฉฆใใฎใใใใใใงใใ
- 01_hello_pyxel โ Pyxel ใฎๅบๆฌ
- 05_color_palette โ ใซใฉใผใใฌใใ
- 03_draw_api โ ๆ็ป API
- 04_sound_api โ ใตใฆใณใ API
- 02_jump_game โ ใฒใผใ ๅฎ่ฃ
ใตใณใใซใณใผใใฏ pyxel copy_examples ใงใณใใผใงใใใปใใPyxel Showcase ใงใใฉใฆใถไธใงใๅฎ่กใงใใพใใ
Pyxel ใซ้ขใใๆธ็ฑใฏใใใพใใ๏ผ
ๆฅๆฌ่ช็ใฎใฟใงใใใๅ ฌๅผใฎๆธ็ฑ ใ็บๅฃฒใใใฆใใพใใ
API ไปๆงใจไฝฟใๆน
update ้ขๆฐใจ draw ้ขๆฐใฎ้ใใฏไฝใงใใ๏ผ
update ้ขๆฐใฏๆฏใใฌใผใ ๅผใณๅบใใใพใใใdraw ้ขๆฐใฏๅฆ็ๆ้ใ่จฑๅฎน้็ใ่ถ
ใใๅ ดๅใซในใญใใใใใใใจใใใใพใใPyxel ใฏใใฎ่จญ่จใซใใใใฌใณใใชใณใฐ่ฒ ่ทใ OS ใฎๅฒใ่พผใฟๅฆ็ใฎๅฝฑ้ฟใ่ปฝๆธใใฆใๆปใใใชใขใใกใผใทใงใณใๅฎ็พใใฆใใพใใ
Pyxel MML ใฎไฝฟใๆนใๆใใฆใใ ใใ
MML (Music Macro Language) ใฏใ้ณ็ฌฆใใใณใใชใฉใๆๅญๅใง่จ่ฟฐใใฆใตใฆใณใใๅฎ็พฉใใ่จ่ชใงใใ
Sound ใฏใฉในใฎ mml ้ขๆฐใซ MML ๆๅญๅใๆธกใใจใใใฎ Sound ใ MML ใฎๅ
ๅฎนใซๆฒฟใฃใฆๅ็ใใใใใใซใชใใพใใmml() ใๅผๆฐใชใใงๅผใถใจ MML ่จญๅฎใ่งฃ้คใงใใพใใ
pyxel.sounds[0].mml("CDEFGAB>C")play ้ขๆฐใซใตใฆใณใ็ชๅทใฎไปฃใใใซ MML ๆๅญๅใ็ดๆฅๆธกใใฆๅ็ใใใใจใใงใใพใใ
pyxel.play(0, "CDEFG")ๅฉ็จใงใใ MML ใณใใณใใฏ Pyxel MML ใณใใณใ ใๅ็ งใใฆใใ ใใใไฝฟ็จไพใฏใตใณใใซ 09_shooter.py ใฎ ใใข ใ ใณใผใ ใง็ขบ่ชใงใใพใใ
ใพใใPyxel MML Studio ใไฝฟใใฐใMML ใใใฉใฆใถไธใงไฝๆใปๅ ฑๆใงใใพใใ
ใใกใคใซๆไฝใจใใผใฟ็ฎก็
็ฐๅขใๅคใใใจใใกใคใซใ่ชญใฟ่พผใใชใใชใใฎใฏใชใใงใใ๏ผ
ใใกใคใซใ่ชญใฟ่พผใ้ใซใใซใฌใณใใใฃใฌใฏใใชใๆๅณใใใใฎใซใชใฃใฆใใใใ็ขบ่ชใใฆใใ ใใใ
Pyxel ใฎ init ้ขๆฐใๅผใฐใใใจใใซใฌใณใใใฃใฌใฏใใชใฏใใฎในใฏใชใใใใกใคใซใจๅใๅ ดๆใซๅคๆดใใใใใไปฅ้ใฏ็ธๅฏพใในใงใใกใคใซใๆๅฎใงใใพใใใใใใinit ใๅผใถๅใซใใกใคใซใ้ใใใจใใๅ ดๅใ init ใฎๅพใซใซใฌใณใใใฃใฌใฏใใชใๅคๆดใใๅ ดๅใซใฏ่ชญใฟ่พผใฟใซๅคฑๆใใๅฏ่ฝๆงใใใใพใใ
ใใคในใณใขใใฒใผใ ใฎ้ฒ่ก็ถๆณใชใฉใใขใใชใฑใผใทใงใณๅบๆใฎใใผใฟใไฟๅญใใๆนๆณใฏใใใพใใ๏ผ
้็บ่
ๅ (vendor_name) ใจใขใใชๅ (app_name) ใ user_data_dir(vendor_name, app_name) ้ขๆฐใซๆธกใใจใใใฉใใใใฉใผใ ใซ้ฉใใใใผใฟไฟๅญ็จใฎใใฃใฌใฏใใชใไฝๆใใใใฎใในใ่ฟใใพใใใใฎใใฃใฌใฏใใชใฎไธใงใขใใชใฑใผใทใงใณ็จใฎใใกใคใซใฎไฟๅญใ่ชญใฟ่พผใฟใ่กใฃใฆใใ ใใใ
Pyxel ใใผใซใฎไฝฟใๆน
ใคใณในใใผใซใใใซ Pyxel ใ่ฉฆใใพใใ๏ผ
Pyxel Code Maker ใไฝฟใใฐใใใฉใฆใถไธใง Pyxel ใขใใชใฎไฝๆใปๅฎ่กใใงใใพใใใใ ใใ่คๆฐใใกใคใซๆงๆใซใฏๅฏพๅฟใใฆใใชใใใใๆฌๆ ผ็ใช้็บใซใฏใญใผใซใซ็ฐๅขใใใใใใใพใใ
Pyxel Showcase ใงใฏใใตใณใใซใณใผใใใขใใชใใใฉใฆใถไธใงไธ่ฆงใปๅฎ่กใงใใพใใ
่ชไฝใฎ Pyxel ใขใใชใ Web ใงๅ ฌ้ใใใซใฏใฉใใใใฐใใใงใใ๏ผ
Pyxel Web Launcherใapp2htmlใHTML ใซในใฟใ ่ฆ็ด ใฎ 3 ใคใฎๆนๆณใใใใพใใ่ฉณใใใฏ Web ็ Pyxel ใฎไฝฟใๆน ใๅ็ งใใฆใใ ใใใ
Pyxel Editor ใงใใฌใใใฎ่ฒใๅคๆดใงใใพใใ๏ผ
Pyxel ใชใฝใผในใใกใคใซ (.pyxres) ใจๅใใใฃใฌใฏใใชใซใๆกๅผตๅญใ .pyxpal ใซๅคใใๅๅใฎใใกใคใซใ้
็ฝฎใใใจใPyxel Editor ใฎใใฌใใ่กจ็คบ่ฒใๅคๆดใใใพใใใใฌใใใใกใคใซใฏ save_pal ้ขๆฐใงไฝๆใงใใใปใใ1 ่กใซ 1 ่ฒใฎ RRGGBB ๅฝขๅผใฎ 16 ้ฒๆฐใซใฉใผใณใผใใ่จ่ฟฐใใใใญในใใใกใคใซใจใใฆๆๅใงไฝๆใใใใจใใงใใพใใ
ใใผใธใงใณ็งป่กใฌใคใ
ใใผใธใงใณ 2.4 ใธใฎ็งป่กๆนๆณ
Pyxel 2.4 ใงใฏใตใฆใณใใจใณใธใณใจ MML ๆๆณใๅทๆฐใใใฆใใพใใ
ใณใผใใใใผใธใงใณ 2.4 ใซๅฏพๅฟใใใใซใฏใไปฅไธใฎๅคๆดใ่กใฃใฆใใ ใใใ
- Tone ใฏใฉในใฎ
waveformใใฃใผใซใใwavetableใซใชใใผใ ใใ play้ขๆฐใplaym้ขๆฐใฎtickๅผๆฐใsec๏ผๅฐๆฐๅฝขๅผใฎ็งๆฐ๏ผใซๅคๆดใใplay_pos้ขๆฐใฎๆปใๅคใ(sound_index, sec)ใซๅคใใฃใใใจใซๅฏพๅฟใใ- Sound ใฏใฉในใMusic ใฏใฉในใฎ
save้ขๆฐใฎcountๅผๆฐใsecใซๅคๆดใใ - ใตใฆใณใใฎๅ็็งๆฐใๅฟ
่ฆใชๅ ดๅใฏใSound ใฏใฉในใฎ
total_sec้ขๆฐใๅฉ็จใใ - Sound ใฏใฉในใฎ
mml้ขๆฐใซใฏๆฐ MML ๆๆณใซๆฒฟใฃใใณใผใใๆๅฎใใ๏ผๆงๆๆณใฏ่ชๅๆคๅบใใใใold_mml้ขๆฐใฏ้ๆจๅฅจ๏ผ saveใload้ขๆฐใฎexcl_*ใชใใทใงใณใexclude_*ใซๅคๆดใใsaveใload้ขๆฐใฎincl_*ใชใใทใงใณใฎๆๅฎใๅ้คใใ
ๆฐใใ MML ๆๆณใฏไธ่จใฎใPyxel MML ใฎไฝฟใๆนใใๅ็ งใใฆใใ ใใใ
ใฉใคใปใณในใจในใใณใตใผใทใใ
Pyxel ใไฝ่ ใฎ่จฑๅฏใชใๅๆฅญ็ฎ็ใงไฝฟ็จใใใใจใฏใงใใพใใ๏ผ
MIT ใฉใคใปใณในใซๅพใใใฝใผในใณใผใใใฉใคใปใณใน่กจ็คบ็จใฎใใกใคใซใซ่ไฝๆจฉใใใณใฉใคใปใณในใฎๅ จๆใๆ็คบใใใฐใไฝ่ ใฎ่จฑๅฏใๅพใใใจใชใ่ช็ฑใซ่ฒฉๅฃฒใ้ ๅธใๅฏ่ฝใงใใใใ ใใPyxel ใฏๅไบบใง้็บใใฆใใใใใไฝ่ ใธใฎใ้ฃ็ตกใในใใณใตใผใซใใใๆฏๆดใใใใ ใใใจใใใใใใงใใ
Faq (`docs/faq.md`)
Pyxel FAQ
Learning Pyxel
Where do I start to learn Pyxel?
We recommend trying Pyxel's example code in the following order.
- 01_hello_pyxel โ Pyxel basics
- 05_color_palette โ Color palette
- 03_draw_api โ Drawing API
- 04_sound_api โ Sound API
- 02_jump_game โ Game implementation
You can copy the examples with pyxel copy_examples, or run them in your browser on Pyxel Showcase.
Are there any books on Pyxel?
The official book is available in Japanese only.
API Specification and Usage
What is the difference between the update and draw functions?
The update function is called every frame, but the draw function may be skipped if the processing time exceeds the allowable limit. Pyxel uses this design to reduce the impact of rendering load and OS interrupts, enabling smooth animation.
How do I use Pyxel MML?
MML (Music Macro Language) is a language for defining sounds by describing notes, tempo, and other parameters as a string.
Pass an MML string to the Sound class's mml function, and that Sound will play back following the MML. Calling mml() with no arguments clears the MML setting.
pyxel.sounds[0].mml("CDEFGAB>C")You can also play an MML string directly by passing it to the play function instead of a sound number.
pyxel.play(0, "CDEFG")For available MML commands, see Pyxel MML Commands. For usage examples, see the demo and code of the 09_shooter.py example.
You can also create and share MML in your browser using Pyxel MML Studio.
File Operations and Data Management
Why does file loading fail when the environment changes?
Make sure that the current directory is set as intended when loading files.
When Pyxel's init function is called, the current directory is changed to the same location as the script file. After that, files can be specified using relative paths. However, loading may fail if you try to open a file before calling init or if the current directory is changed after calling init.
How can I save application-specific data like high scores or game progress?
Pass the developer name (vendor_name) and application name (app_name) to the user_data_dir(vendor_name, app_name) function. It will create a directory suitable for data storage on the current platform and return its path. Use this directory to save and load your application's files.
Using Pyxel Tools
Can I try Pyxel without installing it?
With Pyxel Code Maker, you can create and run Pyxel apps in your browser. However, it does not support multi-file projects, so a local environment is recommended for full-scale development.
Pyxel Showcase lets you browse and run sample code and apps in your browser.
How do I publish my Pyxel app on the web?
There are three methods: Pyxel Web Launcher, app2html, and HTML Custom Elements. For details, see How to Use Pyxel for Web.
Can I change the palette colors in Pyxel Editor?
If you place a file with the same name but the .pyxpal extension in the same directory as the Pyxel resource file (.pyxres), Pyxel Editor will display the palette using those colors. Palette files can be created with the save_pal function, or manually as a text file with one RRGGBB hex color per line.
Migration Guide
How to migrate code to version 2.4
In Pyxel 2.4, the sound engine and MML syntax have been revamped.
To make your code compatible with version 2.4, please make the following changes:
- Rename the
waveformfield of the Tone class towavetable - Change the
tickargument of theplayandplaymfunctions tosec(a float value in seconds) - Update code to handle the return value of the
play_posfunction, which is now(sound_index, sec) - Change the
countargument of thesavefunction in the Sound and Music classes tosec - If you need the playback duration of a sound, use the
total_secfunction of the Sound class - For the Sound class's
mmlfunction, use code that follows the new MML syntax (old syntax is auto-detected; theold_mmlfunction is deprecated) - Change the
excl_*option in thesaveandloadfunctions toexclude_* - Remove the
incl_*option from thesaveandloadfunctions
For details on the new MML syntax, see "How do I use Pyxel MML?" above.
Licensing and Sponsorship
Can I use Pyxel for commercial purposes without the author's permission?
As long as you comply with the MIT License and clearly display the full text of the copyright and license in the source code or license file, you are free to sell or distribute your work without the author's permission. That said, Pyxel is developed by a single individual, so reaching out to the author or becoming a sponsor would be greatly appreciated.
Mml Commands (`docs/mml-commands.md`)
Pyxel MML Commands
This document was auto-generated from the Pyxel MML Commands web page, which also offers multilingual support.
| Command | Description |
|---|---|
T |
Sets the tempo (BPM). Range: 1-. Default is 120. |
Q <gate_percent> |
Sets the gate time as a percentage. Range: 0-100. 100 means the note is played with no gap, 0 means it is not played at all. Default is 80. |
@ <tone> |
Sets the tone. Range: 0-3 (by default: 0:Triangle / 1:Square / 2:Pulse / 3:Noise). Default is 0. |
V <vol> |
Sets the volume. Range: 0-127. Default is 100. |
K <key_offset> |
Sets the transpose amount in semitones. 12 raises the pitch by one octave. Default is 0. |
Y <offset_cents> |
Sets detune in cents. 100 raises by a semitone, -100 lowers by a semitone. Default is 0. |
@ENV <slot> |
Switches the envelope (volume curve) slot. Range: 0-. 0 turns it off. |
@ENV <slot> { init_vol, dur_ticks1, vol1, dur_ticks2, vol2, ... } |
Slot range: 1-. Sets and switches to the specified envelope slot. Slot 0 cannot be specified. Inside { }, specify "initial volume (once)", then repeat "duration (tick), volume (vol)". 1 tick is 1/48 of a quarter note. Example: @ENV1 { 30, 20, 100, 50, 0 } |
@VIB <slot> |
Switches the vibrato (pitch modulation) slot. Range: 0-. 0 turns it off. |
@VIB <slot> { delay_ticks, period_ticks, depth_cents } |
Slot range: 1-. Sets and switches to the specified vibrato slot. Slot 0 cannot be specified. Inside { }, specify "delay (tick), period (tick), depth (cent)". 1 tick is 1/48 of a quarter note. Example: @VIB1 { 24, 12, 100 } |
@GLI <slot> |
Switches the glide (pitch slide) slot. Range: 0-. 0 turns it off. |
@GLI <slot> { offset_cents, dur_ticks } |
Slot range: 1-. Sets and switches to the specified glide (pitch slide) slot. Slot 0 cannot be specified. Inside { }, specify "initial pitch offset (cent), time to return to 0 (tick)". 1 tick is 1/48 of a quarter note. Specifying * for each parameter automatically applies the pitch offset as the difference from the previous note and the return time as the playback duration of each note, respectively. Example: @GLI1 { -100, 24 } |
O <oct> |
Sets the octave. Range: -1-9. O4's A is 440 Hz. Default is 4. |
> |
Raises the octave by 1 (max 9). |
< |
Lowers the octave by 1 (min -1). |
L <len> |
Sets the default note/rest length. Range: 1-192. L4 is a quarter note, L8 is an eighth note, and L12 is an eighth note triplet. Default is 4. |
C/D/E/F/G/A/B |
Plays the specified note. You can specify the length after the note, e.g., F16. |
R |
Rest. Range: 1-192. You can specify the length after the rest, e.g., R8. |
# |
Raises the note by a semitone. |
+ |
Raises the note by a semitone. |
- |
Lowers the note by a semitone. |
. |
Dotted note/rest. Extends the length by half. Can be repeated for multiple dots. |
& |
Tie/Slur. When connecting the same pitch, it ties the notes into one. When connecting different pitches, it plays them legato (no gap). You can also specify only the length, e.g., C4&16. |
[ |
Start of repeat section. |
] <count> |
End of repeat section. Count range: 1-. Repeats the section between [ and ] the specified number of times. If omitted, repeats infinitely. Nested repeats are supported. |
Pyxres Format (`docs/pyxres-format.md`)
Pyxel Resource File Format (.pyxres)
This document describes the internal format of Pyxel resource files (.pyxres).
Overview
A .pyxres file is a ZIP archive containing a single TOML file named pyxel_resource.toml. All resource data โ images, tilemaps, sounds, and music โ is stored as human-readable text in TOML format.
An optional palette file (.pyxpal) can accompany the resource file to define a custom color palette.
File Structure
example.pyxres (ZIP archive)
โโโ pyxel_resource.tomlexample.pyxpal (optional, same directory)TOML Format
The pyxel_resource.toml file has the following top-level structure:
format_version = 1
[[images]]
...
[[tilemaps]]
...
[[sounds]]
...
[[musics]]
...The format_version field and all four section arrays (images, tilemaps, sounds, musics) are required. Empty fields inside an entry use empty arrays (e.g., notes = []), and a section intentionally skipped by save(..., exclude_*) is written as an empty array. A normal save writes the runtime banks (3 images, 8 tilemaps, 64 sounds, 8 musics); files with fewer entries are accepted on load.
Pyxel currently writes format_version = 1 for maximum backward compatibility. On load, files with format version up to 4 (the current maximum) are accepted. Files that contain the legacy archive layout (pyxel_resource/version + separate files) are detected and loaded with automatic conversion.
Images
Up to 3 image banks, each 256ร256 pixels. Each pixel is a palette color index (u8, 0โ15 for the default palette; 0โ255 for the extended palette of up to 256 colors).
[[images]]
width = 256
height = 256
data = [[0, 0, 10, 12, 12, 0, ...], [0, 7, 7, ...], ...]All fields are required.
| Field | Type | Description |
|---|---|---|
width |
u32 | Image width in pixels |
height |
u32 | Image height in pixels |
data |
array of arrays of u8 | 2D pixel data, one sub-array per row. Each value is a color index |
Compression: Trailing elements in each row that repeat the last distinct value are omitted. Trailing rows that are identical to the last distinct row are also omitted. When loading, omitted values are filled by repeating the last value.
For example, a row [0, 0, 5, 5, 5, 5] is stored as [0, 0, 5], and an image where the last 200 rows are all [0] stores only the first 56 rows plus one [0] row.
Tilemaps
Up to 8 tilemaps, each 256ร256 tiles. Each tile references an 8ร8 pixel region in an image bank.
[[tilemaps]]
width = 256
height = 256
imgsrc = 0
data = [[10, 6, 11, 6, 12, 6, 0, 0, ...], ...]All fields are required.
| Field | Type | Description |
|---|---|---|
width |
u32 | Tilemap width in tiles |
height |
u32 | Tilemap height in tiles |
imgsrc |
u32 | Source image bank index (0โ2) |
data |
array of arrays of u16 | 2D tile data in interleaved format (see below) |
Each tile in the tilemap is a coordinate pair (tile_x, tile_y) (u16, u16) pointing to the position of the 8ร8 tile in the source image bank. In the TOML data, these pairs are interleaved within each row: [tx0, ty0, tx1, ty1, ...], so each row has width ร 2 elements.
For example, a tilemap row of 3 tiles referencing image positions (10, 6), (11, 6), and (12, 6) is stored as [10, 6, 11, 6, 12, 6].
The same trailing-value compression as images is applied.
Sounds
Up to 64 sounds. Each sound is a sequence of notes with per-note tone, volume, and effect settings.
[[sounds]]
notes = [28, 28, 24, 19, -1, -1]
tones = [2]
volumes = [6]
effects = [2, 3, 3, 0]
speed = 25All fields are required. Empty sounds use empty arrays (e.g., notes = []).
| Field | Type | Description |
|---|---|---|
notes |
array of i8 | Note values. -1 = rest, 0 (C0) to 59 (B4) |
tones |
array of u8 | 0 = Triangle, 1 = Square, 2 = Pulse, 3 = Noise |
volumes |
array of u8 | 0 (silent) to 7 (max) |
effects |
array of u8 | 0 = None, 1 = Slide, 2 = Vibrato, 3 = FadeOut, 4 = Half-FadeOut, 5 = Quarter-FadeOut |
speed |
u16 | Playback speed in ticks per note (1 tick = 1/120 second). Default: 30 |
The tones, volumes, and effects arrays are stored exactly as set on the sound and may be shorter than notes. During playback, values are read cyclically (index modulo array length), and an empty array falls back to the default: tone 0 (Triangle), volume 7, effect 0 (None).
Note mapping: Notes are encoded as base + octave ร 12, where C=0, D=2, E=4, F=5, G=7, A=9, B=11, and octave ranges from 0 to 4. For example, C0=0, A4=57, B4=59.
MML-defined sounds: Sounds defined with Sound.mml() cannot be saved to .pyxres; only the notes, tones, volumes, effects, and speed fields are persisted. To preserve MML-based sounds, keep the MML strings in your source code and call sound.mml() at runtime.
Musics
Up to 8 music tracks. Each track arranges sounds across up to 4 channels for sequential playback.
[[musics]]
seqs = [[0, 1], [2, 3], [4]]The seqs field is required. Empty music uses an empty array (seqs = []).
| Field | Type | Description |
|---|---|---|
seqs |
array of arrays of u32 | Sound sequences per channel. seqs[0] is channel 0, seqs[1] is channel 1, etc. Each value is a sound index (0โ63) |
Trailing empty channels are omitted when saving.
Palette File (.pyxpal)
An optional text file with one RGB color per line in 6-digit hexadecimal format. The file uses the same base name as the .pyxres file (e.g., sample.pyxres โ sample.pyxpal).
000000
2b335f
7e2072
19959c
...| Property | Value |
|---|---|
| Default colors | 16 |
| Maximum colors | 256 |
| Format | One RRGGBB hex value per line |
If no .pyxpal file is present, the built-in default palette is used:
| Index | Color | Hex |
|---|---|---|
| 0 | Black | 000000 |
| 1 | Navy | 2b335f |
| 2 | Purple | 7e2072 |
| 3 | Green | 19959c |
| 4 | Brown | 8b4852 |
| 5 | Dark Blue | 395c98 |
| 6 | Light Blue | a9c1ff |
| 7 | White | eeeeee |
| 8 | Red | d4186c |
| 9 | Orange | d38441 |
| 10 | Yellow | e9c35b |
| 11 | Lime | 70c6a9 |
| 12 | Cyan | 7696de |
| 13 | Gray | a3a3a3 |
| 14 | Pink | ff9798 |
| 15 | Peach | edc7b0 |
User Guide (`docs/user-guide.md`)
Pyxel User Guide
This document was auto-generated from the Pyxel User Guide web page, which also offers multilingual support.
Pyxel (/หpษชksษl/) is a retro game engine for Python. With simple specifications inspired by retro gaming consoles, such as displaying only 16 colors and supporting 4 sound channels, you can easily enjoy making pixel-art-style games.
Pyxel is open source under the MIT License and free to use. Let's start making retro games with Pyxel!
Also, this project is developed by one person, kept going by your GitHub stars. If you enjoy it, please give it a star!
Specifications
- Runs on Windows, Mac, Linux, and Web
- Programming in Python
- Customizable screen size
- 16-color palette
- 3 256x256 image banks
- 8 256x256 tilemaps
- 4 channels with 64 definable sounds
- 8 music tracks that can combine any sounds
- Keyboard, mouse, and gamepad inputs
- Image and sound editing tools
- User-extensible colors, sound channels, and banks
Color Palette
How to Install
Windows / Mac / Linux
After installing Python 3 (version 3.11 or higher), run the following command:
pip install -U pyxelNote: On Windows, if installing Python using the installer from python.org, make sure to check Add python.exe to PATH to enable the pyxel command.
Web
The web version of Pyxel can be used without installation on PCs, smartphones, tablets, and other devices with a compatible browser.
The web-based development environment Pyxel Code Maker is ready to use simply by opening it in your browser.
For other usage, such as embedding Pyxel apps on your own site, please refer to How to Use Pyxel for Web.
VS Code
By adding the Pyxel extension to Visual Studio Code (VS Code), you can develop and run Pyxel apps without installing Python or Pyxel.
To add the Pyxel extension, search for "Pyxel" in the VS Code Extensions view and click the install button.
Basic Usage
Pyxel Command
Installing Pyxel adds the pyxel command. Specify a command name after pyxel to perform various operations.
Run it without arguments to see the list of available commands:
pyxelPyxel, a retro game engine for Python
usage:
pyxel run PYTHON_SCRIPT_FILE(.py)
pyxel watch WATCH_DIR PYTHON_SCRIPT_FILE(.py)
pyxel play PYXEL_APP_FILE(.pyxapp)
pyxel edit [PYXEL_RESOURCE_FILE(.pyxres)]
pyxel package APP_DIR STARTUP_SCRIPT_FILE(.py)
pyxel app2exe PYXEL_APP_FILE(.pyxapp)
pyxel app2html PYXEL_APP_FILE(.pyxapp)
pyxel copy_examplesTry Examples
The following command copies Pyxel examples to the current directory:
pyxel copy_examplesYou can run examples locally with the following commands:
# Run example in examples directory
cd pyxel_examples
pyxel run 01_hello_pyxel.py
# Run app in examples/apps directory
cd apps
pyxel play 30sec_of_daylight.pyxappExamples can also be viewed and run in the browser from Pyxel Showcase.
Creating Applications
Create a Program
In your Python script, import Pyxel, set the window size with init, and start the application with run.
import pyxel
pyxel.init(160, 120)
def update():
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
def draw():
pyxel.cls(0)
pyxel.rect(10, 10, 20, 20, 11)
pyxel.run(update, draw)The arguments of the run function are the update function, which processes frame updates, and the draw function, which handles screen drawing.
In an actual application, it is recommended to wrap Pyxel code in a class, as shown below:
import pyxel
class App:
def __init__(self):
pyxel.init(160, 120)
self.x = 0
pyxel.run(self.update, self.draw)
def update(self):
self.x = (self.x + 1) % pyxel.width
def draw(self):
pyxel.cls(0)
pyxel.rect(self.x, 0, 8, 8, 9)
App()For creating simple graphics without animation, you can use the show function to simplify your code.
import pyxel
pyxel.init(120, 120)
pyxel.cls(1)
pyxel.circb(60, 60, 40, 7)
pyxel.show()Run a Program
A created script can be executed using the python command:
python PYTHON_SCRIPT_FILEIt can also be run with the pyxel run command:
pyxel run PYTHON_SCRIPT_FILEAdditionally, the pyxel watch command monitors changes in a specified directory and automatically re-runs the program when changes are detected:
pyxel watch WATCH_DIR PYTHON_SCRIPT_FILEStop directory monitoring by pressing Ctrl(Cmd)+C.
Special Key Controls
The following special key actions are available while a Pyxel application is running:
| Shortcut | Action |
|---|---|
| Esc | Quit the application |
| Alt(Option)+R or A+B+X+Y+BACK on gamepad | Reset the application |
| Alt(Option)+1 | Save the screenshot to the desktop |
| Alt(Option)+2 | Reset the recording start time of the screen capture video |
| Alt(Option)+3 | Save a screen capture video to the desktop (up to 10 seconds) |
| Alt(Option)+8 or A+B+X+Y+DL on gamepad | Toggle screen scaling between maximum and integer |
| Alt(Option)+9 or A+B+X+Y+DR on gamepad | Switch between screen modes (Crisp/Smooth/Retro) |
| Alt(Option)+0 or A+B+X+Y+DU on gamepad | Toggle the performance monitor (FPS/update time/draw time) |
| Alt(Option)+Enter or A+B+X+Y+DD on gamepad | Toggle fullscreen |
| Shift+Alt(Option)+1/2/3 | Save image bank 0, 1, or 2 to the desktop |
| Shift+Alt(Option)+0 | Save the current color palette to the desktop |
Creating Resources
Pyxel Editor
Pyxel Editor creates images and sounds used in a Pyxel application.
The created data is saved as a Pyxel resource file (.pyxres).
For detailed usage instructions, see the Pyxel Editor Manual.
Other Creation Methods
Pyxel images and tilemaps can also be created using the following methods:
- Create images or tilemaps from lists of strings with the
Image.setorTilemap.setfunctions - Load palette-ready image files (PNG/GIF/JPEG) with the
Image.loadfunction
Pyxel sounds and music can also be created using the following method:
- Create them from strings with the
Sound.setorMusic.setfunctions
Refer to the API reference for the use of these functions.
Distributing Applications
Pyxel supports a cross-platform distribution format called a Pyxel application file.
Create a Pyxel application file (.pyxapp) with the pyxel package command:
pyxel package APP_DIR STARTUP_SCRIPT_FILEIf you need to include resources or additional modules, place them in the application directory.
Metadata can be displayed at runtime by specifying it in the following format within the startup script. Fields other than title and author are optional.
# title: Pyxel Platformer
# author: Takashi Kitao
# desc: A Pyxel platformer example
# site: https://github.com/kitao/pyxel
# license: MIT
# version: 1.0The created application file can be run using the pyxel play command:
pyxel play PYXEL_APP_FILEA Pyxel application file can also be converted to an executable or an HTML file using the pyxel app2exe or pyxel app2html commands.
API Reference
A complete list of Pyxel APIs is available at Pyxel API Reference.
Pyxel also includes advanced APIs that require specialized knowledge. You can view them by checking the "Advanced" checkbox on the reference page.
If you're confident in your skills, try using the Advanced API to create truly amazing works!
Links
Documentation
- Pyxel API Reference
- Pyxel MML Commands
- Pyxel Editor Manual
- How to Use Pyxel for Web
- Pyxel Resource File Format
- FAQ
Examples & Tools
- Pyxel Showcase
- Pyxel Web Launcher
- Pyxel Code Maker
- Pyxel MML Studio
- VS Code Extension
- MCP Server
- Claude Code Skill
Other Information
- User Examples
- Developer's X Account
- Discord Server (English)
- Discord Server (Japanese)
- Official Guidebook (Japanese)
How to Contribute
Submitting Issues
Use the Issue Tracker to submit bug reports and feature or enhancement requests. Before submitting a new issue, make sure there are no similar open issues.
Functional Testing
Anyone who manually tests the code and reports bugs or suggestions for enhancements in the Issue Tracker is very welcome!
Submitting Pull Requests
Patches and fixes are accepted in the form of pull requests (PRs). Make sure that the issue the pull request addresses is open in the Issue Tracker.
Submitting a pull request implies that you agree to license your contribution under the MIT License.
License
Pyxel is licensed under the MIT License. It can be reused in proprietary software, provided that all copies of the software or its substantial portions include a copy of the MIT License terms and a copyright notice.
Recruiting Sponsors
Pyxel is looking for sponsors on GitHub Sponsors. Please consider sponsoring Pyxel to support its continued maintenance and feature development. As a benefit, sponsors can consult directly with the Pyxel developer. For more details, please visit here.
Web Usage (`docs/web-usage.md`)
How to Use Pyxel for Web
This document was auto-generated from the How to Use Pyxel for Web web page, which also offers multilingual support.
Pyxel for Web is a version of Pyxel that runs in web browsers using WebAssembly technology. No installation of Python or Pyxel is required, and it is accessible from PCs, smartphones, and tablets.
Ways to Use Pyxel for Web
There are four ways to use Pyxel for Web.
| Method | Description |
|---|---|
| Pyxel Code Maker | An online development environment for writing and running code in the browser |
| Pyxel Web Launcher | Run a GitHub repository in the browser by specifying its URL |
| app2html Command | Convert a Pyxel application file (.pyxapp) to an HTML file |
| HTML Custom Elements | Add HTML custom elements to run Pyxel apps on any HTML page |
Pyxel Code Maker
Pyxel Code Maker is an online development environment that lets you develop and run Pyxel apps in the browser without installing Python or Pyxel. Just open it in your browser with no setup required, making it a great way to try Pyxel.
For detailed usage, see the Pyxel Code Maker Manual.
Pyxel Web Launcher
Pyxel Web Launcher is a tool that runs Python scripts and Pyxel apps (.pyxapp) published on GitHub simply by specifying their URL.
Launch URLs can be created on the Pyxel Web Launcher page by entering the required information, or manually using the format below. Note that Pyxel Web Launcher always uses the latest version of Pyxel.
URL Format
https://kitao.github.io/pyxel/web/launcher/?<command>=<username>/<repository>/<branch>/<path>/<filename without extension>Commands
| Command | Action |
|---|---|
run |
Run a Python script (.py) |
play |
Run a Pyxel app (.pyxapp) |
edit |
Edit a resource file (.pyxres) in Pyxel Editor |
URL Examples
To run src/scenes/title.py in user taro's repository my_repo, branch main:
https://kitao.github.io/pyxel/web/launcher/?run=taro/my_repo/main/src/scenes/titleTo run dist/games/shooter.pyxapp in the same repository:
https://kitao.github.io/pyxel/web/launcher/?play=taro/my_repo/main/dist/games/shooterAdditional Parameters
The following additional parameters can be specified for the run and play commands.
| Parameter | Description |
|---|---|
gamepad=enabled |
Display a virtual gamepad on touch devices (smartphones and tablets) |
Example URL with additional parameters for the run command:
https://kitao.github.io/pyxel/web/launcher/?run=taro/my_repo/main/src/scenes/title&gamepad=enabledThe edit command has the editor parameter to specify which editor to launch: image, tilemap, sound, music
Example URL for the edit command:
https://kitao.github.io/pyxel/web/launcher/?edit=taro/my_repo/main/assets/shooter&editor=tilemapApps consisting of multiple Python files load faster when bundled into a .pyxapp file with pyxel package and run with play.
app2html Command
The pyxel app2html command converts a Pyxel application file (.pyxapp) into a standalone HTML file.
pyxel app2html your_app.pyxappAll code and resource data are embedded in the HTML, so the generated file can be published simply by distributing it.
The Pyxel version is pinned to the one used at conversion time, so future updates will not affect behavior.
The virtual gamepad is enabled by default and automatically displayed on touch devices. To disable it, remove gamepad: "enabled" from the generated HTML.
HTML Custom Elements
By adding HTML custom elements provided by Pyxel to an HTML file, you can run Pyxel apps on any HTML page.
Setup
Add the following script tag to your HTML. If no version is specified, the latest version of Pyxel is always used.
<script src="https://cdn.jsdelivr.net/gh/kitao/pyxel/wasm/pyxel.js"></script>You can pin the Pyxel version by specifying a version number after @.
<script src="https://cdn.jsdelivr.net/gh/kitao/[email protected]/wasm/pyxel.js"></script>Loading this script makes three HTML custom elements available, corresponding to Pyxel's run, play, and edit commands: pyxel-run, pyxel-play, and pyxel-edit.
pyxel-run
A tag for running Python scripts.
To run Python code directly, write the code in the script attribute.
<pyxel-run
script="
import pyxel
pyxel.init(200, 150)
pyxel.cls(8)
pyxel.line(20, 20, 180, 130, 7)
pyxel.show()
"
></pyxel-run>To load an external file, specify root and name. root is the base directory for file lookup, and name is the file path.
<pyxel-run root="." name="test.py"></pyxel-run>If root is the current directory (root="."), the root attribute can be omitted.
pyxel-play
A tag for running Pyxel applications (.pyxapp).
A URL can also be specified for root.
<pyxel-play
root="https://cdn.jsdelivr.net/gh/kitao/pyxel/python/pyxel/examples/apps"
name="megaball.pyxapp"
></pyxel-play>pyxel-edit
A tag for editing resource files (.pyxres) in Pyxel Editor.
Use the editor attribute to specify which editor to launch.
<pyxel-edit root="assets" name="shooter.pyxres" editor="image"></pyxel-edit>Common Attributes
The following common attributes are available for pyxel-run and pyxel-play.
| Attribute | Description |
|---|---|
gamepad="enabled" |
Enable the virtual gamepad (automatically displayed on touch devices) |
Customizing Screen Display
By default, the Pyxel screen is displayed across the entire page. Place a `` tag with id="pyxel-screen" in the HTML to render the screen inside that element, allowing you to adjust its position and size.
Running in a Local Environment
When using HTML custom elements that load external files, a server is required because browser security restrictions prevent opening local files directly.
If you have a Python environment, you can start a simple server with the following command.
python -m http.server
# Use python3 on macOS and LinuxAfter starting the server, access http://localhost:8000/test.html in your browser.
--- METRICS ---
- Files Extracted: 11
- Estimated Token Budget: ~36918 tokens
- Canonical Reference: https://codewiki.google/github.com/kitao/pyxel