`applyCmds`'s handler for `a === "add_card"` in `stage.html` hardcodes the spawn position for every non-hand card:
```js
it.x = innerWidth * 0.5; it.y = innerHeight * 0.4;
```
Extra keys in the payload are passed through to the client, which ignores them.
I also checked the other allowed verbs (`yank`, `hover`, `present`, `explode`/`assemble`, etc.) — none of them can reposition an existing item by title after the fact either.
Impact: anything driving the board that fires more than one `add_card` in a row stacks every card in the exact same spot. You have to manually drag each one apart before you can read them.
The fix is small. Read optional `x`/`y` (0..1 fractions of the viewport — matches the convention `/state` already reports item positions in) from the command, clamp to a safe on-screen range, and fall back to the current 50%/40% when neither is given, so existing callers are unaffected:
```diff
-
it.x = innerWidth * 0.5; it.y = innerHeight * 0.4;
-
const nx = typeof c.x === "number" ? c.x : 0.5;
-
const ny = typeof c.y === "number" ? c.y : 0.4;
-
it.x = Math.min(0.92, Math.max(0.08, nx)) * innerWidth;
-
it.y = Math.min(0.92, Math.max(0.08, ny)) * innerHeight;
```
Happy to open a PR with this if it's useful.
`applyCmds`'s handler for `a === "add_card"` in `stage.html` hardcodes the spawn position for every non-hand card:
```js
it.x = innerWidth * 0.5; it.y = innerHeight * 0.4;
```
Extra keys in the payload are passed through to the client, which ignores them.
I also checked the other allowed verbs (`yank`, `hover`, `present`, `explode`/`assemble`, etc.) — none of them can reposition an existing item by title after the fact either.
Impact: anything driving the board that fires more than one `add_card` in a row stacks every card in the exact same spot. You have to manually drag each one apart before you can read them.
The fix is small. Read optional `x`/`y` (0..1 fractions of the viewport — matches the convention `/state` already reports item positions in) from the command, clamp to a safe on-screen range, and fall back to the current 50%/40% when neither is given, so existing callers are unaffected:
```diff
```
Happy to open a PR with this if it's useful.