signalk-racer 1.1.2 → 1.3.1

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.
@@ -0,0 +1,23 @@
1
+ # Claude Code — resume checkpoint
2
+
3
+ Session: fe0c247c-615f-438d-9888-bb2d81cfa8b7
4
+ Written: 2026-08-19T08:14:05.997Z
5
+ Trigger: near-limit
6
+ Ref with your in-progress files: refs/claude/checkpoint-fe0c247c
7
+
8
+ ## To resume
9
+
10
+ claude --resume fe0c247c-615f-438d-9888-bb2d81cfa8b7
11
+
12
+ (or open Claude Code in this directory and run /resume)
13
+
14
+ ## Plan (from TodoWrite state)
15
+
16
+ No task list was active; see transcript via the resume command above.
17
+
18
+ ---
19
+
20
+ Don't want these changes? Resume this session (above), then run
21
+ `/rewind` to roll back the turn's tool edits (bash-made changes
22
+ excluded). refs/claude/checkpoint-fe0c247c holds a full snapshot until this session's
23
+ next checkpoint, or for up to ~2 weeks.
@@ -5,7 +5,21 @@
5
5
  "Bash(git -C /home/gregw/src/signalk-racer tag -l)",
6
6
  "Bash(git -C /home/gregw/src/signalk-racer log --oneline -5)",
7
7
  "Bash(git -C /home/gregw/src/signalk-racer status -sb)",
8
- "Bash(git -C /home/gregw/src/signalk-racer remote -v)"
8
+ "Bash(git -C /home/gregw/src/signalk-racer remote -v)",
9
+ "Bash(npx jest *)",
10
+ "Bash(node --check index.js)",
11
+ "Bash(node --check racer.js)",
12
+ "Bash(node *)",
13
+ "Bash(npm root *)",
14
+ "Read(//home/gregw/.signalk/**)",
15
+ "Read(//home/gregw/.signalk/plugin-config-data/**)",
16
+ "Bash(npm view *)",
17
+ "Bash(systemctl list-units *)",
18
+ "Bash(systemctl --user list-units --type=service --all)",
19
+ "Bash(sed *)",
20
+ "Bash(python3 -)",
21
+ "Bash(awk '/^## 1.2.0/,/^## 1.1.2/' ReleaseNotes.md)",
22
+ "Bash(tee /dev/stderr)"
9
23
  ]
10
24
  }
11
25
  }
package/README.md CHANGED
@@ -14,26 +14,34 @@ GitHub repository: [https://github.com/gregw/signalk-racer](https://github.com/g
14
14
 
15
15
  This plugin calculates and publishes the following Signal K paths:
16
16
 
17
- | Path | Description | Units | Std |
18
- |-------------------------------------------------|--------------------------------------------------------|------------------------|-----|
19
- | `navigation.racing.`<br/>`distanceStartline` | Signed minimum distance from the bow to the start line | `m` | Y |
20
- | `navigation.racing.`<br/>`startLineLength` | Total length of the start line | `m` | |
21
- | `navigation.racing.`<br/>`stbLineBias` | Bias of the start line toward the starboard end | `m` | |
22
- | `navigation.racing.`<br/>`startLinePort` | Location of the port (pin) end of the start line | `{latitude,longitude}` | Y |
23
- | `navigation.racing.`<br/>`startLineStb` | Location of the starboard (boat) end of the start line | `{latitude,longitude}` | Y |
24
- | `navigation.racing.`<br/>`nextLegHeading` | True heading for the next leg of the course | `rad` | |
25
- | `navigation.racing.`<br/>`nextLegTrueWindAngle` | True Wind Angle for the next leg of the course | `rad` | |
26
- | `navigation.racing.`<br/>`timeToStart` | Period of time until the race start | `s` | Y |
27
- | `navigation.racing.`<br/>`timeToLine` | Period of time to sail to the line at best VMG | `s` | |
28
- | `navigation.racing.`<br/>`timeToBurn` | Period of time delay before sailing to the at best VMG | `s` | |
29
- | `navigation.racing.`<br/>`startTime` | The start time as an ISO timestamp | `rfc3339` | |
17
+ | Path | Description | Units | Std |
18
+ |--------------------------------------------|------------------------------------------------------------------------|----------------------------------------------------|-----|
19
+ | `navigation.racing.distanceStartline` | Signed minimum distance from the bow to the start line | `m` | Y |
20
+ | `navigation.racing.startLineLength` | Total length of the start line | `m` | |
21
+ | `navigation.racing.startLineBearing` | Bearing of the start line, from the stb end to the port end | `rad` | |
22
+ | `navigation.racing.stbLineBias` | Bias of the start line toward the starboard end | `m` | |
23
+ | `navigation.racing.bestVmg.toCourseSide` | Best VMG across the line towards the course side | `m/s` | |
24
+ | `navigation.racing.bestVmg.fromCourseSide` | Best VMG back across the line from the course side (used when OCS) | `m/s` | |
25
+ | `navigation.racing.bestVmg.toPortEnd` | Best VMG along the line towards the port end (pin) | `m/s` | |
26
+ | `navigation.racing.bestVmg.toStbEnd` | Best VMG along the line towards the stb end (boat) | `m/s` | |
27
+ | `navigation.racing.bestVmg.*.override` | The manual adjustment behind each best VMG, `null` when not adjusted | `m/s` | |
28
+ | `navigation.racing.effectiveVmg.toLine` | VMG the perpendicular leg of the time to line is divided by | `m/s` | |
29
+ | `navigation.racing.effectiveVmg.alongLine` | VMG the along-line leg is divided by, 0 when inside the start zone | `m/s` | |
30
+ | `navigation.racing.startLinePort` | Location of the port (pin) end of the start line | `{latitude,longitude}` | Y |
31
+ | `navigation.racing.startLineStb` | Location of the starboard (boat) end of the start line | `{latitude,longitude}` | Y |
32
+ | `navigation.racing.nextLegHeading` | True heading for the next leg of the course | `rad` | |
33
+ | `navigation.racing.nextLegTrueWindAngle` | True Wind Angle for the next leg of the course | `rad` | |
34
+ | `navigation.racing.timeToStart` | Period of time until the race start | `s` | Y |
35
+ | `navigation.racing.timeToLine` | Period of time to sail to the line at best VMG | `s` | |
36
+ | `navigation.racing.timeToBurn` | Period of time delay before sailing to the at best VMG | `s` | |
37
+ | `navigation.racing.startTime` | The start time as an ISO timestamp | `rfc3339` | |
30
38
 
31
39
  These values can be displayed in KIP widgets, Freeboard-SK, or other Signal K clients.
32
40
  There are dedicated widgets for the start timer and line adjustment since 3.5.0 of KIP
33
41
 
34
42
  ![KIP and Freeboard Screenshot](racer-kip.png)
35
43
 
36
- There is also a webapp to adjust the line and timer.
44
+ There is also a webapp to: adjust the line, visualize the approach to the line, adjust VMGs and configure the timer.
37
45
 
38
46
  ![Signalk Racer Webapp](racer-webapp.png)
39
47
 
@@ -53,6 +61,7 @@ You can configure the plugin via the Signal K web interface or by editing `setti
53
61
  | `period` | How often to update values (in milliseconds) | `1000` |
54
62
  | `updateStartLineWaypoint` | Should the waypoints be updated if the line is set/adjusted | `true` |
55
63
  | `createStartLineWaypoint` | Should the waypoints be created if the line is set | `true` |
64
+ | `minEffectiveVmg` | Floor under each effective VMG used for time to line (in knots) | `0.5` |
56
65
  | `lines` | Array of named lines | null |
57
66
 
58
67
  ---
@@ -90,9 +99,18 @@ If `navigation.headingTrue` is not available, then `navigation.courseOverGroundT
90
99
 
91
100
  - Uses the effective VMG as the maximum VMG of either the current COG/SOG or the 90th percentile of the VMG recently achieved (approx in the last 10 minutes).
92
101
  This allows a boat to luff / delay without changing the time to line.
102
+ - Each effective VMG is floored at `minEffectiveVmg` (default 0.5 knots), so a direction
103
+ with nothing collected yet - or a drifting boat - still yields a time rather than none.
104
+ The floor is not applied to the along-line leg when the boat is inside the start zone,
105
+ there being no such leg to sail.
93
106
  - A boat within the start zone has the time calculated by the perpendicular distance to the line divided by their effective VMG to the line.
94
107
  - A boat outside the start zone also has the perpendicular time plus the time calculated by the parallel distance to the zone divided by their effective VMG in that direction.
95
108
  - If the line is changed, then the samples used to calculate the effective VMGs are cleared.
109
+ - The four collected VMGs are published under `navigation.racing.bestVmg.*` and may be manually
110
+ adjusted. An adjustment stands in for the 90th percentile of the samples, but the VMG the boat
111
+ is actually sailing still wins if it is better, so an adjustment can never make the estimate
112
+ ignore real progress. Adjustments are cleared when the start timer reaches zero, when the line
113
+ changes, and by the `reset` command.
96
114
  - If the boat is navigating a route and the next waypoint is beyond the second in the route, then the time to line is not calculated.
97
115
 
98
116
 
@@ -114,6 +132,35 @@ If `navigation.headingTrue` is not available, then `navigation.courseOverGroundT
114
132
 
115
133
  ---
116
134
 
135
+ ## 📉 Webapp Start Line Visualization
136
+
137
+ The webapp draws the line "line up": always horizontal, with the **port (pin) end to the left**
138
+ and the **starboard (committee boat) end to the right**. The course side of the line is therefore
139
+ always the **upper** half of the drawing and the pre-start side the lower half, so the arrow beside
140
+ the line length and start heading always points straight up. The drawing is auto-scaled to fit the
141
+ line and the boat, so it zooms as the boat closes. The line length and the heading to sail to cross
142
+ the line are marked on the line itself, and the boat is drawn as a triangle pointing along its
143
+ heading, amber when OCS.
144
+
145
+ A projection runs from the boat, drawn to the same scale as the rest of the drawing, so its **tip
146
+ can be read directly against the line**. Hovering the boat reports its SOG and COG and names the
147
+ line running from it.
148
+
149
+ #### Course projection — "Current cog/sog to start"
150
+
151
+ Runs along the boat's present `navigation.courseOverGroundTrue`. While the start timer is counting
152
+ down, its length is `SOG × timeToStart`: the distance the boat will cover before the gun if nothing
153
+ changes. Its tip is therefore **where the boat will be when the start fires**:
154
+
155
+ - tip short of the line — the boat is late and will cross after the gun
156
+ - tip on the line — a perfect start
157
+ - tip beyond the line — the boat is early and will be OCS
158
+
159
+ With no timer running there is nothing to project against, so it degrades to a short fixed-length
160
+ stub showing course only.
161
+
162
+ ---
163
+
117
164
  ## 🌐 API Access
118
165
 
119
166
  This plugin uses the following WebSocket-based PUT requests to Signal K model paths.
@@ -139,6 +186,39 @@ Used to **set** or **adjust** either end of the start line.
139
186
 
140
187
  ---
141
188
 
189
+ ### `navigation.racing.swapStartLine`
190
+
191
+ Used to **swap** the port (pin) and starboard (boat) ends of the line, reversing its bearing.
192
+ Takes no parameters. Collected VMG samples and any manual adjustments are exchanged along
193
+ with the ends rather than discarded, since reversing the bearing flips the sign of both VMG
194
+ components and so leaves every sample valid, just relabelled.
195
+
196
+ ---
197
+
198
+ ### `navigation.racing.setBestVmg`
199
+
200
+ Used to **adjust** or **reset** the best VMGs used to estimate the time to line.
201
+
202
+ #### Payload:
203
+ ```
204
+ {
205
+ "vmg": "toCourseSide" | "fromCourseSide" | "toPortEnd" | "toStbEnd",
206
+ "value": 5.0,
207
+ "delta": 0.0514,
208
+ "command": "reset" | "clear"
209
+ }
210
+ ```
211
+
212
+ - `vmg`: which best VMG to adjust. Optional for `reset`, which otherwise clears all four.
213
+ - `value`: absolute best VMG in `m/s`.
214
+ - `delta`: adjustment in `m/s` applied to the current best VMG.
215
+ - `command`: `"reset"` to clear the override and revert to the collected samples, or
216
+ `"clear"` to throw away the collected samples themselves and start again.
217
+
218
+ An absolute value may also be put directly to `navigation.racing.bestVmg.<name>`.
219
+
220
+ ---
221
+
142
222
  ### `navigation.racing.setStartTime`
143
223
 
144
224
  Used to **start**, **sync**, **reset**, or **set a fixed start time**.
@@ -184,6 +264,9 @@ Bug reports and suggestions are welcome at
184
264
 
185
265
  ---
186
266
  ## Development
267
+
268
+ ### Linking the plugin into a local server
269
+
187
270
  ```text
188
271
  npm install
189
272
  npm link
@@ -191,6 +274,63 @@ cd ~/.signalk
191
274
  npm link signalk-racer
192
275
  ```
193
276
 
277
+ This replaces `~/.signalk/node_modules/signalk-racer` with a symlink to your checkout, so
278
+ edits take effect on the next server restart with no reinstall. Verify the link with:
279
+
280
+ ```text
281
+ readlink -f ~/.signalk/node_modules/signalk-racer
282
+ ```
283
+
284
+ > ⚠️ **The link is fragile.** `~/.signalk/package.json` still lists `signalk-racer` as a
285
+ > normal dependency, so running `npm install` (or installing/updating *any* plugin from the
286
+ > server's Appstore) will overwrite the symlink with the published release from npm, silently
287
+ > reverting you to the registry version. Re-run `npm link signalk-racer` in `~/.signalk`
288
+ > whenever that happens.
289
+
290
+ ### Checking which build is actually running
291
+
292
+ The plugin stamps its version in three places, so a stale link is easy to spot:
293
+
294
+ - the **Plugin Config** page in the admin UI, as the plugin status `signalk-racer <version> started`
295
+ - the bottom of the **racer webapp**
296
+ - the server log, via `app.debug`, including the directory it was loaded from
297
+
298
+ During development the version carries a `-dev.N` suffix (e.g. `1.2.0-dev.0`), so it is
299
+ immediately distinguishable from a released version installed from npm.
300
+
301
+ A restart is required for any change to plugin code — the server does not hot-reload plugins.
302
+ Changes to files under `public/` are served statically, so those only need a browser reload
303
+ (with cache bypass: `Ctrl+Shift+R`).
304
+
305
+ ### Running the server on this machine
306
+
307
+ The server is installed **globally** (`npm root -g` → `/usr/lib/node_modules`) and runs as a
308
+ system service, using `~/.signalk` as its config directory:
309
+
310
+ ```text
311
+ sudo systemctl status signalk # is it running?
312
+ sudo systemctl restart signalk # pick up plugin changes
313
+ journalctl -u signalk -f # follow the log
314
+ ```
315
+
316
+ ### Updating signalk-server
317
+
318
+ Because it is installed into a system directory, updating needs `sudo`, and the service must be
319
+ restarted afterwards:
320
+
321
+ ```text
322
+ npm view signalk-server version # latest published
323
+ npm ls -g --depth=0 signalk-server # currently installed
324
+ sudo npm install -g signalk-server # update to latest
325
+ sudo systemctl restart signalk
326
+ ```
327
+
328
+ To pin a specific version instead, use `sudo npm install -g signalk-server@2.31.1`.
329
+
330
+ Note that `~/.signalk/package.json` also lists `signalk-server` as a dependency; that entry is
331
+ only bookkeeping for the Appstore and is **not** what the service runs — the globally installed
332
+ copy in `/usr/lib/node_modules/signalk-server` is. Updating the global copy is what counts.
333
+
194
334
  ---
195
335
  ## 🚀 Releasing
196
336
 
package/ReleaseNotes.md CHANGED
@@ -1,3 +1,51 @@
1
+ ## 1.3.1 Start line approach
2
+ + Fixed the distance to the start zone being measured against a 54.7 degree wedge while
3
+ the zone itself was tested at 45 degrees, so `distanceStartline` and `timeToLine`
4
+ jumped by 0.29 times the offset as a boat crossed the boundary. They are now continuous
5
+ and the along-line leg reaches zero exactly at the wedge
6
+ + The start zone geometry moved from `index.js` into `racer.js` as `startZoneDistances`,
7
+ where it is unit tested - it had no coverage at all, which is how the above survived
8
+ + `navigation.racing.timeToBurn` is now published when OCS as well. The time to line is
9
+ then the time to get back over the line from the course side, so the spare time before
10
+ you have to turn and do it is just as real, and goes negative once it is too late
11
+ + Removed `navigation.racing.bestApproach` and the `cog`/`sog` each VMG sample carried
12
+ to produce it. It described one course the boat had genuinely sailed, which was useful
13
+ but not the path the time to line is computed over, so it read as a second answer to a
14
+ question that already had one. Best VMG angles will be revisited once the polar plugin
15
+ offers an API for them, by which point the shape is likely to be quite different
16
+ + Each effective VMG is now floored at a configurable minimum, `minEffectiveVmg`,
17
+ defaulting to 0.5 knots. A direction with nothing collected reported no VMG at all, which
18
+ left the time to line falling back to the time to start rather than estimating anything
19
+ + `navigation.racing.setBestVmg` accepts `command: "clear"`, which discards the collected
20
+ samples themselves rather than just the manual adjustments
21
+ + Published the two VMGs the time to line is actually divided by as
22
+ `navigation.racing.effectiveVmg.{toLine,alongLine}`: the collected best for each
23
+ direction, or the VMG being sailed right now when that is better. `bestVmg.*` reports
24
+ only the collected half, so a client drawing the approach from it disagreed with the
25
+ published time whenever the boat was going well
26
+
27
+ ## 1.3.0 Visualize line and best VMGs
28
+ + Added `navigation.racing.swapStartLine` to swap the port and starboard ends of the line,
29
+ carrying the collected VMG samples across with the ends
30
+ + Published the four best VMGs behind the time to line as `navigation.racing.bestVmg.`
31
+ `{toCourseSide,fromCourseSide,toPortEnd,toStbEnd}`, each with an `.override` beside it
32
+ reporting the manual adjustment, if any
33
+ + Added `navigation.racing.setBestVmg` to adjust or reset them, plus direct puts to each path.
34
+ An adjustment holds until the gun, but the VMG actually being sailed wins if it is better
35
+ + Samples now keep the `cog` and `sog` that produced them, published as
36
+ `navigation.racing.bestApproach`: the course actually sailed that best closes the line
37
+ + Published the start line bearing as `navigation.racing.startLineBearing`
38
+ + Webapp: swap-ends button, race countdown, and a start line visualisation with the best VMGs
39
+ as a cross below it and projections showing where the boat reaches at the gun
40
+ + Webapp and admin UI now show the running plugin version
41
+ + Fixed VMG samples being rejected below an absolute 1 m/s in each direction, so a boat closing
42
+ the line at an angle only fed the direction it was mostly travelling (now `minVmg`, 0.01 m/s)
43
+ + Fixed the collected VMG samples being discarded whenever any waypoint changed
44
+ + Fixed the start line bias not being cleared when the line is lost
45
+ + Fixed the webapp race countdown never being displayed
46
+
47
+ ## 1.2.0 Never released
48
+
1
49
  ## 1.1.2 TTL fixes
2
50
  + use a FIFO queue for VMGs towards the line.
3
51
  + avoid undefined values in deltas