@looop-games/cli 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,142 +0,0 @@
1
- ---
2
- name: handbook
3
- description: The entry point to this game's handbook — its durable truth. Use when you need to know what this game already believes (before building, before proposing anything), and when something durable emerges that belongs in it — a design pillar, a blessed feel value, or a playtest catch that needs converting into an automated check. Also use when durable truth appears that has no chapter yet (the game's vision, its world, its cast, its economy) and one should be started.
4
- ---
5
-
6
- # /handbook — what this game knows about itself
7
-
8
- `handbook/` is this game's **durable truth**: the things a future session must
9
- not violate, and must not have to re-derive. It is the game's own layer on top
10
- of the engine's read-only craft docs — where they touch the same topic, the
11
- handbook is *this game's* answer.
12
-
13
- Three places knowledge lives here; keep them straight:
14
-
15
- | | Holds | Lifespan |
16
- |---|---|---|
17
- | **`handbook/`** | what this game IS and has decided | durable — outlives every plan |
18
- | **`notes/`** | what we're building or might build (`plans/`, `todos/`) | transient — closed when the work is |
19
- | the engine's `shared/practices/` | how Looop games are built in general | read-only, ships with the engine |
20
-
21
- The test for whether something belongs here: **would a future session need to
22
- *not violate* this?** → handbook. *Is it something we're doing, or might do?* →
23
- `notes/`.
24
-
25
- ## The chapters
26
-
27
- ```
28
- handbook/
29
- design.md the pillars — what this game IS, checked against new ideas
30
- feel.md locked feel values the creator has blessed
31
- qa.md checks this game has earned (mostly from playtests that caught something)
32
- ```
33
-
34
- **The set is open, and these three are only where it starts.** They ship with
35
- every game because every game accumulates them. They are not the limit, and they
36
- are not a template to fill in — what else a handbook holds depends entirely on
37
- what this game turns out to need. See *Starting a new chapter*.
38
-
39
- ## Reading it — do this before you build
40
-
41
- **`ls handbook/` and read what's relevant before writing game code or proposing
42
- a direction.** Every chapter opens with a line saying what it's for, so the
43
- folder listing plus the first two lines of each file is a cheap orientation.
44
- Reading is free; contradicting the handbook and being caught later is not.
45
-
46
- If what you're about to propose **contradicts something the handbook already
47
- says**, that is not a detail to smooth over — stop and say so. Either the idea is
48
- wrong, or what's written is out of date and the creator needs to say so out loud.
49
- Never quietly build against it.
50
-
51
- An empty chapter is honest — an early game hasn't decided much yet, and a
52
- speculative pillar nobody has lived is worse than none.
53
-
54
- ## Growing it
55
-
56
- **Every handbook write needs the creator's approval first.** The handbook is
57
- *their* game's truth — propose the exact entry ("I'd like to record: …") and
58
- write it only after they say yes. Never slip an entry in as a side effect of
59
- other work. (Smoke/test FILES don't need this gate — they're regression tests,
60
- not blessed truth; only `handbook/` writes do.)
61
-
62
- ### A design principle emerged → `handbook/design.md`
63
-
64
- When a decision reveals what this game IS ("never text tutorials — the world
65
- teaches", "death must always be the player's fault"), write the pillar down.
66
- Future builds check new ideas against these.
67
-
68
- ### A playtest caught a defect → an automated check
69
-
70
- The premise (from the engine's `shared/practices/qa.md`): **a human catching a
71
- defect means an automated check was missing.** Convert the *class* of defect,
72
- not the instance:
73
-
74
- 1. Name the miss precisely — not "the door was broken" but "doors can lose
75
- their collision when the room resets, and nothing checks collision after a
76
- reset."
77
- 2. Prefer an **executable check**: write a `<aspect>.smoke.mjs` (or
78
- `*.test.mjs`) that reproduces the defect — confirm it fails RED on the
79
- broken state, then goes green on the fix. `npx looop test` discovers it
80
- forever after; a guard you never saw fail is a guard you can't trust.
81
- 3. **If the check needs to SEE the game's internals** (collision boxes, depth
82
- order, hit areas) and the game has no debug overlay yet, **build one as part
83
- of the conversion** — a keyboard-toggled draw of the real boxes/order. It's
84
- a small one-time cost, and every later screenshot-verify reuses it (master
85
- list row R2).
86
- 4. Only if it truly can't be executed (needs human perception), add it as a
87
- procedural step in **`handbook/qa.md`** — `/qa` runs those by hand each time.
88
-
89
- ## Starting a new chapter
90
-
91
- The four standing chapters won't fit everything. When durable truth appears
92
- that belongs in none of them, **start a chapter** — that is the handbook
93
- working as intended, not a special case.
94
-
95
- A subject earns a chapter when it is: **durable** (it outlives the current
96
- plan), **referred back to** (future sessions need it to stay consistent), and
97
- **not a fit** for an existing chapter. It can be anything this game actually
98
- needs: `vision.md` (what the game is *for*, once the creator has said it out
99
- loud), `world.md` (a setting an agent must not contradict), `characters.md`,
100
- `economy.md` (numbers that have to balance), `controls.md`. Don't shop from that
101
- list — reach for whatever this game keeps needing to remember.
102
-
103
- To start one:
104
-
105
- 1. **Propose it** — the name, and the exact first entry. Same approval gate as
106
- any handbook write; creating a chapter is a bigger act than adding a line,
107
- not a smaller one.
108
- 2. Create `handbook/<subject>.md` with the standard shape:
109
-
110
- ```markdown
111
- # <Subject> — <what this chapter is for, in half a line>
112
-
113
- <One or two sentences: what belongs here, what doesn't.>
114
-
115
- ## YYYY-MM-DD — <the entry>
116
- <The truth itself. Short. Actionable cold, by someone who wasn't there.>
117
- ```
118
-
119
- 3. Don't pre-create chapters "in case", and don't propose one because the game
120
- "ought to" have it. An empty speculative chapter is a trap — it invites
121
- invented content, and a creator filling in a template is not the same as a
122
- creator telling you something true. A chapter starts the day it has something
123
- true to hold.
124
-
125
- ## The upstream half
126
-
127
- Before writing, ask: **is this lesson specific to this game, or would every
128
- Looop game want it?** A generic hole (an engine component that breaks a
129
- universal expectation, a check every game should run) belongs in the engine's
130
- master list, not just this repo — offer `/feedback` so it lands upstream for
131
- everyone. Do both when in doubt: the handbook entry protects this game now; the
132
- feedback fixes it everywhere later.
133
-
134
- ## Rules
135
-
136
- - **One lesson per invocation, converted fully** — an entry someone can act on
137
- cold, not a vague reminder.
138
- - **Date entries.** When a later decision supersedes one, update it **in place**
139
- rather than stacking contradictions — a handbook that argues with itself is
140
- worse than no handbook, because a future session will pick the wrong side.
141
- - **Short.** Every line in here is read by every future session. It earns its
142
- place or it goes.
@@ -1,53 +0,0 @@
1
- ---
2
- name: qa
3
- description: Verify the current change — run every automated check that applies and hand the creator only the shortest possible list of things that genuinely need human eyes. Use when the creator asks "does it work?", before any playtest handback, or whenever work is about to be called done.
4
- ---
5
-
6
- # /qa — run the game's checks, hand back only what needs a human
7
-
8
- The QA framework lives in ONE place: the engine's master doc at
9
- `node_modules/@looop-games/engine/shared/practices/qa.md` — what counts as an
10
- **automated** step (you run it, you report it) vs a **manual** one (only the
11
- creator can judge it), the ratchet, and the master steps list. **Read it
12
- first, every time. This skill is the procedure; the steps live there.**
13
-
14
- The governing rule (from that doc): **maximize automated, drive manual toward
15
- zero.** Anything you *can* run, you run and report — it never goes on the
16
- creator's list.
17
-
18
- ## The three sources of checks (merge all three)
19
-
20
- 1. **Executable checks — `npx looop test`.** Discovers and runs every
21
- `*.test.mjs` and `*.smoke.mjs` in this folder against a real dev stack.
22
- The files ARE the list; always the whole gate, not just new tests.
23
- 2. **This game's earned checks — `handbook/qa.md`.** Procedural steps this
24
- specific game accumulated (past playtest catches, fragile spots).
25
- 3. **The engine master list** — the doc above. Generic steps every Looop game
26
- is checked against.
27
-
28
- ## Procedure
29
-
30
- 1. **Scope the change** — which surfaces did it touch? That selects which
31
- master-list rows and handbook steps apply.
32
- 2. **Run every automated step that applies**, from all three sources. Where
33
- the master doc calls for fresh reviewer or adjudicator sub-agents, spawn
34
- them yourself with the briefs it describes.
35
- 3. **Report results concretely** — how you verified, not "tested": suite
36
- counts, which URL you drove, what the screenshot showed, findings resolved.
37
- 4. **Emit the minimal human list.** Only feel/look/judgment items and things
38
- you genuinely couldn't verify — each against a game that is **already
39
- running** (start or reuse the dev stack yourself; the creator gets the
40
- URL to open, never a command to run). If everything was automatable, say
41
- so plainly; "couldn't test it" must never read as "tested and fine".
42
- 5. **Close the ratchet.** If the creator's pass catches something your run
43
- missed, that's a hole in the checks — run `/handbook` to convert
44
- that defect class into an automated check.
45
-
46
- ## Notes
47
-
48
- - `/qa` verifies; it never commits or publishes.
49
- - Smokes drive a real browser with Playwright — **already in this repo's
50
- devDependencies** (`looop create` ships it and pre-fetches Chromium, and
51
- `looop test` re-fetches the browser if the cache was pruned). Only a repo
52
- scaffolded before playwright shipped needs the one-time
53
- `npm i -D playwright && npx playwright install chromium`.
@@ -1,54 +0,0 @@
1
- ---
2
- name: todo
3
- description: Capture a bug, idea, or improvement for later without acting on it now. Use when the creator (or you, mid-build) spots something worth remembering — "we should fix that jump later", "idea — a boss level", "note that down" — and when they want to see what's captured or start work on one.
4
- ---
5
-
6
- # /todo — capture now, decide later
7
-
8
- A **todo** is the one lightweight capture type in this repo: bug, idea,
9
- improvement — all the same thing until someone decides to act. Capturing must
10
- be nearly free; never derail the current work to file one.
11
-
12
- ## Capture
13
-
14
- Write one small file per todo at `notes/todos/<YYYY-MM-DD-HHMM>-<short-slug>.md`
15
- (creation datetime first, always — the whole `notes/` tree names files this way
16
- so they list in order):
17
-
18
- ```markdown
19
- ---
20
- status: open # open | done | promoted | abandoned
21
- created: YYYY-MM-DD
22
- ---
23
- # <One-line summary>
24
-
25
- What was seen / imagined, in a couple of sentences. Enough that a future
26
- session understands it cold. Reference files by path if relevant.
27
- ```
28
-
29
- Then get back to what you were doing. If the creator says something mid-build
30
- that is clearly a "later" item, offer to capture it in one line — don't stop
31
- the milestone.
32
-
33
- ## Browse
34
-
35
- "What's on the list?" → read `notes/todos/`, summarize the open ones in a few
36
- lines each. Group bugs vs ideas by content, not by folder — there is
37
- deliberately only one folder.
38
-
39
- ## Promote
40
-
41
- When the creator decides to actually DO a todo, it becomes a **plan**: start
42
- `/build`, which creates the plan in `notes/plans/` through its discussion
43
- phase, seeded from the todo's content. Mark the todo `status: promoted` with a
44
- line pointing at the plan file. Small fixes don't need promotion — just do
45
- them and mark the todo `done`.
46
-
47
- ## Rules
48
-
49
- - Never delete a todo — mark it `done` (with a line saying what happened),
50
- `promoted`, or — when the creator decides NOT to do it — `abandoned` **with
51
- a one-line why**. The why is the value: it saves re-deciding the same thing
52
- next month. "Won't do" and "did it" must never collapse into one status.
53
- - A todo about **Looop itself** (the engine, the CLI, the platform — not this
54
- game) is `/feedback`'s job, not a todo.
@@ -1,74 +0,0 @@
1
- ---
2
- name: update-looop
3
- description: Update Looop itself — the engine, and the skills and instructions this repo runs on. Use when the creator asks for the latest Looop ("is there an update?", "update looop", "get the newest version"), when a Looop feature they've heard about is missing, or when something looks like a Looop bug that may already be fixed. Not for updating their GAME — that's just building.
4
- ---
5
-
6
- # /update-looop — get the latest Looop, and explain what changed
7
-
8
- `npx looop update` moves this game to the newest Looop release. It is the **only**
9
- command that writes to Looop's files inside this repo — `dev` and `publish` never
10
- do. That is deliberate: an update is something the creator *asks* for.
11
-
12
- But it does write into **their** repo. After it runs, `git status` shows changes
13
- they did not make. **Your job is to make sure that is never a surprise.**
14
-
15
- ## Before
16
-
17
- Tell them what an update touches, in one or two sentences:
18
-
19
- - **The engine** — the game code they import from (`/shared/...`). Their game
20
- keeps running on the old engine until they publish again, so an update is safe
21
- to take at any time.
22
- - **The skills and instructions** — the files in `.claude/skills/` and the Looop
23
- section of `AGENTS.md`. These are Looop's, living in their repo.
24
- - **Never their game.** Not `index.html`, not `game.js`, not `handbook/`, not
25
- `notes/`. And never a skill they wrote, or an edit they made to one of ours —
26
- where they've changed something, their version wins and the update says so.
27
-
28
- If they have uncommitted work, say so first — the update's changes will land
29
- alongside it, and a mixed diff is harder to read. Offer to save theirs first.
30
-
31
- ## Run it
32
-
33
- ```bash
34
- npx looop update
35
- ```
36
-
37
- It prints exactly what it did: every file updated, every file removed, and every
38
- file it **kept because the creator had changed it**. Read that output — it is the
39
- source of truth for the next step, not your assumptions about what a release
40
- contains.
41
-
42
- ## After — the part that matters
43
-
44
- **Report the change in their terms, not ours.** Don't paste the file list back at
45
- them; tell them what is now different about what you and they can do:
46
-
47
- > *"Looop updated to engine 0.1.8. The `/update-handbook` skill was replaced by a
48
- > broader `/handbook` — same job, plus it now keeps your game's vision and design
49
- > pillars. Your own `/my-thing` skill was left alone."*
50
-
51
- Then **offer the commit** — never run it unasked:
52
-
53
- > *"That changed 3 of Looop's files in your repo. Want me to save them?
54
- > (`git add -A && git commit -m "update Looop to engine 0.1.8"`)"*
55
-
56
- Two things to volunteer without being asked:
57
-
58
- - **If they'd edited a Looop file**, the update kept *their* version and did not
59
- apply ours. Say which file, and that they may want to re-apply their change on
60
- top of the new one — otherwise they'll silently miss the update to that file
61
- forever.
62
- - **If the update mentions a backup folder** (`.looop/backup-<version>/`), that
63
- is the pre-update copy of files whose history we couldn't be sure of. Tell them
64
- it exists. They can delete it once they're happy.
65
-
66
- ## Rules
67
-
68
- - **Never run `looop update` as a side effect of something else.** It is its own
69
- act, with its own consent. If a bug looks like it might already be fixed
70
- upstream, *propose* the update — don't just do it mid-build.
71
- - **Never commit on their behalf** without asking, even when the only changes are
72
- Looop's own files. It is their repo and their history.
73
- - The live game at `play.looop.games` does **not** change until they run
74
- `npx looop publish`. Say so — creators reasonably assume an update is live.
@@ -1,93 +0,0 @@
1
- # {{name}} — a Looop game
2
-
3
- <!-- looop:managed:start -->
4
- <!-- Everything between the looop:managed markers belongs to the Looop
5
- platform and is REWRITTEN when the engine updates. Add your own
6
- instructions BELOW the end marker — updates never touch them. -->
7
-
8
- This folder is a standalone Looop game. You (the agent) build it for a person
9
- who is probably **not a developer** — the "creator". They describe the game in
10
- plain language and make the judgment calls; you own everything else: process,
11
- code, and verification. They should never need to learn git, npm, or servers.
12
-
13
- ## Where things go
14
-
15
- The workflows live as **skills** in `.claude/skills/` (aliased at
16
- `.agents/skills/` — same files); each skill's `description` says when it
17
- applies. This table routes only what has no skill:
18
-
19
- | The creator wants… | Do this |
20
- |---|---|
21
- | To "save my work" | `git add -A && git commit` (and push, if the repo has a remote). Saving is local; it is **not** publishing. |
22
- | To update Looop / the engine | `/update-looop`. It is the ONLY thing that writes Looop's files into this repo (`.claude/skills/`, the managed block of this file) — `dev` and `publish` never do, so an update is never a surprise in their git. The live game changes only on the next publish. |
23
- | Better game feel (tuning speeds, jumps, timings) | The engine's **tweaks** library (`node_modules/@looop-games/engine/shared/ui/tweaks/`) + `shared/practices/feel.md`. |
24
- | To change how an engine file behaves | Copy it to `overrides/shared/<same path>` and edit the copy — dev and publish serve your override instead of the official module. Imports stay `/shared/...`; never rewrite them. An override is a fork: that file stops receiving engine updates until you re-port it. |
25
-
26
- ## Commands (run from this folder)
27
-
28
- - `npx looop dev` — the full local stack: the game at
29
- http://localhost:8000/games/{{name}}/index.html, multiplayer on :1999,
30
- platform services (LLM etc.) on :8788. Leave it running; edits hot-reload.
31
- **On a new machine the first `dev` signs the creator in: a browser window
32
- opens, they log in and click Approve (~30 seconds, once per machine). Tell
33
- them it's coming BEFORE you run it** — an unexplained browser popup mid-build
34
- reads as something going wrong.
35
- - `npx looop test` — the per-change gate: runs every `*.test.mjs` (unit, under
36
- node) and every `*.smoke.mjs` (against a real dev stack it boots itself on
37
- free ports) in this folder.
38
- - `npx looop login` — connect this machine to the creator's Looop account
39
- (once per machine; the first `looop dev` runs it automatically).
40
- - `npx looop publish` — ship to https://play.looop.games/g/{{name}}.
41
- **The first publish permanently claims the name `{{name}}` for the creator's
42
- account** — from then on only they can update it. `--slug <alt>` publishes an
43
- A/B copy without touching the live game.
44
-
45
- ## The rules that are physics (not preference)
46
-
47
- 1. **Multiplayer-first.** Any state other players can see (positions, physics,
48
- scores, world objects) rides the room's authority — `room.update(...)`,
49
- `room.send('input', ...)` — never local mutation only one client sees.
50
- Verify multiplayer behaviour with TWO browser contexts, not one.
51
- 2. **The engine is read-only — and it is not the ceiling.** `/shared/...`
52
- imports come from the installed engine at `node_modules/@looop-games/engine`
53
- (not an npm dependency — `looop dev` downloads the version pinned in
54
- `package.json`'s `looop.engine` and reinstalls it if an `npm install` prunes
55
- it). Never edit files in `node_modules` — use `overrides/shared/` (see the
56
- table above). But read-only means *don't edit it*, **not** *don't exceed
57
- it*: a Looop game is a web page, so **anything the browser can do, this game
58
- can do.** The library is a bag of conveniences you draw from, not a fence
59
- around what the game may be — what it doesn't have, you build, here in the
60
- game folder. **Never tell the creator that Looop "can't" do something**
61
- (see `/engine` — it is almost always false, and it retires their idea
62
- without their consent).
63
- 3. **Never hand-roll a server.** Only `looop dev` (or `looop test`) serves
64
- this game: they alias `/shared/...` and inject the platform layer. A plain
65
- static server 404s every engine import and the game silently never boots.
66
- 4. **Never handle tokens or keys.** Login is a browser device flow; platform
67
- services (LLM etc.) are already wired through the local shim. If something
68
- seems to need an API key, you're on the wrong path.
69
- 5. **Read what's already known before writing game code.** First this game's
70
- own **`handbook/`** (its locked truths — qa.md, feel.md, design.md), then
71
- the engine craft docs at
72
- `node_modules/@looop-games/engine/shared/practices/` — `feel.md`,
73
- `architecture.md`, `multiplayer.md`, `qa.md` (and `eval.md` when anything
74
- is LLM-generated), which apply to every game.
75
- The handbook augments the generic docs; where they touch the same topic,
76
- the handbook is this game's answer.
77
- 6. **Anything with an assertion is a regression test.** Playwright checks live
78
- in `<aspect>.smoke.mjs` files (excluded from publish, discovered by
79
- `looop test`). Keep them; delete only assertion-free scratch.
80
-
81
- ## This repo's own knowledge
82
-
83
- - **`handbook/`** — durable truth about THIS game: `qa.md` (its checks),
84
- `feel.md` (locked feel values), `design.md` (its pillars). Consult it before
85
- working; grow it with `/handbook`.
86
- - **`notes/`** — work tracking: `notes/plans/` (what's being built — `/build`
87
- runs from these), `notes/todos/` (captured bugs/ideas), and
88
- `notes/feedback/` (reports for the Looop team, written by `/feedback`).
89
- Nothing under `notes/` is ever published.
90
-
91
- <!-- looop:managed:end -->
92
-
93
- <!-- Your own instructions go below this line. -->
@@ -1,4 +0,0 @@
1
- @AGENTS.md
2
-
3
- (If your tool didn't inline the line above: read AGENTS.md — it is this
4
- project's agent instructions.)
@@ -1,4 +0,0 @@
1
- @AGENTS.md
2
-
3
- (If your tool didn't inline the line above: read AGENTS.md — it is this
4
- project's agent instructions.)
@@ -1,21 +0,0 @@
1
- // Boot smoke — the game's first regression test, shipped with the scaffold.
2
- // Proves the dev stack serves the game page AND the engine alias (a plain
3
- // static server would 404 every /shared/... import and the game would
4
- // silently never boot). Runs under `npx looop test`, which boots a real dev
5
- // stack and exports its URL. Grow your own checks as `<aspect>.smoke.mjs`
6
- // files next to this one.
7
- const url = process.env.LOOOP_TEST_GAME_URL || process.env.URL;
8
- if (!url) {
9
- console.error('boot smoke: no game URL — run this via `npx looop test`.');
10
- process.exit(1);
11
- }
12
-
13
- const page = await fetch(url);
14
- if (!page.ok) throw new Error(`game page: ${page.status} for ${url}`);
15
- if (!(await page.text()).includes('<canvas')) throw new Error('game page served, but no canvas in it');
16
-
17
- const engineModule = new URL('/shared/ui/room/client.js', url);
18
- const engine = await fetch(engineModule);
19
- if (!engine.ok) throw new Error(`engine alias broken: ${engineModule.pathname} → ${engine.status}`);
20
-
21
- console.log('boot smoke: game page + engine alias OK');
package/template/game.js DELETED
@@ -1,53 +0,0 @@
1
- // A tiny multiplayer plaza — walk around, see everyone else.
2
- // This is a REAL Looop game: it already syncs across browsers and works
3
- // published. Reshape it into your game; the room + identity plumbing stays.
4
- import { createRoom, getIdentity } from '/shared/ui/room/client.js';
5
-
6
- const me = getIdentity(); // injected by the platform (fails closed if absent)
7
- const canvas = document.getElementById('game');
8
- const ctx = canvas.getContext('2d');
9
- const size = () => { canvas.width = innerWidth; canvas.height = innerHeight; };
10
- addEventListener('resize', size); size();
11
-
12
- const self = { name: me.name, color: me.color, x: Math.random() * 400 - 200, y: Math.random() * 400 - 200 };
13
- // One room per game: the slug (injected by the serve path) is the room id.
14
- const room = createRoom({ room: window.GAME_SLUG ?? 'dev', self });
15
-
16
- let others = new Map();
17
- room.onPlayers = (players) => { others = new Map(players); };
18
- // Handy for smokes: how many players does this client see (self included)?
19
- window.__looopPlayers = () => others.size + 1;
20
-
21
- const keys = new Set();
22
- addEventListener('keydown', (e) => keys.add(e.key.toLowerCase()));
23
- addEventListener('keyup', (e) => keys.delete(e.key.toLowerCase()));
24
-
25
- const SPEED = 220; // px/s — tune the feel!
26
- let last = performance.now();
27
- function tick(now) {
28
- const dt = Math.min((now - last) / 1000, 0.05); last = now;
29
- const dx = (keys.has('d') || keys.has('arrowright')) - (keys.has('a') || keys.has('arrowleft'));
30
- const dy = (keys.has('s') || keys.has('arrowdown')) - (keys.has('w') || keys.has('arrowup'));
31
- if (dx || dy) {
32
- const n = Math.hypot(dx, dy);
33
- self.x += (dx / n) * SPEED * dt;
34
- self.y += (dy / n) * SPEED * dt;
35
- room.update({ x: self.x, y: self.y });
36
- }
37
-
38
- ctx.fillStyle = '#0f1220';
39
- ctx.fillRect(0, 0, canvas.width, canvas.height);
40
- const cx = canvas.width / 2, cy = canvas.height / 2;
41
- const drawAvatar = (p) => {
42
- ctx.fillStyle = p.color ?? '#888';
43
- ctx.fillRect(cx + (p.x ?? 0) - self.x - 14, cy + (p.y ?? 0) - self.y - 14, 28, 28);
44
- ctx.fillStyle = '#e7e9f4';
45
- ctx.font = '12px system-ui';
46
- ctx.textAlign = 'center';
47
- ctx.fillText(p.name ?? '?', cx + (p.x ?? 0) - self.x, cy + (p.y ?? 0) - self.y - 22);
48
- };
49
- for (const p of others.values()) drawAvatar(p);
50
- drawAvatar(self);
51
- requestAnimationFrame(tick);
52
- }
53
- requestAnimationFrame(tick);
@@ -1,2 +0,0 @@
1
- node_modules/
2
- .looop/
@@ -1,8 +0,0 @@
1
- # Design — the pillars
2
-
3
- The rules that follow from the vision: the principles new ideas get checked
4
- against. Written as
5
- they emerge from real decisions (via `/handbook`), not invented up
6
- front — an empty file is honest; a speculative pillar is a trap.
7
-
8
- _No pillars yet._
@@ -1,8 +0,0 @@
1
- # Feel — locked values
2
-
3
- Feel calls the creator has blessed: the value, where it lives, and why it's
4
- right — so no future session "improves" them away. General feel craft lives in
5
- the engine's `shared/practices/feel.md`; this file is only what THIS game has
6
- locked. `/handbook` adds entries.
7
-
8
- _Nothing locked yet._
@@ -1,9 +0,0 @@
1
- # QA — this game's own checks
2
-
3
- Checks THIS game has earned, on top of the engine's master list
4
- (`node_modules/@looop-games/engine/shared/practices/qa.md`) and the executable
5
- tests `npx looop test` discovers. `/qa` runs all three sources; `/handbook`
6
- adds entries here when a playtest catches something no automated check saw —
7
- but prefer writing a `*.smoke.mjs` when the check can be executed.
8
-
9
- _No game-specific checks yet. The first playtest catch starts this list._
@@ -1,26 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <!-- Mobile baseline (engine practices, architecture.md): locked viewport,
6
- no double-tap/pinch zoom, no text selection on game UI. Required on
7
- every Looop game — keep all four pieces when reshaping this file. -->
8
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
9
- <title>{{name}}</title>
10
- <style>
11
- html, body { margin: 0; height: 100%; background: #0f1220; overflow: hidden; touch-action: manipulation; }
12
- * { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
13
- input, textarea, [contenteditable] { -webkit-user-select: text; user-select: text; }
14
- canvas { display: block; width: 100vw; height: 100vh; }
15
- </style>
16
- <script>
17
- // Safari ignores user-scalable=no — block iOS gesture-zoom too.
18
- for (const ev of ['gesturestart', 'gesturechange', 'gestureend'])
19
- document.addEventListener(ev, (e) => e.preventDefault());
20
- </script>
21
- </head>
22
- <body>
23
- <canvas id="game"></canvas>
24
- <script type="module" src="game.js"></script>
25
- </body>
26
- </html>