Created
April 25, 2026 00:49
-
-
Save levity/9b39a7c35c6035a60608fb735e3ccc07 to your computer and use it in GitHub Desktop.
patch Figma.app to allow remote debugging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # figma-debug-start | |
| # Stand-alone launcher: patches Figma (if needed) and starts with remote debugging. | |
| # - No dependency on this repo's JS files | |
| # - No dependency on project working directory | |
| # - No automatic package installation (safer for supply-chain) | |
| # - If CDP is already reachable, it does NOT restart Figma | |
| set -euo pipefail | |
| PORT="${FIGMA_DEBUG_PORT:-9222}" | |
| NO_KILL=false | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --no-kill) NO_KILL=true ;; | |
| -h|--help) | |
| cat <<EOF | |
| Usage: figma-debug-start [options] | |
| Options: | |
| --no-kill Do not kill running Figma before trying to start debug mode | |
| -h, --help Show help | |
| Environment: | |
| FIGMA_DEBUG_PORT Override debug port (default: 9222) | |
| EOF | |
| exit 0 | |
| ;; | |
| esac | |
| done | |
| if [[ "$(uname -s)" != "Darwin" ]]; then | |
| echo "This standalone script currently supports macOS only." | |
| exit 1 | |
| fi | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| RED='\033[0;31m' | |
| BOLD='\033[1m' | |
| NC='\033[0m' | |
| FIGMA_APP="/Applications/Figma.app" | |
| ASAR_PATH="$FIGMA_APP/Contents/Resources/app.asar" | |
| require_cmd() { | |
| local cmd="$1" | |
| if ! command -v "$cmd" >/dev/null 2>&1; then | |
| echo -e "${RED}Missing required command: '$cmd'. Please install it and retry.${NC}" | |
| exit 1 | |
| fi | |
| } | |
| cdp_ready() { | |
| local code | |
| code=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:${PORT}/json" || true) | |
| [[ "$code" == "200" ]] | |
| } | |
| is_figma_running() { | |
| pgrep -x "Figma" >/dev/null 2>&1 | |
| } | |
| require_cmd curl | |
| require_cmd python3 | |
| require_cmd codesign | |
| if [[ ! -d "$FIGMA_APP" ]]; then | |
| echo -e "${RED}Figma not found at $FIGMA_APP${NC}" | |
| exit 1 | |
| fi | |
| # IMPORTANT: If already running with CDP, do not restart. | |
| if cdp_ready; then | |
| echo -e "${GREEN}✓ Figma already running with remote debugging on localhost:${PORT}${NC}" | |
| exit 0 | |
| fi | |
| if [[ ! -f "$ASAR_PATH" ]]; then | |
| echo -e "${RED}Could not find app.asar at: $ASAR_PATH${NC}" | |
| exit 1 | |
| fi | |
| BLOCK='removeSwitch("remote-debugging-port")' | |
| PATCH='removeSwitch("remote-debugXing-port")' | |
| PATCH_STATUS=$(python3 - "$ASAR_PATH" <<'PY' | |
| import sys | |
| path = sys.argv[1] | |
| b = open(path, 'rb').read() | |
| block = b'removeSwitch("remote-debugging-port")' | |
| patch = b'removeSwitch("remote-debugXing-port")' | |
| cb = b.count(block) | |
| cp = b.count(patch) | |
| if cp >= 1 and cb == 0: | |
| print('already_patched') | |
| elif cb == 1 and cp == 0: | |
| print('patchable') | |
| elif cb == 0 and cp == 0: | |
| print('unknown_format') | |
| else: | |
| print(f'suspicious:{cb}:{cp}') | |
| PY | |
| ) | |
| if [[ "$PATCH_STATUS" == "already_patched" ]]; then | |
| echo -e "${GREEN}✓ Figma binary already patched${NC}" | |
| elif [[ "$PATCH_STATUS" == "patchable" ]]; then | |
| echo "Patching Figma binary (single known-string replacement)..." | |
| BACKUP_DIR="$HOME/.figma-debug-start/backups" | |
| mkdir -p "$BACKUP_DIR" | |
| BACKUP_PATH="$BACKUP_DIR/app.asar.$(date +%Y%m%d-%H%M%S).bak" | |
| cp "$ASAR_PATH" "$BACKUP_PATH" | |
| python3 - "$ASAR_PATH" <<'PY' | |
| import sys | |
| path = sys.argv[1] | |
| block = b'removeSwitch("remote-debugging-port")' | |
| patch = b'removeSwitch("remote-debugXing-port")' | |
| b = open(path, 'rb').read() | |
| if b.count(block) != 1 or b.count(patch) != 0: | |
| raise SystemExit('Refusing patch: unexpected pre-state') | |
| b2 = b.replace(block, patch, 1) | |
| if b2.count(block) != 0 or b2.count(patch) < 1: | |
| raise SystemExit('Refusing patch: verification failed') | |
| open(path, 'wb').write(b2) | |
| PY | |
| echo "Re-signing Figma app..." | |
| if codesign --force --deep --sign - "$FIGMA_APP" >/dev/null 2>&1; then | |
| echo -e "${GREEN}✓ Patch applied and app re-signed${NC}" | |
| else | |
| echo -e "${YELLOW}Patch applied, but re-signing failed (Figma may still run).${NC}" | |
| fi | |
| elif [[ "$PATCH_STATUS" == "unknown_format" ]]; then | |
| echo -e "${YELLOW}Could not find expected patch target in app.asar.${NC}" | |
| echo -e "${YELLOW}Figma version may have changed; continuing to launch anyway.${NC}" | |
| else | |
| echo -e "${RED}Suspicious/ambiguous patch state detected: $PATCH_STATUS${NC}" | |
| echo -e "${RED}Refusing to modify app.asar automatically.${NC}" | |
| exit 1 | |
| fi | |
| if is_figma_running; then | |
| if [[ "$NO_KILL" == "true" ]]; then | |
| echo -e "${YELLOW}Figma is already running and --no-kill was set.${NC}" | |
| echo "Attempting to launch with debug args without restart..." | |
| open -a Figma --args "--remote-debugging-port=${PORT}" >/dev/null 2>&1 || true | |
| else | |
| echo "Restarting Figma to apply debug args..." | |
| killall Figma >/dev/null 2>&1 || true | |
| sleep 1 | |
| open -a Figma --args "--remote-debugging-port=${PORT}" >/dev/null 2>&1 | |
| fi | |
| else | |
| echo "Starting Figma with remote debugging..." | |
| open -a Figma --args "--remote-debugging-port=${PORT}" >/dev/null 2>&1 | |
| fi | |
| for _ in {1..30}; do | |
| if cdp_ready; then | |
| echo -e "${GREEN}✓ Figma ready with remote debugging on localhost:${PORT}${NC}" | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo -e "${RED}Figma started, but remote debugging is not reachable yet.${NC}" | |
| if [[ "$NO_KILL" == "true" ]]; then | |
| echo -e "${YELLOW}Try again without --no-kill so Figma can restart with debug args.${NC}" | |
| fi | |
| exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment