Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
c75d7af
added pipelines
clragon Feb 14, 2026
5d42d8d
added new game engine (wip)
clragon Jun 23, 2025
304ac7b
added scheduler plugin (wip)
clragon Jun 23, 2025
b5425ad
fixed context unwrapping
clragon Jun 23, 2025
58ee838
fixed scheduling
clragon Jun 23, 2025
781b29b
removed failed files
clragon Jun 23, 2025
b9af4c6
added note about scheduling
clragon Jun 23, 2025
4c0454a
updated scheduling to use action system
clragon Jun 23, 2025
00334c4
updated messages to use action system
clragon Jun 23, 2025
fe1c49f
renamed actions to events
clragon Jun 24, 2025
85b080c
updated composer dsl
clragon Jun 27, 2025
2a9b38f
rewrote messages to use scheduling
clragon Jun 27, 2025
e1be4c1
fixed updating messages preserving index
clragon Jun 27, 2025
ec067de
added composer shortcuts for simple pipes
clragon Jun 27, 2025
6b929c5
removed apply in favour of pipe
clragon Jun 28, 2025
b4d30ed
restored message ui
clragon Jun 28, 2025
e45ab5a
added use game context
clragon Jun 28, 2025
68943a3
improved composer.bind ease of use
clragon Jun 29, 2025
a34abd7
improved composer.chain ease of use
clragon Jun 29, 2025
a023034
fixed old lens Path usage
clragon Jun 29, 2025
2f3e8c9
improved event handle typing
clragon Jun 29, 2025
6010528
added intensity pipe
clragon Jun 29, 2025
88bfb9a
ignored any usage
clragon Aug 24, 2025
2c8e385
added image pipeline
clragon Aug 24, 2025
194f8bb
moved random image switching into own pipe
clragon Aug 24, 2025
45ccfd6
added game phase pipe
clragon Aug 24, 2025
7cdd531
improved fps display
clragon Aug 24, 2025
ab547ac
added warump pipe
clragon Aug 24, 2025
6dc483f
improved composer dsl
clragon Aug 25, 2025
bfe55f0
improved static composer functions
clragon Aug 25, 2025
e9e85b0
made intensity phase aware
clragon Aug 25, 2025
c6f2e4d
added pace pipe
clragon Aug 25, 2025
d7da1fa
added tests
clragon Nov 2, 2025
04fa5f2
added plugin system
clragon Feb 11, 2026
d00d380
added imperative composer api
clragon Feb 11, 2026
1658349
added some guard rails to imperative composer
clragon Feb 11, 2026
75225f9
added else to when
clragon Feb 12, 2026
620d559
added typed paths to composer
clragon Feb 12, 2026
6465d22
improved plugin system
clragon Feb 12, 2026
c184c2f
added pause plugin
clragon Feb 13, 2026
d211e0c
added global sdk object for plugins
clragon Feb 13, 2026
f1a9214
added performance monitoring
clragon Feb 13, 2026
ec4c9c7
moved game pips to plugins
clragon Feb 13, 2026
afbef40
removed deep cloning
clragon Feb 13, 2026
2803a77
added expiration to performance overlay
clragon Feb 13, 2026
ce22e70
added remaining game features (wip)
clragon Feb 13, 2026
fbf840a
added event sequencer
clragon Feb 13, 2026
5c73e6f
improved performance monitor
clragon Feb 13, 2026
cf906dd
removed pause button
clragon Feb 14, 2026
fc50929
fixed unpausing the game
clragon Feb 14, 2026
58a4934
moved messaging to plugin
clragon Feb 14, 2026
8f5caad
removed old fps pipe
clragon Feb 14, 2026
9526307
moved completing dice state into dealer
clragon Feb 14, 2026
e72e603
added freezing game on tab or minimize
clragon Feb 14, 2026
5f94b8e
applied formatter
clragon Feb 14, 2026
00a3874
improved performance and typing of state access in ui
clragon Feb 14, 2026
47d8967
optimized composer invocations
clragon Feb 14, 2026
6ca40a4
removed old gamepace component
clragon Feb 14, 2026
833fa5b
deleted context api injections in favour of static apis
clragon Feb 14, 2026
b5d305b
refactored old pipes to use typed paths
clragon Feb 14, 2026
ceef3b9
updated event pipe dsl
clragon Feb 14, 2026
5601658
updated primitive pipes to plugin pattern
clragon Feb 14, 2026
e5a2719
applied formatting
clragon Feb 14, 2026
8160ea9
refactored performance phase parameter to freeform string
clragon Feb 14, 2026
526ebdd
added sdk.debug prop
clragon Feb 14, 2026
77df653
added types to events
clragon Feb 14, 2026
75e6622
replaced delta time with fixed ticks
clragon Feb 14, 2026
cefa79c
replaced math random with randomness plugin
clragon Feb 14, 2026
334a3d4
formatted files
clragon Feb 14, 2026
91afdb4
fixed updating game settings during live game
clragon Feb 14, 2026
8c42d33
fixed event button alignment
clragon Feb 14, 2026
6baf6e0
moved tests to their own folder
clragon Feb 14, 2026
159d2ed
extracted test utilities
clragon Feb 14, 2026
b3b025a
formatted files
clragon Feb 14, 2026
7616765
moved game engine to root
clragon Feb 14, 2026
739ad32
added pause menu
clragon Feb 14, 2026
13126ad
fixed sdk registration
clragon Feb 15, 2026
c22f0d5
formatted files
clragon Feb 15, 2026
f9103b4
added default to lens.over
clragon Feb 15, 2026
b91e837
fixed automatic unpausing
clragon Feb 15, 2026
5c6525d
fixed fps display
clragon Feb 15, 2026
80430ce
added game over screen
clragon Feb 16, 2026
469ac75
added scene plugin
clragon Feb 16, 2026
0990843
reordered plugins
clragon Feb 16, 2026
6ca0dde
formatted files
clragon Feb 16, 2026
e790053
added errors pipe primitive
clragon Feb 16, 2026
a399888
fixed perf plugin path access
clragon Feb 16, 2026
fcd8abb
formatted files
clragon Feb 16, 2026
15b470a
killed game context
clragon Feb 19, 2026
f86a154
added module manager
clragon Mar 2, 2026
9914d12
refactored plugin shape
clragon Mar 7, 2026
a5d4fb8
fixed seen images tracking using loads of space unnecessarily
clragon Mar 7, 2026
cdca970
dissolved plugin manager into plugin installer
clragon Mar 7, 2026
c5e2418
formatted files
clragon Mar 7, 2026
66263a6
updated pause timer
clragon Mar 8, 2026
1f6eb72
moved seen image tracking into random images
clragon Mar 8, 2026
6666426
fixed tests
clragon Mar 8, 2026
66427f1
refactored classic mode dealer to use modules
clragon Mar 8, 2026
e105c58
fixed b/s display
clragon Mar 8, 2026
b0cbf14
fixed flaky tests
clragon Mar 8, 2026
030eb03
improved plugin settings ui
clragon Mar 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ module.exports = {
{ allowConstantExport: true },
],
'@typescript-eslint/no-unused-vars': 'warn',
// I am going to be real with you, this pipe system is not going to be very typed.
// Lets just. put this aside for now.
'@typescript-eslint/no-explicit-any': 'off',
},
};
19 changes: 19 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Test

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'
- run: yarn install --frozen-lockfile
- run: yarn test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
coverage

# Editor directories and files
.vscode/*
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"format": "prettier --write .",
"format": "prettier --write src/ tests/",
"lint": "eslint . --ext ts,tsx --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"test": "vitest run",
"test:coverage": "vitest run --coverage"
},
"dependencies": {
"@awesome.me/webawesome": "^3.2.1",
Expand Down Expand Up @@ -54,14 +56,16 @@
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^4.0.6",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4",
"jsdom": "^27.1.0",
"prettier": "^3.2.5",
"typescript": "^5.2.2",
"vite": "^5.2.0"
"vite": "^5.2.0",
"vitest": "^4.0.6"
},
"engines": {
"node": ">=20.0.0",
Expand Down
23 changes: 15 additions & 8 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { HomePage } from '../home';
import { GamePage } from '../game';
import { EndPage } from '../end';
import { GameShell } from '../game/GameShell';
import { SceneBridge } from '../game/SceneBridge';

import '@awesome.me/webawesome/dist/styles/webawesome.css';

export const App = () => {
return (
<BrowserRouter
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path='/' element={<HomePage />} />
<Route path='/play' element={<GamePage />} />
</Routes>
</BrowserRouter>
<GameShell>
<BrowserRouter
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<SceneBridge />
<Routes>
<Route path='/' element={<HomePage />} />
<Route path='/play' element={<GamePage />} />
<Route path='/end' element={<EndPage />} />
</Routes>
</BrowserRouter>
</GameShell>
);
};
1 change: 1 addition & 0 deletions src/common/ToggleTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class JoiToggleTileElement extends LitElement {
display: block;
width: 100%;
cursor: pointer;
text-align: left;

background: var(--wa-color-neutral-fill-quiet);
opacity: var(--tile-inactive-opacity);
Expand Down
44 changes: 44 additions & 0 deletions src/end/ClimaxResult.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import styled from 'styled-components';
import { useGameFrame } from '../game/hooks';
import { climax, type ClimaxResultType } from '../game/plugins/dice/climax';

type OutcomeDisplay = { label: string; description: string };

const outcomes: Record<NonNullable<ClimaxResultType>, OutcomeDisplay> = {
climax: { label: 'Climax', description: 'You came' },
denied: { label: 'Denied', description: 'Better luck next time' },
ruined: { label: 'Ruined', description: 'How unfortunate' },
};

const earlyEnd: OutcomeDisplay = { label: 'Ended early', description: '' };

const StyledResult = styled.div`
display: flex;
flex-direction: column;
gap: 2px;
`;

const StyledLabel = styled.span`
font-size: 1.1rem;
font-weight: bold;
color: var(--text-color);
`;

const StyledDescription = styled.span`
font-size: 0.85rem;
opacity: 0.6;
`;

export const ClimaxResult = () => {
const result = useGameFrame(climax.result) as ClimaxResultType;
const display = (result && outcomes[result]) || earlyEnd;

return (
<StyledResult>
<StyledLabel>{display.label}</StyledLabel>
{display.description && (
<StyledDescription>{display.description}</StyledDescription>
)}
</StyledResult>
);
};
159 changes: 159 additions & 0 deletions src/end/EndPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import styled, { keyframes } from 'styled-components';
import { WaButton } from '@awesome.me/webawesome/dist/react';
import { ContentSection } from '../common';
import { useGameEngine } from '../game/hooks/UseGameEngine';
import { useGameFrame } from '../game/hooks';
import Clock from '../game/plugins/clock';
import Rand from '../game/plugins/rand';
import Scene from '../game/plugins/scene';
import { formatTime } from '../utils';
import { ClimaxResult } from './ClimaxResult';
import { GameTimeline } from './GameTimeline';

const fadeInUp = keyframes`
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;

const StyledEndPage = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--wa-space-l);

min-height: 100%;
width: 100%;
padding: 16px;

& > * {
max-width: 480px;
width: 100%;
animation: ${fadeInUp} 500ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

& > :nth-child(1) {
animation-delay: 100ms;
}
& > :nth-child(2) {
animation-delay: 250ms;
}
& > :nth-child(3) {
animation-delay: 400ms;
}
`;

const StyledTitle = styled.h1`
text-align: center;
font-size: clamp(2rem, 8vw, 3.5rem);
font-weight: bold;
line-height: 1;
`;

const StyledCard = styled(ContentSection)`
display: flex;
flex-direction: column;
gap: var(--wa-space-m);
padding: 20px;
`;

const StyledStatsRow = styled.div`
display: flex;
justify-content: space-around;
`;

const StyledStat = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
`;

const StyledStatValue = styled.span`
font-size: 1.25rem;
font-weight: bold;
color: var(--text-color);
`;

const StyledStatLabel = styled.span`
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.1em;
opacity: 0.4;
`;

const StyledDivider = styled.hr`
border: none;
border-top: 1px solid currentColor;
width: 100%;
margin: 0;
`;

const StyledActions = styled.div`
display: flex;
justify-content: center;
`;

const StyledFinishButton = styled(WaButton)`
&::part(base) {
height: fit-content;
padding: 12px 40px;
}

&::part(label) {
font-size: 1.25rem;
text-transform: uppercase;
}
`;

export const EndPage = () => {
const { injectImpulse } = useGameEngine();
const clockState = useGameFrame(Clock.paths) as
| { elapsed?: number }
| undefined;
const randState = useGameFrame(Rand.paths) as { seed?: string } | undefined;

const displayTime =
typeof clockState?.elapsed === 'number' ? clockState.elapsed : 0;
const seed = randState?.seed ?? '';

return (
<StyledEndPage>
<StyledTitle>Game Over</StyledTitle>
<StyledCard>
<ClimaxResult />
<StyledDivider />
<StyledStatsRow>
<StyledStat>
<StyledStatValue>{formatTime(displayTime)}</StyledStatValue>
<StyledStatLabel>Play time</StyledStatLabel>
</StyledStat>
<StyledStat>
<StyledStatValue
style={{ fontFamily: 'monospace', fontSize: '1rem' }}
>
{seed}
</StyledStatValue>
<StyledStatLabel>Seed</StyledStatLabel>
</StyledStat>
</StyledStatsRow>
<StyledDivider />
<GameTimeline />
</StyledCard>
<StyledActions>
<StyledFinishButton
size='large'
onClick={() => injectImpulse(Scene.setScene('home'))}
>
Finish
</StyledFinishButton>
</StyledActions>
</StyledEndPage>
);
};
Loading