Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Validate

on:
push:
pull_request:

permissions:
contents: read

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run verify
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

A browser client for the [Encounter+](https://encounter.plus) virtual tabletop app. Encounter+ serves this client to players' browsers, TVs and table displays. The client shows the current map, tokens, lighting and fog of war, the initiative order and the chat. Everything updates live over a WebSocket. Depending on how the host has set up the screen, players can also move their tokens, ping the map and send messages.

## Player tools

- **My character** shows the selected friendly token's sheet and enabled status effects. HP controls appear when the host supplies an HP range, and players can enter an initiative result before combat starts.
- **Ruler** provides precise distances and grid movement. Saved rulers stay in the current browser session and are cleared when the map changes.
- **Area preview** draws local sphere, cylinder, cone, cube and line templates. Overlapping squares are highlighted on square grids; the preview does not create or modify host area effects.
- Character sheets and rule references open in separate draggable windows. Roll and reference links are handled when the hosted sheet is accessible from the client's origin.
- Appearance can follow the device or use light/dark mode. Initiative can dock at the right or bottom, and the selected character receives a turn notification.

HP and initiative updates use the host's existing `updateCombatant` WebSocket event; rolls use `createMessage`. Host measurements and area effects continue to arrive through their existing model/event paths. Local map tools do not call area-effect or measurement write endpoints, leaving their shared-state integration for a later change.

## Environment

| | Version |
Expand Down Expand Up @@ -50,7 +60,7 @@ http://localhost:4200/?remoteHost=192.168.1.10:8080
| `device` | e.g. `gameboard` | Marks a dedicated display device. `gameboard` also applies a 1.5× viewport scale. |
| `interactions` | `all` | Enables every interaction, whatever the screen settings say. |

User preferences (max FPS, video playback, name, selected token, open panel) are kept in `localStorage`.
User preferences (max FPS, video playback, name, selected token, open panels, appearance and initiative dock position) are kept in `localStorage`.

## Architecture

Expand Down Expand Up @@ -122,8 +132,9 @@ To rebuild an existing release, run the Release workflow manually with its tag.
## Tests

```
npm run verify # all unit tests followed by the production build
npm test # Karma in watch mode
npm run test:ci # single run
npm run test:ci # unit tests only, single run
```

Specs sit next to the code they cover (`*.spec.ts`). `core/map/testing/` and `shared/models/testing/` hold stubs and fixtures.
14 changes: 1 addition & 13 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,6 @@
],
"scripts": []
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "web-client:serve"
},
"configurations": {
"production": {
"devServerTarget": "web-client:serve:production"
}
}
}
}
}
Expand Down Expand Up @@ -160,4 +148,4 @@
"typeSeparator": "."
}
}
}
}
32 changes: 0 additions & 32 deletions e2e/protractor.conf.js

This file was deleted.

23 changes: 0 additions & 23 deletions e2e/src/app.e2e-spec.ts

This file was deleted.

11 changes: 0 additions & 11 deletions e2e/src/app.po.ts

This file was deleted.

13 changes: 0 additions & 13 deletions e2e/tsconfig.json

This file was deleted.

14 changes: 7 additions & 7 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@ module.exports = function (config) {
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/web-client'),
subdir: '.',
Expand All @@ -23,10 +19,14 @@ module.exports = function (config) {
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
reporters: ['dots'],
browserConsoleLogOptions: {
level: 'error',
terminal: true
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
colors: false,
logLevel: config.LOG_WARN,
autoWatch: true,
browsers: ['ChromeHeadless'],
singleRun: false,
Expand Down
13 changes: 0 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:prod": "ng build --configuration production",
"build:prod": "ng build --configuration production --progress=false",
"package": "npm run build:prod && node scripts/package.mjs",
"test": "ng test",
"test:ci": "ng test --watch=false",
"test:ci": "ng test --watch=false --progress=false --reporters=dots",
"verify": "node scripts/verify.mjs",
"lint": "ng lint",
"e2e": "ng e2e",
"version": "node scripts/sync-version.mjs && git add src/manifest.json"
},
"private": true,
Expand Down Expand Up @@ -53,7 +53,6 @@
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"typescript": "^6.0.3"
}
}
32 changes: 32 additions & 0 deletions scripts/verify.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import path from 'node:path';

const root = fileURLToPath(new URL('..', import.meta.url));
const ng = path.join(root, 'node_modules', '@angular', 'cli', 'bin', 'ng.js');

function run(label, args, summarize = () => label) {
const result = spawnSync(process.execPath, [ng, ...args], {
cwd: root,
env: process.env,
encoding: 'utf8'
});
const output = `${result.stdout ?? ''}${result.stderr ?? ''}`;

if (result.status !== 0) {
process.stderr.write(`Verification failed: ${label}\n${output}`);
process.exit(result.status ?? 1);
}

console.log(`✓ ${summarize(output)}`);
}

run(
'unit tests',
['test', '--watch=false', '--progress=false', '--reporters=dots'],
output => {
const match = output.match(/Executed (\d+) of \1 SUCCESS/);
return match ? `${match[1]} unit tests` : 'unit tests';
}
);
run('production build', ['build', '--configuration', 'production', '--progress=false']);
Loading