gsproremote/Recommended kickoff plan.md

191 lines
No EOL
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Recommended kickoff plan
## 0) Toolchain (lock these down)
* **Python** 3.11 (for wheels availability + perf)
* **Node** 20.19+ and **npm** 10+
* **UV** for deps
* **Playwright** (later for UI smoke tests)
* **Git** repo from day 1
## 1) Make a tiny, opinionated repo scaffold
Create a new repo (you can copy/paste this tree into your README so the LLM follows it):
```
gspro-remote/
backend/
app/
__init__.py
main.py # FastAPI app factory + router mounts
api/
__init__.py
actions.py # /api/actions/*
vision.py # /api/vision/* (keep but V2-gated)
core/
config.py # AppConfig + load/save
input_ctrl.py # pydirectinput helpers
screen.py # mss capture utils (non-vision bits)
pkg.json # (optional) for uvicorn dev script via npm - or just use Makefile
pyproject.toml
README.md
frontend/
src/
main.tsx
App.tsx
pages/DynamicGolfUI.tsx
components/
AimPad.tsx
StatBar.tsx
MapPanel.tsx
styles/
index.html
package.json
vite.config.ts
README.md
scripts/
dev.ps1 # start both servers on Windows
.editorconfig
.gitignore
README.md
```
## 2) Bootstrap bare bones projects
### Backend (FastAPI)
```bash
cd backend
uv venv && uv pip install fastapi uvicorn pydantic-settings pydirectinput pywin32 mss opencv-python pillow zeroconf
# Or with pip:
# python -m venv .venv && .venv\Scripts\activate && pip install fastapi uvicorn pydirectinput pywin32 mss opencv-python pillow zeroconf
```
`app/main.py` (minimal)
```python
from fastapi import FastAPI
from .api.actions import router as actions_router
def create_app() -> FastAPI:
app = FastAPI(title="GSPro Remote", version="0.1.0")
app.include_router(actions_router, prefix="/api/actions", tags=["actions"])
return app
app = create_app()
```
`app/api/actions.py` (just enough to prove the vertical slice)
```python
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from ..core.input_ctrl import press_keys, focus_window
router = APIRouter()
class KeyReq(BaseModel):
keys: str
@router.post("/key")
def post_key(req: KeyReq):
if not focus_window("GSPro"):
raise HTTPException(409, "GSPro window not found/active")
press_keys(req.keys)
return {"ok": True}
```
Run:
```bash
uvicorn app.main:app --reload --host 0.0.0.0 --port 5005
```
### Frontend (Vite + React + TS)
```bash
cd ../frontend
npm create vite@latest . -- --template react-ts
npm i
npm run dev
```
Add a `.env` in frontend later if you want a configurable API base URL.
## 3) Migrate your existing code **incrementally**
You already have solid pieces. Bring them in slice by slice:
* Move `config.py``backend/app/core/config.py` (keep AppConfig + persistence).
* Move `input_ctrl.py``backend/app/core/input_ctrl.py` (unchanged).
* Create `backend/app/api/vision.py` and paste **only** the streaming endpoint youll use first (WebSocket or SSE). Keep OCR endpoints behind a `VISION_ENABLED` flag for V2.
* Defer `screen_watch.py`, `capture.py`, `streaming.py` until the “MapPanel” slice (below). Its okay if V1 ships with **no** OCR.
## 4) Implement one **vertical slice** end-to-end (MVP proof)
Start with the **Aim Pad + Mulligan** because it touches everything:
* Frontend:
* `components/AimPad.tsx`: buttons call `POST /api/actions/key` with `"left"`, `"right"`, `"up"`, `"down"`, and `"a"` (Reset).
* Add Mulligan button calling `"ctrl+m"`.
* Backend:
* The `post_key` route already exists.
* Make sure `focus_window("GSPro")` works on your machine.
* Test on Windows: you should see GSPro react from the tablet/phone.
Now you have a working remote!
## 5) Add the **MapPanel** as the second slice
* Backend:
* Introduce a simple `/api/vision/ws/stream` that returns a **downscaled JPEG** buffer of a fixed region; reuse your `mss` capture and JPEG base64 helpers. Keep the code minimal.
* Frontend:
* `components/MapPanel.tsx` opens a WS to `/api/vision/ws/stream`, paints frames onto a `<canvas>`, supports expand/collapse (no click mapping yet).
* Aim for **720p @ 30fps, \~7585 JPEG quality**. Measure latency, then optimize resize **before** JPEG encode.
## 6) Wire the rest of the “Essentials”
* Tee left/right (`c`/`v`)
* Scorecard (`t`) and Range finder (`r`) as secondary buttons under a kebab menu
* Stat row at bottom (hard-coded 0.0° up/right for now—wire later)
## 7) Keep OCR as **V2** but leave hooks
* Add a feature flag `VISION_ENABLED = False` in `app/core/config.py`.
* Keep `vision.py` imported but routes gated: if disabled, return 404 with a friendly message.
* This lets you merge OCR work later without reshaping the app.
## 8) Dev ergonomics on Windows
Create `scripts/dev.ps1` to run both servers:
```powershell
Start-Job { Set-Location backend; uvicorn app.main:app --reload --port 5005 }
Start-Sleep -Seconds 1
Start-Process powershell -ArgumentList 'cd frontend; npm run dev'
```
## 9) Packaging (when MVP is stable)
* **Backend**: PyInstaller or Nuitka into a single EXE, then wrap with **Inno Setup** to produce an installer that:
* Installs the EXE + config files to `C:\ProgramData\GSPro Remote\`
* Creates a Start Menu entry and an **auto-start shortcut** for the Windows user
* Opens firewall rule for your port
* **Frontend**: `npm run build` → copy `dist/` into `backend/ui/` and serve using FastAPI `StaticFiles`. (You already had `build-ui.py`; keep that idea.)
## 10) How to use the LLM effectively (so it helps, not hurts)
* **Give it the scaffold** and the **PRD** (and the Section-12 matrix).
* Ask for **one file at a time**: “Implement `components/AimPad.tsx` against `/api/actions/key`” with explicit props and return types.
* Paste back **real compiler/server errors** verbatim; ask it to fix **only those**.
* Freeze the public contracts early (API request/response shapes). LLMs drift if the interface is fuzzy.
---