@hopple/sdk 1.0.0-next.5 → 1.0.0-next.9

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.
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/analytics.d.ts
1
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/analytics.d.ts
2
2
  /**
3
3
  * What a game says happened.
4
4
  *
@@ -29,7 +29,7 @@ type AnalyticsValue = string | number | boolean;
29
29
  /** @group Analytics */
30
30
  type AnalyticsProps = Record<string, AnalyticsValue>;
31
31
  //#endregion
32
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/errors.d.ts
32
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/errors.d.ts
33
33
  /**
34
34
  * How a call fails.
35
35
  *
@@ -115,7 +115,7 @@ declare class BridgeError extends Error {
115
115
  constructor(error: ProtocolError);
116
116
  }
117
117
  //#endregion
118
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/input.d.ts
118
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/input.d.ts
119
119
  /**
120
120
  * What the host says about how this game is being played.
121
121
  *
@@ -175,7 +175,7 @@ type InputBinding = {
175
175
  label?: string;
176
176
  };
177
177
  //#endregion
178
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/pause.d.ts
178
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/pause.d.ts
179
179
  /**
180
180
  * Whether the game is holding still, which the host may ask for and only the
181
181
  * game can answer.
@@ -233,7 +233,7 @@ type PauseState =
233
233
  */
234
234
  'unpausable';
235
235
  //#endregion
236
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/save.d.ts
236
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/save.d.ts
237
237
  /**
238
238
  * The one thing a game may keep.
239
239
  *
@@ -285,7 +285,7 @@ type SaveStored = {
285
285
  bytes: number;
286
286
  };
287
287
  //#endregion
288
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/score.d.ts
288
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/score.d.ts
289
289
  /**
290
290
  * What the host says came of it.
291
291
  *
@@ -323,7 +323,7 @@ type ScoreStanding = {
323
323
  of?: number;
324
324
  };
325
325
  //#endregion
326
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/share.d.ts
326
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/share.d.ts
327
327
  /**
328
328
  * A link to this game, offered to the player by the host.
329
329
  *
@@ -423,7 +423,7 @@ type ShareMeta = {
423
423
  [key: string]: ShareMetaValue;
424
424
  };
425
425
  //#endregion
426
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/methods.d.ts
426
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/methods.d.ts
427
427
  /**
428
428
  * How far a game has got with its own preparation.
429
429
  *
@@ -603,7 +603,7 @@ type DeviceInfo = {
603
603
  tier: DeviceTier;
604
604
  };
605
605
  //#endregion
606
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/protocol/src/listeners.d.ts
606
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/protocol/src/listeners.d.ts
607
607
  /**
608
608
  * The one way anything here is listened to: `on(listener)` hands back the
609
609
  * function that stops it.
@@ -632,7 +632,7 @@ type DeviceInfo = {
632
632
  */
633
633
  type Unsubscribe = () => void;
634
634
  //#endregion
635
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/manifest/src/manifest.d.ts
635
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/manifest/src/manifest.d.ts
636
636
  /**
637
637
  * The API a game is written against: `M.m`, a major and the least minor it
638
638
  * needs, or `next`, the pre-releases of the next stable release.
@@ -1121,7 +1121,7 @@ type InputDeviceSet = InputDevice[];
1121
1121
  * doubled. A thumbstick is not one of these; see `InputStick`.
1122
1122
  *
1123
1123
  * @group Input
1124
- * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
1124
+ * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right|wheelup|wheeldown)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
1125
1125
  * @errorMessage is not a binding this SDK knows (a thumbstick is read rather than bound, and Escape is the host's key)
1126
1126
  */
1127
1127
  type InputBinding$1 = string;
@@ -1197,7 +1197,7 @@ type PlayerBinding = string;
1197
1197
  * mouse button.
1198
1198
  *
1199
1199
  * @group Input
1200
- * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\.(?:left|middle|right))$
1200
+ * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\.(?:left|middle|right|wheelup|wheeldown))$
1201
1201
  * @errorMessage must be a key or a mouse button (and Escape is the host's key)
1202
1202
  */
1203
1203
  type KeyboardBinding = string;
@@ -1705,7 +1705,7 @@ type ProjectManifest = Omit<GameManifest, 'api'> & {
1705
1705
  api?: ApiVersion;
1706
1706
  };
1707
1707
  //#endregion
1708
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/achievements.d.ts
1708
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/achievements.d.ts
1709
1709
  /**
1710
1710
  * Where this player stands on one achievement.
1711
1711
  *
@@ -1803,7 +1803,7 @@ type Achievements<Id extends string = string, Measured extends string = Id> = {
1803
1803
  progress(id: Measured, value: number): void;
1804
1804
  };
1805
1805
  //#endregion
1806
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/analytics.d.ts
1806
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/analytics.d.ts
1807
1807
  /**
1808
1808
  * @group Analytics
1809
1809
  * @category Important
@@ -1820,7 +1820,7 @@ type Analytics<Events extends object = Record<string, AnalyticsProps>> = {
1820
1820
  track<Event extends keyof Events & string>(name: Event, props?: Events[Event]): void;
1821
1821
  };
1822
1822
  //#endregion
1823
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/audio.d.ts
1823
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/audio.d.ts
1824
1824
  /**
1825
1825
  * Something about the game's sound changed: the host's order, the player's
1826
1826
  * mute, a fader. Read what you need — `volume(channel)`, `allowed` — and apply
@@ -1911,7 +1911,7 @@ type Audio<Channel extends string = string> = {
1911
1911
  media(element: HTMLMediaElement, channel?: Channel): Unsubscribe;
1912
1912
  };
1913
1913
  //#endregion
1914
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/info.d.ts
1914
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/info.d.ts
1915
1915
  /**
1916
1916
  * What the host said, frozen.
1917
1917
  *
@@ -1929,7 +1929,7 @@ type Info = Readonly<{
1929
1929
  device: Readonly<DeviceInfo>;
1930
1930
  }>;
1931
1931
  //#endregion
1932
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/layout.d.ts
1932
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/layout.d.ts
1933
1933
  /**
1934
1934
  * How much of each edge belongs to the host. CSS pixels.
1935
1935
  *
@@ -2039,7 +2039,7 @@ type InsetPolicy = {
2039
2039
  */
2040
2040
  declare function insetsFrom(obstructions: readonly Obstruction[], frame: Size, policy?: InsetPolicy): Insets;
2041
2041
  //#endregion
2042
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/names.d.ts
2042
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/names.d.ts
2043
2043
  /**
2044
2044
  * The keys of a declared map, or `string` where the map is not a literal one —
2045
2045
  * which is what a manifest typed as the wide `GameManifest` gives — and
@@ -2159,7 +2159,7 @@ type EventProps<M> = M extends {
2159
2159
  */
2160
2160
  type StickName = 'pad.left.stick' | 'pad.right.stick' | 'pad.stick' | `controls.${string}`;
2161
2161
  //#endregion
2162
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/input/state.d.ts
2162
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/input/state.d.ts
2163
2163
  /**
2164
2164
  * Where the pointer is, in the frame's own coordinates.
2165
2165
  *
@@ -2220,7 +2220,7 @@ type InputSnapshot<Action extends string = string> = {
2220
2220
  pointer: PointerState | null;
2221
2221
  };
2222
2222
  //#endregion
2223
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/input/players.d.ts
2223
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/input/players.d.ts
2224
2224
  /**
2225
2225
  * What one player holds: a pad, one part of the keyboard, or the on-screen
2226
2226
  * controls.
@@ -2242,7 +2242,178 @@ type Controller =
2242
2242
  kind: 'touch';
2243
2243
  };
2244
2244
  //#endregion
2245
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/input/index.d.ts
2245
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/input/gestures.d.ts
2246
+ /**
2247
+ * Dragging, pinching and wheeling a view around, and tapping on it: what a map,
2248
+ * a board or a level editor does with a pointer, done once.
2249
+ *
2250
+ * Every game that wrote this itself got some of it wrong, in the same few
2251
+ * ways: a cancelled touch that counted as a tap, a third finger that made the
2252
+ * view jump, a drag that stuck when the mouse was let go outside the frame, a
2253
+ * trackpad that zoomed six times slower than a wheel, a wheel that barely
2254
+ * moved in Firefox. So a game says what a drag, a pinch and a tap do to it,
2255
+ * and the SDK decides which one the player is making.
2256
+ */
2257
+ /**
2258
+ * A mouse button, by where it is.
2259
+ *
2260
+ * @group Input
2261
+ */
2262
+ type GestureButton = 'left' | 'middle' | 'right';
2263
+ /**
2264
+ * What a game does with each gesture. Every coordinate is in CSS pixels from
2265
+ * the element's top left corner.
2266
+ *
2267
+ * @group Input
2268
+ */
2269
+ type GestureHandlers = {
2270
+ /** Something dragged the view by this much: a finger, two, a mouse button, or a trackpad's two-finger scroll. */
2271
+ pan?(dx: number, dy: number): void;
2272
+ /**
2273
+ * Something zoomed it by this factor, keeping the point at `x`, `y` where it
2274
+ * is: a pinch, a mouse wheel, or a trackpad pinch. Above 1 is closer.
2275
+ */
2276
+ zoom?(factor: number, x: number, y: number): void;
2277
+ /**
2278
+ * A press that let go where it started, and was the only one: never a drag,
2279
+ * never part of a pinch, never cancelled by the browser.
2280
+ */
2281
+ tap?(x: number, y: number, button: GestureButton | 'touch'): void;
2282
+ };
2283
+ /**
2284
+ * @group Input
2285
+ */
2286
+ type GestureOptions = GestureHandlers & {
2287
+ /**
2288
+ * A view to move: its `pan` and `zoom` are the handlers, beside a `tap` of
2289
+ * the game's own.
2290
+ */
2291
+ view?: View;
2292
+ /**
2293
+ * Which mouse buttons drag. A finger always does. `['left', 'middle']` when
2294
+ * left out; the right button is a game's to bind.
2295
+ */
2296
+ drag?: readonly GestureButton[];
2297
+ /**
2298
+ * What a mouse wheel and a trackpad's two-finger scroll do. `'zoom'`, the
2299
+ * default, zooms with a wheel and pans with a trackpad, the way maps do;
2300
+ * `'pan'` pans with both; `'none'` leaves both alone, for a game that binds
2301
+ * `mouse.wheelup`. A pinch on a trackpad zooms whatever this says.
2302
+ */
2303
+ wheel?: 'zoom' | 'pan' | 'none';
2304
+ /** How far a press may move, in CSS pixels, before it is a drag rather than a tap. 8 when left out. */
2305
+ slop?: number;
2306
+ };
2307
+ /**
2308
+ * Gestures being read off an element: `input.gestures`.
2309
+ *
2310
+ * @group Input
2311
+ */
2312
+ type Gestures = {
2313
+ /** Whether a finger or a dragging button is down on the element now. */
2314
+ readonly active: boolean;
2315
+ /** Stop reading them, and give the element back its `touch-action`. */
2316
+ dispose(): void;
2317
+ };
2318
+ /**
2319
+ * A camera over a flat world, moved by gestures: `input.view`.
2320
+ *
2321
+ * The world is in a game's own units, with `y` down; `scale` is CSS pixels to
2322
+ * one of them, and `x`, `y` the world point at the element's top left corner.
2323
+ * A game draws with them, `screen = (world - x) * scale`, and may set any of
2324
+ * them; each gesture keeps them inside `min`, `max` and `bounds`.
2325
+ *
2326
+ * @group Input
2327
+ */
2328
+ type View = {
2329
+ x: number;
2330
+ y: number;
2331
+ scale: number;
2332
+ /** Drag the view by this many CSS pixels, the world following the finger. */
2333
+ pan(dx: number, dy: number): void;
2334
+ /** Zoom by this factor, the world point at `x`, `y` staying where it is. */
2335
+ zoom(factor: number, x: number, y: number): void;
2336
+ /** Put the world point `x`, `y` in the middle of the element, at `scale` if given. */
2337
+ look(x: number, y: number, scale?: number): void;
2338
+ /** The world point at a point on the element. */
2339
+ toWorld(x: number, y: number): {
2340
+ x: number;
2341
+ y: number;
2342
+ };
2343
+ /** The point on the element a world point is drawn at. */
2344
+ toScreen(x: number, y: number): {
2345
+ x: number;
2346
+ y: number;
2347
+ };
2348
+ /**
2349
+ * Say how big the element is, in CSS pixels: what `look` centres on and
2350
+ * `bounds` keeps filled. Call it whenever the element changes size.
2351
+ */
2352
+ resize(width: number, height: number): void;
2353
+ };
2354
+ /**
2355
+ * @group Input
2356
+ */
2357
+ type ViewOptions = {
2358
+ x?: number;
2359
+ y?: number;
2360
+ scale?: number;
2361
+ /** The least `scale` a gesture zooms out to. */
2362
+ min?: number;
2363
+ /** The most `scale` a gesture zooms in to. */
2364
+ max?: number;
2365
+ /**
2366
+ * The part of the world the view stays over, in world units: never scrolled
2367
+ * past an edge, and centred on it once all of it fits.
2368
+ */
2369
+ bounds?: {
2370
+ x: number;
2371
+ y: number;
2372
+ width: number;
2373
+ height: number;
2374
+ };
2375
+ /** The element's size in CSS pixels, as `resize` takes it. */
2376
+ width?: number;
2377
+ height?: number;
2378
+ };
2379
+ //#endregion
2380
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/input/lock.d.ts
2381
+ /**
2382
+ * The mouse held to the game: `input.pointerLock`.
2383
+ *
2384
+ * @group Input
2385
+ */
2386
+ type PointerLock = {
2387
+ /** Whether the mouse is locked to the game now. */
2388
+ readonly locked: boolean;
2389
+ /**
2390
+ * Lock the mouse to an element, the whole page when left out, now if the
2391
+ * browser allows it and on the player's next click or key if not.
2392
+ *
2393
+ * Asked again after the player has just left a lock, the browser makes them
2394
+ * wait about a second; the SDK waits with them. Ask from a press of the
2395
+ * player's where you can, a click on the game or the key that resumes it:
2396
+ * from a frame loop, the browser may not take it until they press something.
2397
+ */
2398
+ request(element?: Element): void;
2399
+ /** Let the mouse go, and stop waiting to take it. */
2400
+ release(): void;
2401
+ /**
2402
+ * Run this when the lock is taken or lost. Lost without `release` is the
2403
+ * player leaving it, with Escape or by switching away: the time to pause.
2404
+ * The SDK does not take it back on its own; `request` again on resuming.
2405
+ */
2406
+ on(listener: (locked: boolean) => void): Unsubscribe;
2407
+ /**
2408
+ * Run this for each move of the mouse while it is locked, in CSS pixels,
2409
+ * or in the mouse's own counts where the browser gives those
2410
+ * (`unadjustedMovement`). The jumps a browser sends as a lock starts are
2411
+ * left out.
2412
+ */
2413
+ onMove(listener: (dx: number, dy: number) => void): Unsubscribe;
2414
+ };
2415
+ //#endregion
2416
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/input/index.d.ts
2246
2417
  /**
2247
2418
  * A binding a game can name on its own, for a prompt about a button that is
2248
2419
  * not one of its actions: `pad.start`, `key.Space`.
@@ -2379,6 +2550,28 @@ type Input<Action extends string = string, Layout extends string = string, Playe
2379
2550
  suspend(): void;
2380
2551
  resume(): void;
2381
2552
  readonly suspended: boolean;
2553
+ /**
2554
+ * Read drags, pinches, wheels and taps off an element, and say what each
2555
+ * did: for a map, a board, a level editor.
2556
+ *
2557
+ * const view = hopple.input.view({ min: 0.5, max: 4, bounds: world });
2558
+ * hopple.input.gestures(canvas, { view, tap: (x, y) => select(view.toWorld(x, y)) });
2559
+ *
2560
+ * One finger or a mouse button drags; two fingers pinch, and pan as they
2561
+ * go; a mouse wheel zooms around the pointer and a trackpad scrolls and
2562
+ * pinches, at one speed in every browser. A tap is a press that let go where
2563
+ * it started and was the only one. The element gets `touch-action: none`
2564
+ * until `dispose`.
2565
+ */
2566
+ gestures(element: Element, options: GestureOptions): Gestures;
2567
+ /**
2568
+ * A camera over a flat world that `gestures` moves, kept between `min` and
2569
+ * `max` and over `bounds`. Nothing in it is drawn: a game reads `x`, `y`
2570
+ * and `scale` when it draws.
2571
+ */
2572
+ view(options?: ViewOptions): View;
2573
+ /** The mouse held to the game, for a game that turns a camera with it. */
2574
+ readonly pointerLock: PointerLock;
2382
2575
  /**
2383
2576
  * The players on this device, each with their own copy of the actions
2384
2577
  * `input.player` declares, by `slot`. Empty for a game that declares none;
@@ -2479,7 +2672,7 @@ type Controls<Layout extends string = string> = {
2479
2672
  readonly available: boolean;
2480
2673
  };
2481
2674
  //#endregion
2482
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/lifecycle.d.ts
2675
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/lifecycle.d.ts
2483
2676
  /** @group Lifecycle */
2484
2677
  type LifecycleListener = (phase: Phase, previous: Phase) => void | Promise<void>;
2485
2678
  /**
@@ -2498,7 +2691,7 @@ type Lifecycle = {
2498
2691
  on(listener: LifecycleListener): Unsubscribe;
2499
2692
  };
2500
2693
  //#endregion
2501
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/loop.d.ts
2694
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/loop.d.ts
2502
2695
  /**
2503
2696
  * The host has let the game run its loop, or stopped it. Return a promise to
2504
2697
  * make the host wait.
@@ -2552,7 +2745,7 @@ type Loop = {
2552
2745
  tick(frame: FrameCallback): Unsubscribe;
2553
2746
  };
2554
2747
  //#endregion
2555
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/panel.d.ts
2748
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/panel.d.ts
2556
2749
  /**
2557
2750
  * The pages of the host's panel a game has a name for, as the keys of this
2558
2751
  * interface.
@@ -2690,7 +2883,7 @@ type Panel = {
2690
2883
  open(page: PageId): void;
2691
2884
  };
2692
2885
  //#endregion
2693
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/pause.d.ts
2886
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/pause.d.ts
2694
2887
  /**
2695
2888
  * The host has asked for a pause, or for the game to carry on.
2696
2889
  *
@@ -2751,7 +2944,7 @@ type Pause = {
2751
2944
  on(listener: PauseListener): Unsubscribe;
2752
2945
  };
2753
2946
  //#endregion
2754
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/resources.d.ts
2947
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/resources.d.ts
2755
2948
  /**
2756
2949
  * The host has let the game hold its resources again, or asked for them back.
2757
2950
  * Return a promise to make the host wait until they have gone, or come back.
@@ -2781,7 +2974,7 @@ type Resources = {
2781
2974
  on(listener: ResourcesListener): Unsubscribe;
2782
2975
  };
2783
2976
  //#endregion
2784
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/save.d.ts
2977
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/save.d.ts
2785
2978
  /**
2786
2979
  * What a game gets back from a read: its own schema number, and its state.
2787
2980
  *
@@ -2956,7 +3149,7 @@ type Save = {
2956
3149
  readonly maxBytes: number;
2957
3150
  };
2958
3151
  //#endregion
2959
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/score.d.ts
3152
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/score.d.ts
2960
3153
  /**
2961
3154
  * Where this player stands on every board, as far as anybody has said.
2962
3155
  *
@@ -3033,7 +3226,7 @@ type Score<Board extends string = string> = {
3033
3226
  }): Promise<ScoreResult>;
3034
3227
  };
3035
3228
  //#endregion
3036
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/share.d.ts
3229
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/share.d.ts
3037
3230
  /**
3038
3231
  * @group Share
3039
3232
  * @category Important
@@ -3117,7 +3310,7 @@ type Share = {
3117
3310
  }): void;
3118
3311
  };
3119
3312
  //#endregion
3120
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/game/src/init.d.ts
3313
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/game/src/init.d.ts
3121
3314
  /**
3122
3315
  * What `init` hands back: every namespace a game has, on one object.
3123
3316
  *
@@ -3413,4 +3606,4 @@ type InitOptions = {
3413
3606
  */
3414
3607
  declare function init<M extends object = GameManifest>(options?: InitOptions): Promise<GameSdk<M>>;
3415
3608
  //#endregion
3416
- export { type Achievement, type AchievementDeclaration, type AchievementListener, type AchievementName, type AchievementProgress, type AchievementStanding, type AchievementStatus, type AchievementTier, type Achievements, type ActionListener, type ActionName, type Analytics, type AnalyticsDeclaration, type AnalyticsProps, type AnalyticsShape, type AnalyticsType, type AnalyticsValue, type ApiVersion, type AppInfo, type AppSurface, type Audio, type AudioChannel, type AudioDeclaration, type AudioListener, type BoardName, BridgeError, type ButtonName, type ChannelName, type ControlLayout, type ControlShape, type ControlSlot, type ControlZone, type Controller, type Controls, type DeclaredNames, type DeclaredValue, type DeviceInfo, type DeviceTier, type ErrorCode, type ErrorCodes, type EventName, type EventProps, type FrameCallback, type GameInfo, type GameManifest, type GameSdk, type Info, type InitOptions, type Input, type InputAction, type InputBinding, type InputDeclaration, type InputDevice, type InputListener, type InputScheme, type InputSnapshot, type InputState, type InsetMode, type InsetPolicy, type Insets, type Layout, type LayoutDeclaration, type LayoutListener, type LayoutName, type LayoutState, type Lifecycle, type LifecycleListener, type Loop, type LoopListener, MAX_STEP, type MeasuredName, type Obstruction, type ObstructionKind, type Orientation, type PageId, type Panel, type PanelListener, type PanelPages, type PanelState, type Pause, type PauseListener, type PauseState, type Phase, type Player, type PlayerActionName, type PlayerInfo, type PointerListener, type PointerState, type ProjectManifest, type Rect, type Resources, type ResourcesListener, SAVE_BYTES, SHARE_BYTES, SHARE_META_BYTES, type Save, type SaveChangeListener, type SaveChangeReason, type SaveDeclaration, type SaveListener, type SaveMerger, type SaveSetup, type SaveState, type SaveStatus, type SaveStored, type Score, type ScoreBoard, type ScoreDeclaration, type ScoreDirection, type ScoreFormat, type ScoreListener, type ScoreResult, type ScoreStanding, type ScoreStandings, type Share, type ShareMeta, type ShareMetaValue, type Size, type StickListener, type StickName, type StickState, type Unsubscribe, init, insetsFrom };
3609
+ export { type Achievement, type AchievementDeclaration, type AchievementListener, type AchievementName, type AchievementProgress, type AchievementStanding, type AchievementStatus, type AchievementTier, type Achievements, type ActionListener, type ActionName, type Analytics, type AnalyticsDeclaration, type AnalyticsProps, type AnalyticsShape, type AnalyticsType, type AnalyticsValue, type ApiVersion, type AppInfo, type AppSurface, type Audio, type AudioChannel, type AudioDeclaration, type AudioListener, type BoardName, BridgeError, type ButtonName, type ChannelName, type ControlLayout, type ControlShape, type ControlSlot, type ControlZone, type Controller, type Controls, type DeclaredNames, type DeclaredValue, type DeviceInfo, type DeviceTier, type ErrorCode, type ErrorCodes, type EventName, type EventProps, type FrameCallback, type GameInfo, type GameManifest, type GameSdk, type GestureButton, type GestureHandlers, type GestureOptions, type Gestures, type Info, type InitOptions, type Input, type InputAction, type InputBinding, type InputDeclaration, type InputDevice, type InputListener, type InputScheme, type InputSnapshot, type InputState, type InsetMode, type InsetPolicy, type Insets, type Layout, type LayoutDeclaration, type LayoutListener, type LayoutName, type LayoutState, type Lifecycle, type LifecycleListener, type Loop, type LoopListener, MAX_STEP, type MeasuredName, type Obstruction, type ObstructionKind, type Orientation, type PageId, type Panel, type PanelListener, type PanelPages, type PanelState, type Pause, type PauseListener, type PauseState, type Phase, type Player, type PlayerActionName, type PlayerInfo, type PointerListener, type PointerLock, type PointerState, type ProjectManifest, type Rect, type Resources, type ResourcesListener, SAVE_BYTES, SHARE_BYTES, SHARE_META_BYTES, type Save, type SaveChangeListener, type SaveChangeReason, type SaveDeclaration, type SaveListener, type SaveMerger, type SaveSetup, type SaveState, type SaveStatus, type SaveStored, type Score, type ScoreBoard, type ScoreDeclaration, type ScoreDirection, type ScoreFormat, type ScoreListener, type ScoreResult, type ScoreStanding, type ScoreStandings, type Share, type ShareMeta, type ShareMetaValue, type Size, type StickListener, type StickName, type StickState, type Unsubscribe, type View, type ViewOptions, init, insetsFrom };
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @hopple/sdk 1.0.0-next.5 | Copyright (c) 2026 The Hopple authors | MIT License */
1
+ /*! @hopple/sdk | Copyright (c) 2026 The Hopple authors | MIT License */
2
2
  // The SDK runs from the runtime the page loads as its first script, which
3
3
  // defines the global `Hopple`; this forwards each export to it.
4
4
  const runtime = globalThis.Hopple;
package/manifest.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../../../../../../../tmp/hopple-sdk-types-ky983p/manifest/src/manifest.d.ts
1
+ //#region ../../../../../../../tmp/hopple-sdk-types-BSfTrJ/manifest/src/manifest.d.ts
2
2
  /**
3
3
  * The API a game is written against: `M.m`, a major and the least minor it
4
4
  * needs, or `next`, the pre-releases of the next stable release.
@@ -487,7 +487,7 @@ type InputDeviceSet = InputDevice[];
487
487
  * doubled. A thumbstick is not one of these; see `InputStick`.
488
488
  *
489
489
  * @group Input
490
- * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
490
+ * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right|wheelup|wheeldown)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
491
491
  * @errorMessage is not a binding this SDK knows (a thumbstick is read rather than bound, and Escape is the host's key)
492
492
  */
493
493
  type InputBinding = string;
@@ -563,7 +563,7 @@ type PlayerBinding = string;
563
563
  * mouse button.
564
564
  *
565
565
  * @group Input
566
- * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\.(?:left|middle|right))$
566
+ * @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\.(?:left|middle|right|wheelup|wheeldown))$
567
567
  * @errorMessage must be a key or a mouse button (and Escape is the host's key)
568
568
  */
569
569
  type KeyboardBinding = string;
package/manifest.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @hopple/sdk 1.0.0-next.5 | Copyright (c) 2026 The Hopple authors | MIT License */
1
+ /*! @hopple/sdk 1.0.0-next.9 | Copyright (c) 2026 The Hopple authors | MIT License */
2
2
  //#region ../manifest/src/manifest.schema.ts
3
3
  const GameManifest = {
4
4
  "type": "object",
@@ -375,7 +375,7 @@ const InputBindings = {
375
375
  };
376
376
  const InputBinding = {
377
377
  "type": "string",
378
- "pattern": "^(?:key\\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\\.(?:primary|secondary)|mouse\\.(?:left|middle|right)|touch\\.tap|controls\\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\\.(?:north|south|east|west|start|select)|pad\\.(?:left|right)\\.(?:north|south|east|west|bumper|trigger))$",
378
+ "pattern": "^(?:key\\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\\.(?:primary|secondary)|mouse\\.(?:left|middle|right|wheelup|wheeldown)|touch\\.tap|controls\\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\\.(?:north|south|east|west|start|select)|pad\\.(?:left|right)\\.(?:north|south|east|west|bumper|trigger))$",
379
379
  "errorMessage": "is not a binding this SDK knows (a thumbstick is read rather than bound, and Escape is the host's key)"
380
380
  };
381
381
  const ControlLayout = {
@@ -572,7 +572,7 @@ const definitions = {
572
572
  },
573
573
  KeyboardBinding: {
574
574
  "type": "string",
575
- "pattern": "^(?:key\\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\\.(?:left|middle|right))$",
575
+ "pattern": "^(?:key\\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\\.(?:left|middle|right|wheelup|wheeldown))$",
576
576
  "errorMessage": "must be a key or a mouse button (and Escape is the host's key)"
577
577
  },
578
578
  PlayersDeclaration: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hopple/sdk",
3
- "version": "1.0.0-next.5",
3
+ "version": "1.0.0-next.9",
4
4
  "description": "The Hopple SDK: what a game imports to talk to the host that runs it, forwarded to the runtime its page loads.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://hopple.app",