# RCWeb Graffiti App

The **RCWeb Graffiti App** (`app/graffiti`) is the display engine for a collaborative, asymmetric spray-paint experience. Operating on the **Asymmetric Pattern**, it turns a primary shared screen into a blank wall where multiple users can paint simultaneously from phones, either by dragging directly or by aiming with their handset orientation sensors.

![icon](pwa-512x512.png "Graffiti App Icon")

## Screenshot
![screenshot](screenshot.png "Graffiti App")

## What it does

- **Spray Paint Wall**: Acts as a full-screen digital wall that renders incoming paint as soft spray clouds and speckled droplets instead of simple straight pen strokes.
- **Easy Drop-in Access**: Generates a standard QR Code routing users securely to the `graffiti-c` app. Scanning the code connects their phone instantly to the canvas.
- **Dynamic Resolution Scaling**: As the browser window resizes, the canvas preserves drawn pixel data transparently by storing it via `ctx.getImageData()` and restoring it dynamically, preventing strokes from being erased during orientation changes.
- **Proportional Tracking**: Constantly broadcasts its actual aspect ratio (`broadcastSize`) down to connected smartphones so that the drawing surfaces geometrically match, preventing warped strokes.
- **Remote Aim Feedback**: Displays a colored live crosshair on the main wall showing where each motion-enabled controller is currently pointing, making phone-based spraying visible before the user presses down.

## How it works

The system is a highly simplified rendering engine running entirely within an HTML5 `<canvas>` context, governed by `script.js`.

- **Asymmetric Graphic Execution**: It exposes public viewer APIs such as `drawLine`, `clearCanvas`, and `setAimCursor`. It performs no input capture locally and relies entirely on RCWeb remote function calls from connected controller devices.
- **Mathematical Paint Scaling**: When the `graffiti-c` app fires `graffiti.drawLine(player, startX, startY, endX, endY, color)`, the coordinates supplied are floating-point percentages (0.0 to 1.0) rather than hard pixels. The script multiplies these values by the local `width` and `height`, completely decoupling coordinate mapping across drastically different screen sizes.
- **Layered Spray Rendering**: Rather than stroking a single vector line, the viewer stamps many translucent droplets and radial mist gradients along the transmitted path, creating a much closer approximation of aerosol paint in the selected color.
- **Motion Cursor Presence**: Motion-enabled controllers also call `graffiti.setAimCursor(...)`, which positions a transient colored crosshair overlay over the canvas so the audience can see where the phone is aimed before and during spraying.
