Skip to content

Instantly share code, notes, and snippets.

@lee2sman
Last active December 4, 2025 00:21
Show Gist options
  • Select an option

  • Save lee2sman/f84e03ef5e5209a9466d2c0795c2d50a to your computer and use it in GitHub Desktop.

Select an option

Save lee2sman/f84e03ef5e5209a9466d2c0795c2d50a to your computer and use it in GitHub Desktop.
A p5.js to L5 script converter - used for converting reference and example code from the p5 site for L5
#!/bin/bash
# p5.js to L5 Converter
# Usage: ./convert.sh input.js [output.lua]
if [ $# -eq 0 ]; then
echo "Usage: $0 input.js [output.lua]"
echo "Converts p5.js JavaScript files to L5 Lua syntax"
exit 1
fi
INPUT_FILE="$1"
OUTPUT_FILE="${2:-${INPUT_FILE%.*}.lua}"
if [ ! -f "$INPUT_FILE" ]; then
echo "Error: Input file '$INPUT_FILE' not found"
exit 1
fi
echo "Converting $INPUT_FILE to $OUTPUT_FILE..."
# Create temporary file for processing
TEMP_FILE=$(mktemp)
# Add L5 require statement and copy input to temp file
echo 'require("L5")' > "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
cat "$INPUT_FILE" >> "$TEMP_FILE"
# Protect template variable syntax ${ ... } BEFORE we convert braces
# Replace ${ with placeholder
sed -i 's/\${/__DLBR__/g' "$TEMP_FILE"
# Replace the } that closes a ${...} expression (anything between __DLBR__ and })
# Match any characters that are not } after __DLBR__
sed -i 's/__DLBR__\([^}]*\)}/__DLBR__\1__RBR__/g' "$TEMP_FILE"
# Function definitions
sed -i 's/function \([a-zA-Z_][a-zA-Z0-9_]*\)(\([^)]*\))\s*{/function \1(\2)/g' "$TEMP_FILE"
# For loops
sed -i 's/for\s*(\s*let\s\+\([a-zA-Z_][a-zA-Z0-9_]*\)\s*=\s*\([^;]*\)\s*;\s*\([a-zA-Z_][a-zA-Z0-9_]*\)\s*<\s*\([^;]*\)\s*;\s*[^)]*)\s*{/for \1=\2,\4-1 do/g' "$TEMP_FILE"
sed -i 's/for\s*(\s*let\s\+\([a-zA-Z_][a-zA-Z0-9_]*\)\s*=\s*\([^;]*\)\s*;\s*\([a-zA-Z_][a-zA-Z0-9_]*\)\s*<=\s*\([^;]*\)\s*;\s*[^)]*)\s*{/for \1=\2,\4 do/g' "$TEMP_FILE"
# For...of loops - convert for (let x of array) to for _,x in ipairs(array) do
sed -i 's/for\s*(\s*let\s\+\([a-zA-Z_][a-zA-Z0-9_]*\)\s\+of\s\+\([^)]*\))\s*{/for _,\1 in ipairs(\2) do/g' "$TEMP_FILE"
sed -i 's/for\s*(\s*const\s\+\([a-zA-Z_][a-zA-Z0-9_]*\)\s\+of\s\+\([^)]*\))\s*{/for _,\1 in ipairs(\2) do/g' "$TEMP_FILE"
# Operators
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)\s*+=\s*\([^;]*\)/\1 = \1 + \2/g' "$TEMP_FILE"
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)\s*-=\s*\([^;]*\)/\1 = \1 - \2/g' "$TEMP_FILE"
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)\s*\*=\s*\([^;]*\)/\1 = \1 * \2/g' "$TEMP_FILE"
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)\s*\/=\s*\([^;]*\)/\1 = \1 \/ \2/g' "$TEMP_FILE"
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)++/\1 = \1 + 1/g' "$TEMP_FILE"
sed -i 's/++\([a-zA-Z_][a-zA-Z0-9_]*\)/\1 = \1 + 1/g' "$TEMP_FILE"
sed -i 's/\([a-zA-Z_][a-zA-Z0-9_]*\)--/\1 = \1 - 1/g' "$TEMP_FILE"
sed -i 's/--\([a-zA-Z_][a-zA-Z0-9_]*\)/\1 = \1 - 1/g' "$TEMP_FILE"
# Comments - convert // to -- (after var-- operator conversion)
sed -i 's|//|--|g' "$TEMP_FILE"
sed -i 's|/\*|--\[\[|g' "$TEMP_FILE"
sed -i 's|\*/|\]\]|g' "$TEMP_FILE"
# Remove semicolons
sed -i 's/;$//g' "$TEMP_FILE"
# Convert createCanvas to size
sed -i 's/createCanvas(/size(/g' "$TEMP_FILE"
# Control structures
# Handle else if before converting if
sed -i 's/}\s*else if\s*(\([^)]*\))\s*{/elseif \1 then/g' "$TEMP_FILE"
# Handle regular if
sed -i 's/if\s*(\([^)]*\))/if \1 then/g' "$TEMP_FILE"
# Handle standalone else
sed -i 's/}\s*else/else/g' "$TEMP_FILE"
# Replace braces with end
sed -i 's/{//g' "$TEMP_FILE"
sed -i 's/}/end/g' "$TEMP_FILE"
# Convert JavaScript arrays to Lua tables: [...] to {...}
sed -i 's/\[/{/g' "$TEMP_FILE"
sed -i 's/\]/}/g' "$TEMP_FILE"
# Variable declarations
sed -i 's/let \([a-zA-Z_][a-zA-Z0-9_]*\)\s*=/local \1 =/g' "$TEMP_FILE"
sed -i 's/var \([a-zA-Z_][a-zA-Z0-9_]*\)\s*=/local \1 =/g' "$TEMP_FILE"
sed -i 's/const \([a-zA-Z_][a-zA-Z0-9_]*\)\s*=/local \1 =/g' "$TEMP_FILE"
sed -i 's/let \([a-zA-Z_][a-zA-Z0-9_]*\);*/local \1/g' "$TEMP_FILE"
sed -i 's/var \([a-zA-Z_][a-zA-Z0-9_]*\);*/local \1/g' "$TEMP_FILE"
sed -i 's/const \([a-zA-Z_][a-zA-Z0-9_]*\);*/local \1/g' "$TEMP_FILE"
# Operators
sed -i 's/===/==/g' "$TEMP_FILE"
sed -i 's/!==/~=/g' "$TEMP_FILE"
sed -i 's/!=/~=/g' "$TEMP_FILE"
sed -i 's/&&/ and /g' "$TEMP_FILE"
sed -i 's/||/ or /g' "$TEMP_FILE"
# Console.log to print
sed -i 's/console\.log/print/g' "$TEMP_FILE"
# Convert template literals to Lua concatenation
# Convert __DLBR__var__RBR__ to __VAR__var__ENDVAR__ (temporarily)
sed -i 's/__DLBR__\([^_]*\)__RBR__/__VAR__\1__ENDVAR__/g' "$TEMP_FILE"
# Replace backticks
sed -i 's/`\([^`]*\)`/"\1"/g' "$TEMP_FILE"
# Replace __VAR__x__ENDVAR__ with "..x.."
sed -i 's/__VAR__\([^_]*\)__ENDVAR__/"..\1.."/g' "$TEMP_FILE"
# Clean up double quotes between .. operators: ".."" -> ".."
sed -i 's/"\.\.""/.../g' "$TEMP_FILE"
# Clean up at start: "".. -> empty (remove both quotes and dots)
sed -i 's/""\.\.//g' "$TEMP_FILE"
# Clean up at end: .."" -> empty (remove both dots and quotes)
sed -i 's/\.\.""//g' "$TEMP_FILE"
# Move converted content to output file
mv "$TEMP_FILE" "$OUTPUT_FILE"
echo "Output saved to $OUTPUT_FILE"
# Clean up
rm -f "$TEMP_FILE" 2>/dev/null
echo
echo "Note: This is a basic conversion. You may need to manually adjust:"
echo "- For loop bounds (JavaScript 0-based vs Lua 1-based indexing)"
echo "- Function names that don't have direct L5 equivalents"
echo "- Complex expressions and syntax"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment