hyperchess-wasm 0.1.0

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,56 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const __wbg_wasmboard_free: (a: number, b: number) => void;
5
+ export const calibrate_piece: (a: number, b: number, c: number, d: number, e: number) => number;
6
+ export const wasmboard_adjudicate_material: (a: number) => number;
7
+ export const wasmboard_apply_move: (a: number, b: number, c: number) => number;
8
+ export const wasmboard_best_move: (a: number, b: number) => [number, number];
9
+ export const wasmboard_best_move_guided: (a: number, b: number) => [number, number];
10
+ export const wasmboard_best_move_guided_iterative: (a: number, b: number) => [number, number];
11
+ export const wasmboard_best_move_iterative: (a: number, b: number) => [number, number];
12
+ export const wasmboard_best_move_mcts: (a: number, b: number) => [number, number];
13
+ export const wasmboard_best_move_pro: (a: number, b: number) => [number, number];
14
+ export const wasmboard_best_move_strategic: (a: number, b: number) => [number, number];
15
+ export const wasmboard_best_move_timed: (a: number, b: number, c: number, d: number) => [number, number];
16
+ export const wasmboard_best_move_timed_profile: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
17
+ export const wasmboard_encode: (a: number) => [number, number];
18
+ export const wasmboard_from_hfen: (a: number, b: number) => number;
19
+ export const wasmboard_hfen: (a: number) => [number, number];
20
+ export const wasmboard_in_check: (a: number) => number;
21
+ export const wasmboard_is_game_over: (a: number) => number;
22
+ export const wasmboard_king_square: (a: number) => number;
23
+ export const wasmboard_legal_moves: (a: number) => [number, number];
24
+ export const wasmboard_new: () => number;
25
+ export const wasmboard_result: (a: number) => number;
26
+ export const wasmboard_result_adjudicated: (a: number, b: number) => number;
27
+ export const wasmboard_set_hfen_history: (a: number, b: number, c: number) => void;
28
+ export const wasmboard_termination: (a: number) => [number, number];
29
+ export const wasmboard_turn: (a: number) => [number, number];
30
+ export const wasmboard_set_search_history: (a: number, b: number, c: number) => void;
31
+ export const __wbg_scene3d_free: (a: number, b: number) => void;
32
+ export const init: () => void;
33
+ export const scene3d_animate_move: (a: number, b: number, c: number) => void;
34
+ export const scene3d_create: (a: any) => any;
35
+ export const scene3d_is_animating: (a: number) => number;
36
+ export const scene3d_orbit: (a: number, b: number, c: number) => void;
37
+ export const scene3d_pick: (a: number, b: number, c: number) => number;
38
+ export const scene3d_render: (a: number) => void;
39
+ export const scene3d_resize: (a: number, b: number, c: number) => void;
40
+ export const scene3d_set_board: (a: number, b: number, c: number, d: number) => void;
41
+ export const scene3d_set_selection: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
42
+ export const scene3d_zoom: (a: number, b: number) => void;
43
+ export const wasm_bindgen__convert__closures_____invoke__hb0b40ee7dfd77fc5: (a: number, b: number, c: any) => [number, number];
44
+ export const wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a: (a: number, b: number, c: any) => [number, number];
45
+ export const wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a_2: (a: number, b: number, c: any) => [number, number];
46
+ export const wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a_3: (a: number, b: number, c: any) => [number, number];
47
+ export const wasm_bindgen__convert__closures_____invoke__h73e935f3b365ecab: (a: number, b: number, c: any, d: any) => void;
48
+ export const __wbindgen_malloc: (a: number, b: number) => number;
49
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
50
+ export const __wbindgen_exn_store: (a: number) => void;
51
+ export const __externref_table_alloc: () => number;
52
+ export const __wbindgen_externrefs: WebAssembly.Table;
53
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
54
+ export const __wbindgen_destroy_closure: (a: number, b: number) => void;
55
+ export const __externref_table_dealloc: (a: number) => void;
56
+ export const __wbindgen_start: () => void;
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "hyperchess-wasm",
3
+ "description": "HyperChess WASM bindings — WasmBoard (rules+search, from src/hyperchess/src/wasm.rs) and Scene3D (WebGPU/WebGL board renderer, from the former standalone hyperchess_3d crate), one wasm-pack build target",
4
+ "version": "0.1.0",
5
+ "license": "GPL-3.0-or-later",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/KyrpyDev/hyperchess-core"
9
+ },
10
+ "files": [
11
+ "hyperchess_wasm_bg.wasm",
12
+ "hyperchess_wasm.js",
13
+ "hyperchess_wasm.d.ts"
14
+ ],
15
+ "main": "hyperchess_wasm.js",
16
+ "homepage": "https://github.com/KyrpyDev/hyperchess-core",
17
+ "types": "hyperchess_wasm.d.ts",
18
+ "keywords": [
19
+ "chess",
20
+ "wasm",
21
+ "webgpu",
22
+ "hyperchess"
23
+ ]
24
+ }
File without changes
@@ -0,0 +1,37 @@
1
+ # hyperchess-wasm
2
+
3
+ Two independent wasm-bindgen surfaces, one wasm-pack build target:
4
+
5
+ - **`WasmBoard`** — rules + search bindings (legal moves, apply-move, every searcher entry
6
+ point). Depends on `hyperchess-rules` + `hyperchess-search`.
7
+ - **`Scene3D`** — WebGPU/WebGL board/piece renderer. Zero dependency on the rules engine —
8
+ takes a 144-byte board encoding as raw bytes (the same format `WasmBoard::encode()`
9
+ produces), not a `Board` reference. The two communicate via that shared byte protocol, not
10
+ Rust-level coupling.
11
+
12
+ The source repo keeps these as genuinely separate crates/build pipelines (`src/hyperchess`
13
+ built directly with `--features wasm`, and a standalone `hyperchess_3d` consumed only by the
14
+ private web app's own hand-loaded WASM, never integrated into the npm SDK workspace). Merging
15
+ them here is a deliberate improvement, not a copy of existing structure — see
16
+ [`docs/hyperchess-core-extraction-plan.md`](../../../docs/hyperchess-core-extraction-plan.md)
17
+ §12 Phase 6. It's also why `hyperchess-rules`/`hyperchess-search` have no wasm-bindgen
18
+ dependency of their own (Phase 1/3) — that lives only here, in the crate whose whole purpose
19
+ is WASM bindings.
20
+
21
+ `geometry`/`pieces` are plain portable math, native-buildable, and used by the `gen_assets`
22
+ dev-tool binary (`cargo run --bin gen_assets`) as well as the wasm32-only renderer — everything
23
+ else here (`board`, `camera`, `gpu`, `obj`, `scene`) is `#[cfg(target_arch = "wasm32")]`, so a
24
+ plain `cargo build`/`cargo test` (no wasm32 target) only touches the portable half.
25
+
26
+ ## Known trade-off: bundle size
27
+
28
+ Verified via a real `wasm-pack build --target nodejs` + Node.js smoke test (not just
29
+ `cargo build`): the resulting `.wasm` binary is **~4.5MB**, because `wgpu` (pulled in for
30
+ `Scene3D`) compiles into the same module as `WasmBoard`, even for consumers who only want 2D
31
+ legal-move validation and never touch the 3D renderer. The source repo's `hyperchess-wasm`
32
+ package (rules-only, no 3D) was necessarily smaller. This is the direct cost of the "one
33
+ wasm-pack build target" merge decision (§12 Phase 6) — worth reconsidering once
34
+ `packages/board-3d` (§12 Phase 8) is built: a `scene3d` Cargo feature gating `wgpu`/`camera`/
35
+ `gpu`/`obj`/`scene` out of the default build would let a `WasmBoard`-only consumer opt out of
36
+ the 3D weight, at the cost of no longer being strictly "one build for everything." Flagged as
37
+ an open item, not solved here.
@@ -0,0 +1,310 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * JS-facing handle. Board state is a 144-byte array: 0 = empty, else
6
+ * `(color << 4) | kind` with kind 1..=8 indexing
7
+ * `[pawn, knight, bishop, rook, queen, king, eagle, hawk]` and color
8
+ * 0 = white, 1 = black (see `board3d.js` for the encoder).
9
+ */
10
+ export class Scene3D {
11
+ private constructor();
12
+ free(): void;
13
+ [Symbol.dispose](): void;
14
+ /**
15
+ * Starts a glide animation for the piece on `from` moving to `to`. Call
16
+ * this *before* `set_board` with the post-move position — it snapshots
17
+ * the pre-move board to know what to animate (and what's being captured).
18
+ */
19
+ animate_move(from: number, to: number): void;
20
+ /**
21
+ * Creates the renderer against the given canvas. Async because adapter/device
22
+ * acquisition is a browser Promise under the hood. JS calls this as a static
23
+ * factory (`await Scene3D.create(canvas)`), not `new Scene3D(...)`.
24
+ */
25
+ static create(canvas: HTMLCanvasElement): Promise<Scene3D>;
26
+ /**
27
+ * True while a move animation is still in flight — keep calling
28
+ * `render()` on every frame until this goes false, then it's fine to
29
+ * idle the render loop until the next interaction.
30
+ */
31
+ is_animating(): boolean;
32
+ /**
33
+ * Rotate the camera around the board by a *delta* in radians;
34
+ * pitch is clamped internally so the camera cannot flip over the pole.
35
+ */
36
+ orbit(dyaw: number, dpitch: number): void;
37
+ /**
38
+ * Canvas-space pixel coordinates -> square index (0-143), or -1 if off-board.
39
+ */
40
+ pick(x: number, y: number): number;
41
+ /**
42
+ * Draw one frame. JS drives the render loop, so this must be called
43
+ * from `requestAnimationFrame` — the renderer never schedules itself.
44
+ */
45
+ render(): void;
46
+ /**
47
+ * Match the swapchain to a new canvas size, in physical pixels.
48
+ */
49
+ resize(width: number, height: number): void;
50
+ /**
51
+ * `board` must be exactly 144 bytes (see the encoding note on `Scene3D`).
52
+ */
53
+ set_board(board: Uint8Array, flipped: boolean): void;
54
+ /**
55
+ * `-1` means "none" for `selected`/`last_from`/`last_to`/`checked_king`.
56
+ */
57
+ set_selection(selected: number, legal: Uint8Array, last_from: number, last_to: number, checked_king: number): void;
58
+ /**
59
+ * Scale the camera distance by `factor` (`>1` pulls back, `<1` moves
60
+ * in), clamped to the scene's usable range.
61
+ */
62
+ zoom(factor: number): void;
63
+ }
64
+
65
+ /**
66
+ * JS-facing wrapper around a [`Board`].
67
+ *
68
+ * Every method takes and returns plain strings or primitives rather than
69
+ * exposing engine types across the wasm boundary, so the JS side never needs
70
+ * to mirror the Rust move or piece encodings.
71
+ */
72
+ export class WasmBoard {
73
+ free(): void;
74
+ [Symbol.dispose](): void;
75
+ /**
76
+ * Material-only adjudication of the current position: 1 = White wins,
77
+ * 2 = Black wins, 3 = draw (within one pawn of equal material).
78
+ */
79
+ adjudicate_material(): number;
80
+ /**
81
+ * Apply a move given as a UCI string. Returns false if the move is not legal.
82
+ */
83
+ apply_move(uci: string): boolean;
84
+ /**
85
+ * Run alpha-beta search at the given depth and return the best move as UCI.
86
+ * Returns an empty string if there are no legal moves.
87
+ */
88
+ best_move(depth: number): string;
89
+ /**
90
+ * Compatibility guided alpha-beta label. Uses the canonical timed search.
91
+ */
92
+ best_move_guided(depth: number): string;
93
+ /**
94
+ * Compatibility guided iterative label. Uses the canonical timed search.
95
+ */
96
+ best_move_guided_iterative(depth: number): string;
97
+ /**
98
+ * Run iterative deepening (with transposition table) at the given depth.
99
+ * Better than `best_move` for the same depth budget — TT avoids re-searching
100
+ * positions seen at shallower iterations.
101
+ */
102
+ best_move_iterative(depth: number): string;
103
+ /**
104
+ * Run MCTS with the given number of simulations and return the best move as UCI.
105
+ * Returns an empty string if there are no legal moves.
106
+ */
107
+ best_move_mcts(simulations: number): string;
108
+ /**
109
+ * Run the "aggressive" profile (PVS, aspiration windows and the
110
+ * speculative pruning family — reverse futility, frontier futility, delta
111
+ * pruning). The strongest fixed-depth option.
112
+ */
113
+ best_move_pro(depth: number): string;
114
+ /**
115
+ * Run the stronger strategic-style tactical profile.
116
+ */
117
+ best_move_strategic(depth: number): string;
118
+ /**
119
+ * Anytime iterative-deepening search with a **wall-clock budget** (and an
120
+ * optional node cap as a deterministic backstop).
121
+ *
122
+ * This is the recommended interactive search: it deepens until `max_depth`,
123
+ * the time budget, or the node cap is hit, then returns the best move from the
124
+ * deepest *completed* depth. The search watches the clock itself
125
+ * (`js_sys::Date::now()`) — essential in the browser, where JS cannot interrupt
126
+ * a running synchronous WASM call, so an external timeout would never fire.
127
+ *
128
+ * * `movetime_ms == 0` → no time cap.
129
+ * * `node_limit == 0` → no node cap.
130
+ * (At least one of `movetime_ms` / `node_limit` / a small `max_depth` should
131
+ * be set, or the search runs to `max_depth` which may be very deep.)
132
+ */
133
+ best_move_timed(max_depth: number, movetime_ms: number, node_limit: number): string;
134
+ /**
135
+ * Anytime search with a wall-clock budget under a named profile:
136
+ * `"balanced"` (default), `"strategic"`, or `"aggressive"`. Same anytime semantics
137
+ * as [`Self::best_move_timed`] — this is what interactive strategic/aggressive
138
+ * callers should use so the computed move timeout is actually honoured
139
+ * (the fixed-depth `best_move_strategic` / `best_move_pro` wrappers ignore it).
140
+ */
141
+ best_move_timed_profile(max_depth: number, movetime_ms: number, node_limit: number, profile: string): string;
142
+ /**
143
+ * Returns the board as a 144-byte Uint8Array for WebGPU evaluation.
144
+ * Each byte is the Piece discriminant: 0=empty, 1-8=white, 9-16=black.
145
+ * Piece order: P=1, N=2, B=3, R=4, Q=5, K=6, Eagle=7, Hawk=8 (+ 8 for black).
146
+ */
147
+ encode(): Uint8Array;
148
+ /**
149
+ * Create a board from a HFEN string. Returns null on parse error.
150
+ */
151
+ static from_hfen(hfen: string): WasmBoard | undefined;
152
+ /**
153
+ * Returns the current position as a HFEN string.
154
+ */
155
+ hfen(): string;
156
+ /**
157
+ * Returns true if the side to move is currently in check.
158
+ */
159
+ in_check(): boolean;
160
+ /**
161
+ * Returns true if the game has ended (checkmate, stalemate, or draw).
162
+ */
163
+ is_game_over(): boolean;
164
+ /**
165
+ * Returns the square index (0-143) of the king for the side to move, or 255 if not found.
166
+ */
167
+ king_square(): number;
168
+ /**
169
+ * Returns all legal moves as a space-separated UCI string (e.g. "a3a4 b3b4 ...").
170
+ */
171
+ legal_moves(): string;
172
+ /**
173
+ * Create a board at the starting position.
174
+ */
175
+ constructor();
176
+ /**
177
+ * Returns the game result: 0=ongoing, 1=white wins, 2=black wins, 3=draw.
178
+ */
179
+ result(): number;
180
+ /**
181
+ * [`Self::result`] with material adjudication for move-limit endings:
182
+ * a draw by the internal no-progress rule — and, when `capped` is true, an
183
+ * ongoing position stopped by an external per-game move cap — is decided
184
+ * by material (≥ 1 pawn wins) instead of collapsing to a draw. Genuine
185
+ * draws (stalemate, repetition, insufficient material) are unchanged.
186
+ */
187
+ result_adjudicated(capped: boolean): number;
188
+ /**
189
+ * Populate game history for draw-rule and search repetition checks.
190
+ *
191
+ * Contract (see `Board::repetition_count`): `history` stores **prior**
192
+ * positions only. Callers pass the full ordered HFEN list of the game
193
+ * (typically including the current position last); a trailing entry equal
194
+ * to the current position is dropped so it is never double-counted.
195
+ * Threefold then fires at `repetition_count() >= 2` (2 prior + current).
196
+ */
197
+ set_hfen_history(hfens: string): void;
198
+ /**
199
+ * Alias of [`Self::set_hfen_history`] — kept for older callers. Both draw
200
+ * rules and search now share the same prior-positions-only contract.
201
+ */
202
+ set_search_history(hfens: string): void;
203
+ /**
204
+ * Returns why the game ended: "checkmate", "stalemate", "move_limit",
205
+ * "fivefold_repetition", "threefold_repetition", "insufficient_material", or
206
+ * "ongoing". Delegates to `Board::termination_reason`, the single source of
207
+ * truth also used by the server's termination endpoint, so the WASM/local-game
208
+ * path reports the same specific reason as server-backed games.
209
+ */
210
+ termination(): string;
211
+ /**
212
+ * Returns whose turn it is: "white" or "black".
213
+ */
214
+ turn(): string;
215
+ }
216
+
217
+ /**
218
+ * Which new piece to calibrate. JS passes `"eagle"` or `"hawk"`.
219
+ */
220
+ export function calibrate_piece(piece: string, games: number, depth: number, max_half_moves: number): number;
221
+
222
+ /**
223
+ * Single combined init for both wasm-bindgen surfaces in this crate —
224
+ * wasm-bindgen only allows one `#[wasm_bindgen(start)]` function per
225
+ * crate. Merges what were two separate inits in the source repo
226
+ * (`hyperchess::wasm`'s panic hook + `Helper::init()`, and
227
+ * `hyperchess_3d`'s panic hook + `console_log` setup).
228
+ */
229
+ export function init(): void;
230
+
231
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
232
+
233
+ export interface InitOutput {
234
+ readonly memory: WebAssembly.Memory;
235
+ readonly __wbg_wasmboard_free: (a: number, b: number) => void;
236
+ readonly calibrate_piece: (a: number, b: number, c: number, d: number, e: number) => number;
237
+ readonly wasmboard_adjudicate_material: (a: number) => number;
238
+ readonly wasmboard_apply_move: (a: number, b: number, c: number) => number;
239
+ readonly wasmboard_best_move: (a: number, b: number) => [number, number];
240
+ readonly wasmboard_best_move_guided: (a: number, b: number) => [number, number];
241
+ readonly wasmboard_best_move_guided_iterative: (a: number, b: number) => [number, number];
242
+ readonly wasmboard_best_move_iterative: (a: number, b: number) => [number, number];
243
+ readonly wasmboard_best_move_mcts: (a: number, b: number) => [number, number];
244
+ readonly wasmboard_best_move_pro: (a: number, b: number) => [number, number];
245
+ readonly wasmboard_best_move_strategic: (a: number, b: number) => [number, number];
246
+ readonly wasmboard_best_move_timed: (a: number, b: number, c: number, d: number) => [number, number];
247
+ readonly wasmboard_best_move_timed_profile: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
248
+ readonly wasmboard_encode: (a: number) => [number, number];
249
+ readonly wasmboard_from_hfen: (a: number, b: number) => number;
250
+ readonly wasmboard_hfen: (a: number) => [number, number];
251
+ readonly wasmboard_in_check: (a: number) => number;
252
+ readonly wasmboard_is_game_over: (a: number) => number;
253
+ readonly wasmboard_king_square: (a: number) => number;
254
+ readonly wasmboard_legal_moves: (a: number) => [number, number];
255
+ readonly wasmboard_new: () => number;
256
+ readonly wasmboard_result: (a: number) => number;
257
+ readonly wasmboard_result_adjudicated: (a: number, b: number) => number;
258
+ readonly wasmboard_set_hfen_history: (a: number, b: number, c: number) => void;
259
+ readonly wasmboard_termination: (a: number) => [number, number];
260
+ readonly wasmboard_turn: (a: number) => [number, number];
261
+ readonly wasmboard_set_search_history: (a: number, b: number, c: number) => void;
262
+ readonly __wbg_scene3d_free: (a: number, b: number) => void;
263
+ readonly init: () => void;
264
+ readonly scene3d_animate_move: (a: number, b: number, c: number) => void;
265
+ readonly scene3d_create: (a: any) => any;
266
+ readonly scene3d_is_animating: (a: number) => number;
267
+ readonly scene3d_orbit: (a: number, b: number, c: number) => void;
268
+ readonly scene3d_pick: (a: number, b: number, c: number) => number;
269
+ readonly scene3d_render: (a: number) => void;
270
+ readonly scene3d_resize: (a: number, b: number, c: number) => void;
271
+ readonly scene3d_set_board: (a: number, b: number, c: number, d: number) => void;
272
+ readonly scene3d_set_selection: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
273
+ readonly scene3d_zoom: (a: number, b: number) => void;
274
+ readonly wasm_bindgen__convert__closures_____invoke__hb0b40ee7dfd77fc5: (a: number, b: number, c: any) => [number, number];
275
+ readonly wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a: (a: number, b: number, c: any) => [number, number];
276
+ readonly wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a_2: (a: number, b: number, c: any) => [number, number];
277
+ readonly wasm_bindgen__convert__closures_____invoke__h050ffcb604d90a8a_3: (a: number, b: number, c: any) => [number, number];
278
+ readonly wasm_bindgen__convert__closures_____invoke__h73e935f3b365ecab: (a: number, b: number, c: any, d: any) => void;
279
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
280
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
281
+ readonly __wbindgen_exn_store: (a: number) => void;
282
+ readonly __externref_table_alloc: () => number;
283
+ readonly __wbindgen_externrefs: WebAssembly.Table;
284
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
285
+ readonly __wbindgen_destroy_closure: (a: number, b: number) => void;
286
+ readonly __externref_table_dealloc: (a: number) => void;
287
+ readonly __wbindgen_start: () => void;
288
+ }
289
+
290
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
291
+
292
+ /**
293
+ * Instantiates the given `module`, which can either be bytes or
294
+ * a precompiled `WebAssembly.Module`.
295
+ *
296
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
297
+ *
298
+ * @returns {InitOutput}
299
+ */
300
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
301
+
302
+ /**
303
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
304
+ * for everything else, calls `WebAssembly.instantiate` directly.
305
+ *
306
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
307
+ *
308
+ * @returns {Promise<InitOutput>}
309
+ */
310
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;