@hopple/sdk 0.1.0-rc.3 → 1.0.0-next.12

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/manifest.md CHANGED
@@ -15,51 +15,57 @@ and the host never asks the game what it is allowed to do.
15
15
 
16
16
  ```json
17
17
  {
18
- "schema": 1,
18
+ "api": "1.0",
19
19
  "id": "ping",
20
20
  "version": "1.0.0",
21
21
  "title": "Ping",
22
22
  "orientation": "portrait",
23
- "sdk": "^0.1.0",
24
23
  "audio": null
25
24
  }
26
25
  ```
27
26
 
28
- These seven keys are required. Everything else is optional.
27
+ These six keys are required. Everything else is optional. A hopple config may
28
+ leave `api` and `previews` out: the CLI fills `api` from the installed
29
+ `@hopple/sdk`, and `previews` from the preview packages the project installs.
29
30
 
30
31
  | Key | Rules | Meaning |
31
32
  |---|---|---|
32
- | `schema` | `1` | The manifest format version. |
33
+ | `api` | `MAJOR.MINOR`, or `next` | The API the game is written against: the major picks what the game is served, the minor is the least it needs. `next` is the pre-releases of the next stable release. Left out of a config, the CLI takes it from the installed `@hopple/sdk` (`1.6.2` is `1.6`, a pre-release is `next`), and refuses one that differs. Publishing is refused until the major has a release of that minor, on `next` until it has a release, and on `next` for users who are neither trusted, admins, nor explicitly granted access. |
33
34
  | `id` | lowercase letters, digits and single hyphens; at most 64 characters | The game's name. On the server, a game is `<owner>/<id>`. |
34
35
  | `version` | `MAJOR.MINOR.PATCH`, optional `-prerelease` | The game's own version. Shown to the game as `sdk.info.game.version`. |
35
36
  | `title` | at most 60 characters | What players see. |
36
37
  | `description` | optional; at most 500 characters | A sentence or two shown beside the title. |
38
+ | `genres` | optional; see [`genres`](#genres) | What kind of game it is, the main one first. |
37
39
  | `orientation` | `portrait`, `landscape` or `any` | The shape the game is designed for. Hosts lay the game out to match. |
38
- | `sdk` | a version, optionally with `^` or `~` | The SDK the game was built against. Recorded, not enforced; the protocol handshake is what checks compatibility. |
39
40
  | `audio` | `null`, or an object | Whether the game makes sound, and its volume channels. See [`audio`](#audio). |
40
41
 
41
42
  ## Validating
42
43
 
43
- `hopple check` validates the manifest and names every problem with its field.
44
- The CLI, the dev shell, the server and the clients all use the same function,
45
- so they always agree on whether a manifest is valid.
44
+ `hopple check` validates the manifest and names every problem with its field,
45
+ with the validator of the installed `@hopple/sdk`, which is of the API the
46
+ game declares. The CLI, the dev shell, the server and the clients all use the
47
+ same function, so they agree on whether a manifest is valid.
46
48
 
47
- - **Unknown keys are allowed.** A game built with a newer SDK may declare
48
- things an older host doesn't know about, and must still run there.
49
+ - **Unknown keys are refused.** A misspelt key (such as `"orientaton"`) is an
50
+ error, not silently ignored. A host reading a published manifest ignores
51
+ keys it doesn't know (`validateManifest(value, { lenient: true })`), since
52
+ the game may be written against a newer minor than the host.
49
53
  - **Known keys are checked strictly.** A misspelt value (such as
50
54
  `"draw_under"`) is an error, not silently ignored.
51
55
 
52
56
  ### In an editor
53
57
 
54
- `@hopple/sdk` ships the hopple config's JSON Schema, the manifest's included,
55
- as `config.schema.json`, for completion, hover docs and errors as you type. A
56
- JSON config can point at it:
58
+ The `hopple` CLI ships the hopple config's JSON Schema, the manifest's
59
+ included, as `config.schema.json`, for completion, hover docs and errors as
60
+ you type. A JSON config in a project with `hopple` installed can point at it:
57
61
 
58
62
  ```json
59
- { "$schema": "./node_modules/@hopple/sdk/config.schema.json", "page": "dist/index.html", "manifest": { ... } }
63
+ { "$schema": "./node_modules/hopple/config.schema.json", "page": "dist/index.html", "manifest": { ... } }
60
64
  ```
61
65
 
62
- A TypeScript config gets the same checks from its type, `HoppleConfig`.
66
+ A TypeScript config gets the same checks from its type,
67
+ `import type { HoppleConfig } from 'hopple'`, whose manifest is the type of
68
+ the installed `@hopple/sdk`.
63
69
 
64
70
  A few rules relate one part of a manifest to another, which JSON Schema can't
65
71
  express: buttons must name declared actions, a control's `as` must name its
@@ -138,6 +144,7 @@ A game without this key can still use `sdk.save`.
138
144
  | `title` | yes | What players see. At most 40 characters. |
139
145
  | `direction` | yes | `desc`: higher is better. `asc`: lower is better (times, strokes). |
140
146
  | `format` | no | `integer` (default), `decimal`, or `duration-ms` (so `224310` shows as `3:44.31`). |
147
+ | `version` | no | 1 by default. Raising it starts the board again; see [Changing the manifest in a new version](#changing-the-manifest-in-a-new-version). |
141
148
 
142
149
  `boards` is a map even for one board, so a game can add a second one later
143
150
  without changing the meaning of the first. At most 16 boards.
@@ -176,6 +183,9 @@ There are two kinds:
176
183
  `secret: true` hides the title and detail from players until it is earned.
177
184
  The manifest is public, so this only stops spoilers.
178
185
 
186
+ `version` is 1 by default. Raising it starts the achievement again for
187
+ everybody; see [Changing the manifest in a new version](#changing-the-manifest-in-a-new-version).
188
+
179
189
  Limits: 128 achievements, titles up to 40 characters, details up to 120, icons
180
190
  up to 8 characters, 8 tiers.
181
191
 
@@ -216,7 +226,8 @@ up to 8 characters, 8 tiers.
216
226
  `buttons` (naming actions) arranged as a `row`, `column`, `diamond` or
217
227
  `cluster`. An unknown shape is drawn as a column. A stick held to an axis is
218
228
  drawn as a track and always reads 0 on the other axis; a real pad's stick
219
- still reports both.
229
+ still reports both. Any control may have a `scale` from 0.75 to 1.5, its
230
+ size next to the layout's others (1 when left out).
220
231
 
221
232
  Binding names:
222
233
 
@@ -225,6 +236,7 @@ Binding names:
225
236
  | `key.KeyZ` | A physical key, by `KeyboardEvent.code`. `KeyA` is the same physical key on every keyboard layout. |
226
237
  | `pointer.primary` | A left click or a tap. (`pointer.secondary`: a right click.) |
227
238
  | `mouse.left` | A left click only, not a tap. Also `mouse.middle`, `mouse.right`. |
239
+ | `mouse.wheelup`, `mouse.wheeldown` | A step of the mouse wheel: a press and a release for each notch, and for every stretch of a trackpad swipe. |
228
240
  | `touch.tap` | A tap only, not a click. |
229
241
  | `pad.south` | The bottom face button of either cluster, on any gamepad or on-screen pad. |
230
242
  | `pad.right.south` | The bottom right face button (A on Xbox, cross on PlayStation). |
@@ -242,6 +254,36 @@ the host's sheet; a tap of Start is still the game's.
242
254
 
243
255
  Limits: 64 actions, 8 bindings per action, 8 control layouts.
244
256
 
257
+ #### Several players on one device
258
+
259
+ ```json
260
+ "players": { "local": 4, "online": 8 },
261
+ "input": {
262
+ "actions": { "pause": { "bind": ["key.KeyP", "pad.start"] } },
263
+ "player": {
264
+ "actions": {
265
+ "bomb": { "bind": ["pad.south"], "title": "Drop bomb", "join": true }
266
+ },
267
+ "keyboard": [
268
+ { "title": "Left keys", "bind": { "bomb": ["key.Space"] } },
269
+ { "title": "Arrows", "bind": { "bomb": ["key.Enter"] } }
270
+ ]
271
+ }
272
+ }
273
+ ```
274
+
275
+ - **`input.player.actions`**: what each local player does, a copy each. Their
276
+ `bind` holds pad buttons and on-screen controls only, the same for every
277
+ pad. An id is never one `input.actions` declares too. `join: true` marks the
278
+ actions that seat a new player; on none, any does.
279
+ - **`input.player.keyboard`**: the parts of the keyboard players share, one
280
+ player each (at most 4): a `title` and the keys and mouse buttons of each
281
+ player action. A key in two parts is refused.
282
+ - **`players.local`**: the most players on one device, 1 by default; more
283
+ than 1 needs `input.player`.
284
+
285
+ Limits: 32 player actions.
286
+
245
287
  ### audio
246
288
 
247
289
  ```json
@@ -262,19 +304,84 @@ Each channel gets its own labelled volume slider in the host's sound controls.
262
304
  `title` is required: it is the slider's label. `master` is reserved, since
263
305
  every host already has a master volume. At most 8 channels.
264
306
 
307
+ ### genres
308
+
309
+ ```json
310
+ "genres": ["puzzle", "shooter", "online-multiplayer"]
311
+ ```
312
+
313
+ What kind of game this is, the main one first: at least one, and at most 3
314
+ beside the two multiplayer words, none twice. A game with none declared is
315
+ filed by what its title and description say, and most often less well.
316
+
317
+ The words are `racing`, `shooter`, `platformer`, `puzzle`, `arcade`, `physics`,
318
+ `roguelike`, `strategy`, `building`, `idle`, `sports`, `horror`, `stealth`,
319
+ `fighting`, `casual`, `simulation`, `adventure`, `rhythm` and `rpg`, and two
320
+ that say how it is played together:
321
+
322
+ - **`local-multiplayer`**: several people on one device. Needs `players.local`
323
+ above 1.
324
+ - **`online-multiplayer`**: over the network. Needs `previews.network`.
325
+
326
+ Either of those without what it needs is not refused: the game is published,
327
+ that word is ignored, and `hopple check`, `hopple upload` and `hopple publish`
328
+ warn about it. They warn the other way round too, for a game that declares
329
+ `genres` and leaves out a way of playing together its manifest shows, since it
330
+ then is not listed as one. Clients group the two under one shelf.
331
+
332
+ ### previews
333
+
334
+ ```json
335
+ "previews": { "network": 1 }
336
+ ```
337
+
338
+ The parts of the SDK that are not stable yet, each at the revision the game
339
+ is written against. A preview is its own `0.x` package, versioned apart from
340
+ `api`: revision `R` is `@hopple/sdk-preview-network` `0.R.x`. A game is served a runtime
341
+ with the previews it declares, at those revisions, so a change to a preview
342
+ reaches only the games written against it. A breaking change is a new
343
+ revision. A name nobody knows is refused, and a revision is a whole number
344
+ from 1.
345
+
346
+ Left out of a config, the CLI fills each preview from its installed package,
347
+ for a project whose `package.json` lists it, as it fills `api`, and refuses
348
+ one that differs from the installed revision, or that names one with none
349
+ installed. Publishing a game that declares any preview needs what `next`
350
+ needs. Once a newer revision of a preview is out, the older one is retired:
351
+ games whose `latest` is on it are unlisted and lose `beta`, keeping their
352
+ approval and links, and an upload declaring it is refused.
353
+
354
+ - **`network`**: the game plays over the network, in matches: `sdk.match`,
355
+ typed by `@hopple/sdk-preview-network`. It is the permission a reviewer grants, and what
356
+ lets a host offer *Play with friends* before the game has loaded. Nothing
357
+ else is declared: how a match is played, and its size, are chosen when the
358
+ game makes one.
359
+ Without it, a game is never told about a match, and `sdk.match` is not
360
+ there.
361
+
265
362
  ## Changing the manifest in a new version
266
363
 
267
- The server refuses a new version whose manifest would corrupt data players
268
- already have:
269
-
270
- - **A score board that has scores can't be removed or change direction.**
271
- Removing it would orphan the scores (and renaming a board looks like removing
272
- it); flipping `direction` would turn the whole board upside down. An admin
273
- can clear the board first if that is really what you want.
274
- - **A published achievement can't be changed.** Its title, detail, icon, secret
275
- flag, kind, target, direction, format and tiers are fixed, because players already
276
- hold it. You can add new achievements, and you can stop declaring old ones
277
- (what players earned is kept).
364
+ Every board and every achievement has a `version`, 1 when left out. The
365
+ server refuses a new version of the game whose manifest would change what data
366
+ players already have means, and the way out is always to raise that board's or
367
+ achievement's `version`: it starts again from nobody under the same id, and
368
+ what was stored under the version before is kept but no longer counted.
369
+
370
+ - **Boards and achievements can be added and dropped freely.** What players
371
+ stored under one that is dropped is kept, and comes back if it is declared
372
+ again.
373
+ - **A board's title can change, and so can its format between `integer` and
374
+ `decimal`.** Once it has scores, flipping its `direction` or moving its
375
+ format to or from `duration-ms` needs a new `version`.
376
+ - **An achievement's title, detail, icon and secret flag can change, and so can
377
+ its target; tiers can be added after the last one.** Progress is kept as the
378
+ number reported, so a player at 12 of 12 is at 12 of 25 when the target is
379
+ raised, and keeps the unlock; when it is lowered past them, they have it.
380
+ Turning a flag into a measured achievement or back, flipping `direction`,
381
+ moving its format to or from `duration-ms`, or moving or dropping a tier it
382
+ already has needs a new `version`, whether or not anybody holds it yet.
383
+ - **A version declared again is held to what it was**, since what was stored
384
+ under it comes back.
278
385
 
279
386
  Input action ids and audio channel ids may change freely. A player's remapped
280
387
  keys or volume settings for an id that no longer exists are simply dropped.
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@hopple/sdk",
3
- "version": "0.1.0-rc.3",
3
+ "version": "1.0.0-next.12",
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",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/pamarit/hopple.git"
10
+ },
7
11
  "keywords": [
8
12
  "hopple",
9
13
  "game",
@@ -21,7 +25,10 @@
21
25
  "types": "./index.d.ts",
22
26
  "default": "./index.js"
23
27
  },
24
- "./config.schema.json": "./config.schema.json",
28
+ "./manifest": {
29
+ "types": "./manifest.d.ts",
30
+ "default": "./manifest.js"
31
+ },
25
32
  "./package.json": "./package.json"
26
33
  },
27
34
  "main": "./index.js",