fuzzyworld

bubbles / files / .github / copilot-instructions.md

copilot-instructions.md

2.7 KB · history · blame


applyTo: "**"

Bubbles — Copilot Instructions

Project Overview

Silly web app: phone becomes a water glass. Canvas 2D physics, no framework, no server. Hosted on GitLab Pages. TypeScript + Vite + pnpm.

Hard Rules

Architecture

src/physics/    — pure simulation (no DOM, no canvas)
src/rendering/  — Canvas 2D drawing only (reads from physics, never writes)
src/input/      — DOM event adapters that produce values (no side effects on world directly)
src/icons/      — static data (icon registry)
src/App.ts      — game loop: wires physics ← input, renderer ← physics
src/main.ts     — DOM entry point only
scripts/        — Node.js tooling (sharp asset pipeline)

Physics Conventions

Rendering Conventions

Input Conventions

File Conventions

Source
1---
2applyTo: "**"
3---
4
5# Bubbles — Copilot Instructions
6
7## Project Overview
8Silly web app: phone becomes a water glass. Canvas 2D physics, no framework, no server.
9Hosted on GitLab Pages. TypeScript + Vite + pnpm.
10
11## Hard Rules
12- **No UI framework** (no React, Vue, Svelte, etc.) — vanilla TypeScript only.
13- **Canvas 2D only** — no WebGL, no Three.js, no PixiJS.
14- **pnpm only** — never suggest npm or yarn commands.
15- **No server** — everything must work as a static site.
16- **`strict: true`** TypeScript — no `any` without explicit justification.
17
18## Architecture
19```
20src/physics/ — pure simulation (no DOM, no canvas)
21src/rendering/ — Canvas 2D drawing only (reads from physics, never writes)
22src/input/ — DOM event adapters that produce values (no side effects on world directly)
23src/icons/ — static data (icon registry)
24src/App.ts — game loop: wires physics ← input, renderer ← physics
25src/main.ts — DOM entry point only
26scripts/ — Node.js tooling (sharp asset pipeline)
27```
28
29## Physics Conventions
30- Coordinates: canvas space, origin top-left, +Y downward.
31- Units: pixels for distance, seconds for time, px/s for velocity, px/s² for acceleration.
32- `g ≈ 980 px/s²` (treats 100 px ≈ 1 metre).
33- `Water` simulation approach is open — column-based, SPH particles, or any other model that runs well on mobile Canvas 2D.
34- Prefer approaches that stay ≥ 30fps on a mid-range phone; profile before committing to a heavier model.
35- max 12 `RigidBody` objects by default; `World.addBody()` enforces this by dropping oldest non-permanent.
36- Fixed physics timestep: `1/60` s (set in `App.ts`).
37- Container is **sealed** — no spilling, volume is always conserved.
38- Gravity is a full 360° `Vector2` (device beta + gamma via `TiltInput`). Buoyancy, constraints, and `Water.getSurfaceY()` all work correctly when the phone is upside-down (`water.isFlipped`).
39
40## Rendering Conventions
41- `Renderer` always draws in this order: clear → glass clip → water → icons → glass outline.
42- Shimmer and refraction are animated via `WaterRenderer.update(dt)` — call every frame.
43- Emoji rendered with `ctx.fillText` — never rasterise to offscreen canvas unless profiling shows it's needed.
44
45## Input Conventions
46- `TiltInput`: pure producer of a `gravity: Vector2` — no direct world mutation.
47- `TouchInput`: spawns `RigidBody` via `World.addBody()` — the only input that mutates world state.
48- iOS orientation permission must be requested inside a user-gesture handler.
49
50## File Conventions
51- One class per file, filename matches class name.
52- Physics files import from `./Vector2.js` etc. (`.js` extension required for ESM bundler resolution).
53- No barrel (`index.ts`) files — import directly.