Initial commit: GSPro Remote MVP - Phase 1 complete
This commit is contained in:
commit
74ca4b38eb
50 changed files with 12818 additions and 0 deletions
191
Recommended kickoff plan.md
Normal file
191
Recommended kickoff plan.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
# 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 you’ll 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). It’s 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, \~75–85 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.
|
||||
|
||||
---
|
||||
Loading…
Add table
Add a link
Reference in a new issue