#!/usr/bin/env bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # verify-web-joy.sh - Joystick gate for the web port: both sticks, every # direction, both buttons and every release, driven through the page's # Gamepad API and read back from what examples/joy draws; then the pads # unplugged while JOY runs. # # The port is the SDL3 backend built with Emscripten: SDL reads the # browser's gamepads (navigator.getGamepads) and the backend opens the # first two as JOYSTICK_0 and JOYSTICK_1, the left stick, the south button # as button 0 and the east as button 1. The gate's pads stand in for the # browser's (webDriver.mjs --gamepads: standard-mapping pads, connected from # the start, driven by pad: steps), so nothing plugged into this machine # is seen. JOY runs in headless Chromium at one canvas pixel per stage # pixel; the step script takes a canvas shot after every change, and the # shots then go through scripts/lib/joyScreen.py (scripts/lib/joyGate.sh) # in order. Unplugging must leave both sticks disconnected. # # Usage: scripts/verify-web-joy.sh # Env: JOY_SHOTS also keep the screenshots in this folder # Requires: Chromium and Node (install emulator:web), python3 + PIL; # build/web/bin/JOY (make web). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/joyGate.sh" source "$repo/scripts/lib/webGate.sh" webNeed JOY_LABEL=verify-web-joy JOY_SCALE=1 # The checks read shots the driver has already taken: no waiting, and none # taken again. JOY_PRESS_SECONDS=0 JOY_SHOT_TRIES=1 program=$(joeyExampleProgram joy web) startSeconds=3 # the page loaded and JOY drawing changeSeconds=0.3 # a change until JOY has drawn it wall=120 # the driver's own cap [ -f "$program" ] || { echo "$JOY_LABEL: build JOY first (make web)" >&2; exit 2; } JOY_WORK=$(mktemp -d -t joeylib-web-joy.XXXXXX) cleanup() { webStop rm -rf "$JOY_WORK" } trap cleanup EXIT shotIndex=0 shotCount=0 script=() joyPress() { : } joyRelease() { : } joyShot() { shotIndex=$((shotIndex + 1)) [ -s "$JOY_WORK/shots/$(printf '%03d' "$shotIndex").png" ] || return 1 cp "$JOY_WORK/shots/$(printf '%03d' "$shotIndex").png" "$1" } # shoot -- a shot step, numbered in the order the checks read them. shoot() { shotCount=$((shotCount + 1)) script+=(--step "wait:$changeSeconds" --step "shot:$JOY_WORK/shots/$(printf '%03d' "$shotCount").png") } mkdir -p "$JOY_WORK/shots" script+=(--step "wait:$startSeconds") shoot for step in "${JOY_STEPS_TWO_STICKS[@]}"; do IFS='|' read -r _ held _ _ <<< "$step" controls="${held// /,}" script+=(--step "pad:press:$controls") shoot script+=(--step "pad:release:$controls") shoot done script+=(--step "pad:unplug") shoot webServe "$(dirname "$program")" webDrive "$(basename "$program")?scale=1&aspect=square" --gamepads --seconds "$wall" "${script[@]}" 2> "$JOY_WORK/driver.log" || { echo "$JOY_LABEL: FAIL - the page could not be driven" >&2; tail -10 "$JOY_WORK/driver.log" >&2; exit 1; } joyCheck "rest" "A=$JOY_REST B=$JOY_REST" joyRunSteps "${JOY_STEPS_TWO_STICKS[@]}" joyCheck "pads unplugged" "A=$JOY_ABSENT B=$JOY_ABSENT" joyResult "$JOY_LABEL" "both pads, every direction, both buttons and every release; unplugged, both sticks gone"