jasonlooked #1

Merged
eros merged 21 commits from jasonlooked into main 2026-07-11 10:13:09 -07:00
Owner
No description provided.
eros added 5 commits 2026-07-10 20:48:39 -07:00
Add Game::process_throw to centralize throw→simulation→scoring→state flow.

Remove dead room_tx field, simplify add_player, and rename end_ends_or_continue.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Replace std::sync::Mutex with tokio::sync::Mutex; extract try_join_room, register_player, spawn_forwarder, broadcast_room_state, spawn_message_handler, remove_player.

Use Game::process_throw in the message handler.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Replace the ad-hoc StoneState | {...} union in drawStone/draw with a named DrawableStone type.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Extract mutable state from game.ts into a dedicated GameModel class to clarify data flow and state transitions.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Drop unused Game methods, Room.id field, and backend-only sheet ring constants that duplicated frontend definitions.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
eros reviewed 2026-07-10 21:57:54 -07:00
eros left a comment
Author
Owner

zoom out a bit so you can see the sidelines. the backline of the house only needs to be visible just above the controls

zoom out a bit so you can see the sidelines. the backline of the house only needs to be visible just above the controls
@ -24,7 +24,13 @@ pub struct Game {
stones_red: u8,
Author
Owner

don't specify stone color here, just team1 or team2, allow generalizability to choose colors. for now we will default to red and yellow

don't specify stone color here, just team1 or team2, allow generalizability to choose colors. for now we will default to red and yellow
Author
Owner

instead of a score. call it scoreboard. for each end, specify team with hammer, score for team1, score for team2. show this scoreboard on the frontend. this allows the hammer and turn_team variables to go away.

instead of a score. call it scoreboard. for each end, specify team with hammer, score for team1, score for team2. show this scoreboard on the frontend. this allows the hammer and turn_team variables to go away.
@ -42,43 +48,31 @@ impl Game {
stones_red: STONES_PER_TEAM,
Author
Owner

on the frontend, use a skeumorphic HUD to display how many stones are left. for instance, at the start of the game, show 2 rows of 8 stones. a stone should be removed from the hud when it is thrown.

on the frontend, use a skeumorphic HUD to display how many stones are left. for instance, at the start of the game, show 2 rows of 8 stones. a stone should be removed from the hud when it is thrown.
@ -109,4 +97,1 @@
}
}
pub fn can_start(&self) -> bool {
Author
Owner

the game should be playable with a single player who has the capability to switch teams

the game should be playable with a single player who has the capability to switch teams
@ -183,4 +189,1 @@
self.score_end_internal(true);
}
fn score_end_internal(&mut self, force: bool) {
Author
Owner

at the completion of an end, show a modal with the points scored, who has hammer next, and the updated scoreboard

at the completion of an end, show a modal with the points scored, who has hammer next, and the updated scoreboard
@ -112,1 +110,3 @@
}
if try_join_room(&room).await.is_err() {
let err = serde_json::to_string(&ServerMessage::Error {
message: "Room is full".to_string(),
Author
Owner

remove this, there should not be a way to have a full room. all anyone to join and choose a team. teams may have multiple clients

remove this, there should not be a way to have a full room. all anyone to join and choose a team. teams may have multiple clients
@ -188,0 +221,4 @@
.process_throw(&player_id, broom_x, broom_y, weight, curl, friction)
{
Ok(ThrowOutcome {
trajectory,
Author
Owner

this should be called trajectories since there are multiple stones moving

this should be called trajectories since there are multiple stones moving
@ -188,0 +222,4 @@
{
Ok(ThrowOutcome {
trajectory,
end_scored,
Author
Owner

instead of saying end_scored, send the scoreboard which should include this information

instead of saying end_scored, send the scoreboard which should include this information
eros reviewed 2026-07-10 22:00:19 -07:00
@ -133,3 +132,4 @@
activeStonePos: DrawableStone | null
}) => {
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
Author
Owner

draw stones animations all at the same time. not one animation after another.

draw stones animations all at the same time. not one animation after another.
Author
Owner

active stones don't need to be distinct from inactive stones. they can be all be active unless they go out of bounds

active stones don't need to be distinct from inactive stones. they can be all be active unless they go out of bounds
eros reviewed 2026-07-10 22:03:43 -07:00
eros left a comment
Author
Owner

zoom out a bit so you can see the sidelines. the backline of the house only needs to be visible just above the controls.

FEET_TO_METERS = 0.3048
make the distances which are represented as feet as FOUR_FT_RADIUS = 2 * FEET_TO_METERS

zoom out a bit so you can see the sidelines. the backline of the house only needs to be visible just above the controls. FEET_TO_METERS = 0.3048 make the distances which are represented as feet as FOUR_FT_RADIUS = 2 * FEET_TO_METERS
eros reviewed 2026-07-10 22:06:11 -07:00
@ -29,3 +35,4 @@
export interface ClientThrowMessage {
type: 'throw'
broom_x: number
Author
Owner

stone trajectory data structucture should be called trajectories with shape something like {stones: [{stoneid, rotation, team, trajectory:[x,y,theta]}])

same on the backend

stone trajectory data structucture should be called trajectories with shape something like {stones: [{stoneid, rotation, team, trajectory:[x,y,theta]}]) same on the backend
eros reviewed 2026-07-10 22:08:08 -07:00
@ -17,3 +5,4 @@
import { GameModel } from './game-model'
export function startGame(): void {
const app = document.querySelector<HTMLDivElement>('#app')!
Author
Owner

move physics parameters (friction, curl) to a dropdown menu

move physics parameters (friction, curl) to a dropdown menu
Author
Owner

the broom does not need to be constrained to the house. simplify this

the broom does not need to be constrained to the house. simplify this
eros reviewed 2026-07-10 22:13:22 -07:00
@ -259,2 +172,2 @@
if (gameState.myTeam !== gameState.turnTeam || gameState.animating || gameState.phase !== 'playing') return
sendThrow(broom.x, broom.y, velocity.getWeight(), curls.getSelected(), friction.getFriction())
if (!model.isMyTurn) return
sendThrow(model.broom.x, model.broom.y, velocity.getWeight(), curls.getSelected(), friction.getFriction())
Author
Owner

physics parameters (curl, friction). should be a shared game state.

physics parameters (curl, friction). should be a shared game state.
eros reviewed 2026-07-10 22:18:11 -07:00
@ -0,0 +72,4 @@
}
tick(now: number): DrawableStone | null {
if (!this.state.animating || this.activePath.length <= 1) {
Author
Owner

again, all stones should be animating at the synced time step

again, all stones should be animating at the synced time step
eros reviewed 2026-07-10 22:18:47 -07:00
@ -0,0 +99,4 @@
const y = p0[1] + (p1[1] - p0[1]) * t
const dx = t2[0] - t0[0]
const dy = t2[1] - t0[1]
const rotation = Math.atan2(dy, dx) * 2
Author
Owner

the rotation (theta) should come from the physics engine

the rotation (theta) should come from the physics engine
Author
Owner

physics comments:

set stone ids as (team, stone_number)
the back and sidelines should not be colliders because stones are out as soon as they touch those boundaries
stop scaling the weight, just use initial velocity (keep the test that determines the velocity to reach the hogline)
handle angular velocity in the physics engine. it should be linearly damped proportional to speed (lower speed, more friction). the starting angular velocity should be 5rot/14sec
a clockwise rotation should move right, the lateral velocity should be proportional to forward speed. (lower speed, more lateral velocity)

the friction setting should be a scalar multiplied by the following
interpolate the following for speed vs. friction

"speed (m/s)" "friction coefficient"
0 0.016
0.1482 0.014
0.3005 0.0116
0.4486 0.0098
0.7371 0.0079
1.0098 0.0073

=2.5 0.0081

physics comments: set stone ids as (team, stone_number) the back and sidelines should not be colliders because stones are out as soon as they touch those boundaries stop scaling the weight, just use initial velocity (keep the test that determines the velocity to reach the hogline) handle angular velocity in the physics engine. it should be linearly damped proportional to speed (lower speed, more friction). the starting angular velocity should be 5rot/14sec a clockwise rotation should move right, the lateral velocity should be proportional to forward speed. (lower speed, more lateral velocity) the friction setting should be a scalar multiplied by the following interpolate the following for speed vs. friction "speed (m/s)" "friction coefficient" 0 0.016 0.1482 0.014 0.3005 0.0116 0.4486 0.0098 0.7371 0.0079 1.0098 0.0073 >=2.5 0.0081
eros added 16 commits 2026-07-11 10:08:35 -07:00
Clients send team on throw; joined no longer assigns a fixed slot team.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Collision playback needs all stones sampled on a shared t=0 release clock.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Anyone identifying as the turn team can throw; room slots for 1v1 removed.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Anyone may join and watch/throw; game auto-starts on first connection.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked

Co-authored-by: Sisyphus <sisyphus@ohmyopenagent.com>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
House radius (12ft diameter -> 6ft radius), button (6in -> 0.5ft), four-ft, eight-ft, twelve-ft radii now computed at compile time from FEET_TO_METERS = 0.3048.

Ultraworked + Co-authored-by
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
eros merged commit d631af71dc into main 2026-07-11 10:13:09 -07:00
eros deleted branch jasonlooked 2026-07-11 10:13:09 -07:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eros/curltastic#1
No description provided.