1681-engine 0.5.9 → 0.5.10

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.
Files changed (140) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +3 -0
  3. package/dist/1681-engine.js +501 -438
  4. package/dist/ambient/life/Birds.js +73 -0
  5. package/dist/ambient/life/Butterflies.js +43 -0
  6. package/dist/ambient/life/ChimneySmoke.js +50 -0
  7. package/dist/ambient/life/Drift.js +75 -0
  8. package/dist/ambient/life/Fireflies.js +52 -0
  9. package/dist/ambient/life/lifeMotion.js +49 -0
  10. package/dist/assets/AssetLoader.js +115 -70
  11. package/dist/assets/Prepainter.js +61 -0
  12. package/dist/assets/workerPainter.js +39 -0
  13. package/dist/cjs/electron/electronLike.d.ts +55 -0
  14. package/dist/cjs/electron/electronLike.js +7 -0
  15. package/dist/cjs/electron/index.d.ts +14 -0
  16. package/dist/cjs/electron/index.js +20 -0
  17. package/dist/cjs/electron/lockdown.d.ts +33 -0
  18. package/dist/cjs/electron/lockdown.js +69 -0
  19. package/dist/cjs/electron/lockdownRules.d.ts +28 -0
  20. package/dist/cjs/electron/lockdownRules.js +61 -0
  21. package/dist/cjs/electron/sessionStore.d.ts +40 -0
  22. package/dist/cjs/electron/sessionStore.js +77 -0
  23. package/dist/cjs/electron/shellId.d.ts +22 -0
  24. package/dist/cjs/electron/shellId.js +31 -0
  25. package/dist/cjs/electron/webFiles.d.ts +13 -0
  26. package/dist/cjs/electron/webFiles.js +52 -0
  27. package/dist/cjs/electron/webPatcher.d.ts +80 -0
  28. package/dist/cjs/electron/webPatcher.js +216 -0
  29. package/dist/cjs/electron/webPointers.d.ts +19 -0
  30. package/dist/cjs/electron/webPointers.js +35 -0
  31. package/dist/cjs/package.json +1 -0
  32. package/dist/cjs/updates/index.d.ts +8 -0
  33. package/dist/cjs/updates/index.js +21 -0
  34. package/dist/cjs/updates/manifest.d.ts +73 -0
  35. package/dist/cjs/updates/manifest.js +67 -0
  36. package/dist/cjs/updates/pickUpdate.d.ts +42 -0
  37. package/dist/cjs/updates/pickUpdate.js +52 -0
  38. package/dist/cjs/updates/webPlan.d.ts +20 -0
  39. package/dist/cjs/updates/webPlan.js +34 -0
  40. package/dist/electron/lockdown.js +31 -0
  41. package/dist/electron/lockdownRules.js +42 -0
  42. package/dist/electron/sessionStore.js +48 -0
  43. package/dist/electron/shellId.js +18 -0
  44. package/dist/electron/webFiles.js +36 -0
  45. package/dist/electron/webPatcher.js +147 -0
  46. package/dist/electron/webPointers.js +25 -0
  47. package/dist/electron.js +19 -0
  48. package/dist/input/haptics.js +50 -0
  49. package/dist/net/ApiClient.js +96 -0
  50. package/dist/pixel/lifeArt.js +83 -0
  51. package/dist/pixel.js +63 -58
  52. package/dist/react/ConfirmButton.js +24 -0
  53. package/dist/react/baseCss.js +1 -0
  54. package/dist/react/labels.js +7 -6
  55. package/dist/react/useJsonSelector.js +13 -0
  56. package/dist/react.js +73 -68
  57. package/dist/tilemap/TilemapView.js +57 -32
  58. package/dist/tilemap/autotile.js +103 -0
  59. package/dist/tilemap/collision.js +29 -18
  60. package/dist/tilemap/ldtk.js +21 -0
  61. package/dist/tilemap/ldtkParse.js +191 -0
  62. package/dist/types/ambient/life/Birds.d.ts +50 -0
  63. package/dist/types/ambient/life/Birds.d.ts.map +1 -0
  64. package/dist/types/ambient/life/Butterflies.d.ts +32 -0
  65. package/dist/types/ambient/life/Butterflies.d.ts.map +1 -0
  66. package/dist/types/ambient/life/ChimneySmoke.d.ts +37 -0
  67. package/dist/types/ambient/life/ChimneySmoke.d.ts.map +1 -0
  68. package/dist/types/ambient/life/Drift.d.ts +58 -0
  69. package/dist/types/ambient/life/Drift.d.ts.map +1 -0
  70. package/dist/types/ambient/life/Fireflies.d.ts +43 -0
  71. package/dist/types/ambient/life/Fireflies.d.ts.map +1 -0
  72. package/dist/types/ambient/life/lifeMotion.d.ts +63 -0
  73. package/dist/types/ambient/life/lifeMotion.d.ts.map +1 -0
  74. package/dist/types/assets/AssetLoader.d.ts +20 -0
  75. package/dist/types/assets/AssetLoader.d.ts.map +1 -1
  76. package/dist/types/assets/Prepainter.d.ts +64 -0
  77. package/dist/types/assets/Prepainter.d.ts.map +1 -0
  78. package/dist/types/assets/workerPainter.d.ts +21 -0
  79. package/dist/types/assets/workerPainter.d.ts.map +1 -0
  80. package/dist/types/electron/electronLike.d.ts +56 -0
  81. package/dist/types/electron/electronLike.d.ts.map +1 -0
  82. package/dist/types/electron/index.d.ts +15 -0
  83. package/dist/types/electron/index.d.ts.map +1 -0
  84. package/dist/types/electron/lockdown.d.ts +34 -0
  85. package/dist/types/electron/lockdown.d.ts.map +1 -0
  86. package/dist/types/electron/lockdownRules.d.ts +29 -0
  87. package/dist/types/electron/lockdownRules.d.ts.map +1 -0
  88. package/dist/types/electron/sessionStore.d.ts +41 -0
  89. package/dist/types/electron/sessionStore.d.ts.map +1 -0
  90. package/dist/types/electron/shellId.d.ts +23 -0
  91. package/dist/types/electron/shellId.d.ts.map +1 -0
  92. package/dist/types/electron/webFiles.d.ts +14 -0
  93. package/dist/types/electron/webFiles.d.ts.map +1 -0
  94. package/dist/types/electron/webPatcher.d.ts +81 -0
  95. package/dist/types/electron/webPatcher.d.ts.map +1 -0
  96. package/dist/types/electron/webPointers.d.ts +20 -0
  97. package/dist/types/electron/webPointers.d.ts.map +1 -0
  98. package/dist/types/index.d.ts +15 -2
  99. package/dist/types/index.d.ts.map +1 -1
  100. package/dist/types/input/haptics.d.ts +42 -0
  101. package/dist/types/input/haptics.d.ts.map +1 -0
  102. package/dist/types/net/ApiClient.d.ts +74 -0
  103. package/dist/types/net/ApiClient.d.ts.map +1 -0
  104. package/dist/types/pixel/index.d.ts +1 -0
  105. package/dist/types/pixel/index.d.ts.map +1 -1
  106. package/dist/types/pixel/lifeArt.d.ts +63 -0
  107. package/dist/types/pixel/lifeArt.d.ts.map +1 -0
  108. package/dist/types/react/ConfirmButton.d.ts +26 -0
  109. package/dist/types/react/ConfirmButton.d.ts.map +1 -0
  110. package/dist/types/react/baseCss.d.ts +1 -1
  111. package/dist/types/react/baseCss.d.ts.map +1 -1
  112. package/dist/types/react/index.d.ts +2 -0
  113. package/dist/types/react/index.d.ts.map +1 -1
  114. package/dist/types/react/labels.d.ts +2 -0
  115. package/dist/types/react/labels.d.ts.map +1 -1
  116. package/dist/types/react/useJsonSelector.d.ts +13 -0
  117. package/dist/types/react/useJsonSelector.d.ts.map +1 -0
  118. package/dist/types/tilemap/TilemapView.d.ts +17 -0
  119. package/dist/types/tilemap/TilemapView.d.ts.map +1 -1
  120. package/dist/types/tilemap/autotile.d.ts +95 -0
  121. package/dist/types/tilemap/autotile.d.ts.map +1 -0
  122. package/dist/types/tilemap/collision.d.ts +8 -0
  123. package/dist/types/tilemap/collision.d.ts.map +1 -1
  124. package/dist/types/tilemap/ldtk.d.ts +97 -0
  125. package/dist/types/tilemap/ldtk.d.ts.map +1 -0
  126. package/dist/types/tilemap/ldtkParse.d.ts +26 -0
  127. package/dist/types/tilemap/ldtkParse.d.ts.map +1 -0
  128. package/dist/types/updates/index.d.ts +9 -0
  129. package/dist/types/updates/index.d.ts.map +1 -0
  130. package/dist/types/updates/manifest.d.ts +74 -0
  131. package/dist/types/updates/manifest.d.ts.map +1 -0
  132. package/dist/types/updates/pickUpdate.d.ts +43 -0
  133. package/dist/types/updates/pickUpdate.d.ts.map +1 -0
  134. package/dist/types/updates/webPlan.d.ts +21 -0
  135. package/dist/types/updates/webPlan.d.ts.map +1 -0
  136. package/dist/updates/manifest.js +35 -0
  137. package/dist/updates/pickUpdate.js +27 -0
  138. package/dist/updates/webPlan.js +14 -0
  139. package/dist/updates.js +15 -0
  140. package/package.json +31 -3
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A buzz on a phone, per kind of moment (a crit landed, a blow taken, a level gained), rate-limited per kind: a cleave
3
+ * clipping six bodies is one buzz, a damage-over-time one buzz, not a stutter. How it buzzes is injected: the default
4
+ * is the Vibration API (`navigator.vibrate`, Android browsers; iOS Safari has none, so it is a silent no-op there), and
5
+ * a native shell hands in its own plugin's call instead.
6
+ */
7
+ /** The shortest gap (ms) between two buzzes of each kind; a kind not named is never held back. */
8
+ export type HapticGaps<K extends string> = Readonly<Partial<Record<K, number>>>;
9
+ /** One buzz per kind per its gap. Pure, so the rule is tested. */
10
+ export declare class HapticGate<K extends string> {
11
+ private readonly gaps;
12
+ private readonly last;
13
+ constructor(gaps?: HapticGaps<K>);
14
+ /** Whether a buzz of `kind` at `now` (ms) may go; one that may is counted. */
15
+ allow(kind: K, now: number): boolean;
16
+ /** Forgets every kind's last buzz. */
17
+ reset(): void;
18
+ }
19
+ export interface HapticsOptions<K extends string> {
20
+ gaps?: HapticGaps<K>;
21
+ /** Plays a buzz. A promise it returns may reject: that is swallowed, a buzz is never worth an error. */
22
+ play?: (kind: K) => unknown;
23
+ /** The Vibration API pattern per kind for the default `play` (ms, or on/off ms; default 15). */
24
+ patterns?: Readonly<Partial<Record<K, number | readonly number[]>>>;
25
+ /** Asked before every buzz (the player's setting, a native-only rule). Default: always. */
26
+ enabled?: () => boolean;
27
+ /** Default `performance.now`. */
28
+ now?: () => number;
29
+ }
30
+ /** The default player: `navigator.vibrate`, where there is one. */
31
+ export declare function vibrate(pattern: number | readonly number[]): boolean;
32
+ /** Buzzes through `play` when `enabled` and the kind's gap has passed. */
33
+ export declare class Haptics<K extends string> {
34
+ private readonly gate;
35
+ private readonly play;
36
+ private readonly enabled;
37
+ private readonly now;
38
+ constructor(options?: HapticsOptions<K>);
39
+ /** Buzzes for `kind`; returns whether it was let through (not whether the device did buzz). */
40
+ buzz(kind: K): boolean;
41
+ }
42
+ //# sourceMappingURL=haptics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haptics.d.ts","sourceRoot":"","sources":["../../../src/input/haptics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kGAAkG;AAClG,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAEhF,kEAAkE;AAClE,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM;IAG1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEhB,IAAI,GAAE,UAAU,CAAC,CAAC,CAAuB;IAEtE,8EAA8E;IAC9E,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAQpC,sCAAsC;IACtC,KAAK,IAAI,IAAI;CAGd;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,MAAM;IAC9C,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACrB,wGAAwG;IACxG,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAC5B,gGAAgG;IAChG,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAID,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAQpE;AAED,0EAA0E;AAC1E,qBAAa,OAAO,CAAC,CAAC,SAAS,MAAM;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,OAAO,GAAE,cAAc,CAAC,CAAC,CAAM;IAO3C,+FAA+F;IAC/F,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO;CAUvB"}
@@ -0,0 +1,74 @@
1
+ export type ApiMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2
+ /**
3
+ * A request that failed. `status` 0 with `code` `'NETWORK'` is no answer at all (offline, a timeout, a refused
4
+ * connection), `'ABORTED'` the caller's own abort; otherwise `status` is the server's, and `code`, `message` and
5
+ * `details` are what `describe` read off its body.
6
+ */
7
+ export declare class ApiError extends Error {
8
+ readonly status: number;
9
+ readonly code: string;
10
+ readonly details?: Readonly<Record<string, string>> | undefined;
11
+ /** The parsed body of the failed answer, when there was one. */
12
+ readonly body?: unknown | undefined;
13
+ constructor(status: number, code: string, message: string, details?: Readonly<Record<string, string>> | undefined,
14
+ /** The parsed body of the failed answer, when there was one. */
15
+ body?: unknown | undefined);
16
+ }
17
+ /** What a failed answer's body says: the default reads `code`, `message` and `details` off a JSON object. */
18
+ export interface ApiErrorInfo {
19
+ code?: string;
20
+ message?: string;
21
+ details?: Readonly<Record<string, string>>;
22
+ }
23
+ /**
24
+ * What a refresh came back with: a new access token, `'refused'` (the session is over), or null (the server could not
25
+ * be asked — keep the session and let the next call try again).
26
+ */
27
+ export type RefreshResult = string | 'refused' | null;
28
+ export interface ApiClientOptions {
29
+ /** The server's origin (`https://host`), or one chosen per path (accounts on one server, the game on another). */
30
+ baseUrl: string | ((path: string) => string);
31
+ /** Headers sent with every request (a client version, a platform), asked afresh each time. */
32
+ headers?: () => Readonly<Record<string, string>>;
33
+ /** Default 10 s; a request may give its own. */
34
+ timeoutMs?: number;
35
+ /** Turns a failed answer's parsed body into its code, message and details (a game rendering its own messages). */
36
+ describe?: (body: unknown, status: number) => ApiErrorInfo;
37
+ /** The message of a request that got no answer (default `'Cannot reach the server.'`). */
38
+ networkMessage?: string | (() => string);
39
+ /** Paths a 401 never refreshes for (the login and refresh calls themselves). */
40
+ noRefresh?: (path: string) => boolean;
41
+ /** Called with every failed answer before it is thrown (an "update required" gate reading `status` or `code`). */
42
+ onError?: (error: ApiError) => void;
43
+ /** Called for answers with one status before it is thrown: `{ 426: (e) => showUpdate(e.details) }`. */
44
+ onStatus?: Readonly<Record<number, (error: ApiError) => void>>;
45
+ /** Default the global `fetch`. */
46
+ fetch?: typeof fetch;
47
+ }
48
+ export interface ApiRequestOptions {
49
+ timeoutMs?: number;
50
+ /** The caller's own abort; its abort throws an `ApiError` with code `'ABORTED'`. */
51
+ signal?: AbortSignal;
52
+ /** Headers for this request alone, over the client's. */
53
+ headers?: Readonly<Record<string, string>>;
54
+ }
55
+ /**
56
+ * A small JSON REST client: a bearer token, JSON in and out, a timeout on every call, and a session kept alive — a 401
57
+ * is refreshed once (`refresher`) and the request sent again. A game keeps its endpoints and types in a subclass or
58
+ * beside it; nothing here knows any route.
59
+ */
60
+ export declare class ApiClient {
61
+ private readonly options;
62
+ private token;
63
+ /** A new access token for a 401 (`RefreshResult`); unset, a 401 is simply thrown. */
64
+ refresher: (() => Promise<RefreshResult>) | null;
65
+ /** Called when a 401 ends the session: no refresher, a refused refresh, or a retry refused again. */
66
+ onUnauthorized: (() => void) | null;
67
+ constructor(options: ApiClientOptions);
68
+ get accessToken(): string | null;
69
+ setToken(token: string | null): void;
70
+ /** Sends a request and returns its parsed JSON body (undefined for an empty or unreadable one). */
71
+ request<T>(method: ApiMethod, path: string, body?: unknown, options?: ApiRequestOptions, retried?: boolean): Promise<T>;
72
+ private networkError;
73
+ }
74
+ //# sourceMappingURL=ApiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiClient.d.ts","sourceRoot":"","sources":["../../../src/net/ApiClient.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ export { spritePixels, NO_PIXELS, PackedPixels, type SpritePixel } from './sprit
24
24
  export { Darkness, WARM_LIGHT, LAMP_DIM, CARRIED_LIGHT, type DarknessOptions } from './Darkness.js';
25
25
  export { flashLight, carriedLight, liveLights, clearLights, type TransientLight } from './lights.js';
26
26
  export { NightShade, type NightShadeOptions } from './NightShade.js';
27
+ export { paintLifeArt, puffPixels, LIFE_COLORS, PUFF_FRAMES, type LifeArt, type LifeColors, type LifePixel } from './lifeArt.js';
27
28
  export { paintWeatherArt, mistPixels, WEATHER_COLORS, type WeatherColors, type WeatherPixel } from './weatherArt.js';
28
29
  export { buildRig, trunkPivot, complement, tileHash, gustAt, swayOffset, type SwayDef, type SwayMode, type TuftRect, type SwayRig, type SwayStrip, type Rect as SwayRect } from './swayRig.js';
29
30
  export { SwayProp, opaqueRowWidths, type SwayPropOptions, type SwayWind } from './SwayProp.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pixel/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EACL,SAAS,EACT,WAAW,EACX,KAAK,EACL,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,KAAK,EACL,GAAG,EACH,SAAS,EACT,KAAK,EACL,KAAK,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,KAAK,KAAK,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,CAAC,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAClF,OAAO,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,IAAI,GACV,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjH,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjF,4FAA4F;AAC5F,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,wEAAwE;AACxE,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAClG,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAClH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,IAAI,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC5L,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pixel/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { TextureRegistry } from '../core/TextureRegistry.js';
2
+ /** A pixel of life art: x, y and a CSS colour. */
3
+ export type LifePixel = readonly [x: number, y: number, color: string];
4
+ /** The colours the life is painted in; every one may be replaced to suit a game's palette. */
5
+ export interface LifeColors {
6
+ /** Each leaf tone, [lit, deep]. */
7
+ leaves: readonly (readonly [string, string])[];
8
+ /** A seed: the whole one, and the second pixel of the longer one. */
9
+ seed: readonly [string, string];
10
+ /** An ember from hot to cool. */
11
+ ember: readonly [string, string, string];
12
+ /** Two motes. */
13
+ mote: readonly [string, string];
14
+ /** Two flakes of ash: [lit, deep] each. */
15
+ ash: readonly (readonly [string, string])[];
16
+ /** Each butterfly tone, [wing, wing's edge]. */
17
+ butterflies: readonly (readonly [string, string])[];
18
+ butterflyBody: string;
19
+ bird: string;
20
+ /** Its shadow's middle and ends (translucent black suits any ground). */
21
+ birdShadow: readonly [middle: string, ends: string];
22
+ /** A firefly's glow and the dim pixels round it. */
23
+ firefly: readonly [lit: string, dim: string];
24
+ /** Smoke: light (up-left), middle, dark (down-right). */
25
+ smoke: readonly [string, string, string];
26
+ }
27
+ export declare const LIFE_COLORS: LifeColors;
28
+ /** The texture keys painted, laid out the way the life classes take them. */
29
+ export interface LifeArt {
30
+ /** `Drift` looks for each kind. */
31
+ leaves: string[][];
32
+ seeds: string[][];
33
+ embers: string[][];
34
+ motes: string[][];
35
+ ash: string[][];
36
+ /** `Butterflies` looks: [open, shut] per tone. */
37
+ butterflies: [string, string][];
38
+ /** `Birds` frames and shadow. */
39
+ bird: [string, string];
40
+ birdShadow: string;
41
+ /** `Fireflies` frames: [dim, lit]. */
42
+ firefly: [string, string];
43
+ /** `ChimneySmoke` frames. */
44
+ puffs: string[];
45
+ }
46
+ /** Frames a puff of smoke grows through. */
47
+ export declare const PUFF_FRAMES = 6;
48
+ /**
49
+ * One puff of smoke at `frame` (0..PUFF_FRAMES-1): a ragged blob, light on its up-left and dark on its down-right, that
50
+ * grows as it climbs. Its corner pixels come and go by a fixed hash, so it is no clean ellipse, and the last two
51
+ * frames lose every other pixel on a checkerboard, the way every effect dithers out. Pure.
52
+ */
53
+ export declare function puffPixels(frame: number, colors?: readonly [string, string, string]): {
54
+ w: number;
55
+ h: number;
56
+ px: LifePixel[];
57
+ };
58
+ /**
59
+ * Paints the life's art under `prefix` (default `'life_'`) and returns its keys. A key already registered is kept, so
60
+ * calling it again (every map) costs nothing — and painting other colours needs another prefix.
61
+ */
62
+ export declare function paintLifeArt(textures: TextureRegistry, colors?: Partial<LifeColors>, prefix?: string): LifeArt;
63
+ //# sourceMappingURL=lifeArt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifeArt.d.ts","sourceRoot":"","sources":["../../../src/pixel/lifeArt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAS/D,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEvE,8FAA8F;AAC9F,MAAM,WAAW,UAAU;IACzB,mCAAmC;IACnC,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IAC/C,qEAAqE;IACrE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iCAAiC;IACjC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,iBAAiB;IACjB,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,2CAA2C;IAC3C,GAAG,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IAC5C,gDAAgD;IAChD,WAAW,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,UAAU,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,oDAAoD;IACpD,OAAO,EAAE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7C,yDAAyD;IACzD,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,WAAW,EAAE,UAuBzB,CAAC;AAEF,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,mCAAmC;IACnC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC;IAChB,kDAAkD;IAClD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAChC,iCAAiC;IACjC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,4CAA4C;AAC5C,eAAO,MAAM,WAAW,IAAI,CAAC;AAQ7B;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAqB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,SAAS,EAAE,CAAA;CAAE,CAqBlJ;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,EAAE,MAAM,SAAU,GAAG,OAAO,CA2CnH"}
@@ -0,0 +1,26 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface ConfirmButtonProps {
3
+ /** What this button arms, among the ones sharing `armed` (a name, "disband"…). */
4
+ armKey?: string;
5
+ /**
6
+ * Which button of a group is armed now, kept by the parent so arming one disarms the others. Left out, the button
7
+ * keeps its own state.
8
+ */
9
+ armed?: string | null;
10
+ setArmed?: (key: string | null) => void;
11
+ onConfirm: () => void;
12
+ label: ReactNode;
13
+ /** Shown once armed: what the second click will do (default `UiLabels.confirmAgain`). */
14
+ armedLabel?: ReactNode;
15
+ title?: string;
16
+ /** Default `'small'`. */
17
+ className?: string;
18
+ disabled?: boolean;
19
+ }
20
+ /**
21
+ * A button asked twice: the first click arms it (it takes the `armed` look and says so), the second does the thing.
22
+ * For what cannot be undone from a list row — removing a friend, disbanding a group — where a dialog would be heavier
23
+ * than the choice.
24
+ */
25
+ export declare function ConfirmButton({ armKey, armed, setArmed, onConfirm, label, armedLabel, title, className, disabled }: ConfirmButtonProps): import("react").JSX.Element;
26
+ //# sourceMappingURL=ConfirmButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmButton.d.ts","sourceRoot":"","sources":["../../../src/react/ConfirmButton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjD,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACxC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,yFAAyF;IACzF,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAmB,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAuB1J"}
@@ -18,7 +18,7 @@
18
18
  * A `-width` may have one to four lengths, like `border-width`. The pixel rules hold here: no `translate(-50%)` centring and no `zoom` (the components place in whole pixels), no
19
19
  * blurred shadow, no gradient. A frame's middle shows through only when its slice says `fill`.
20
20
  */
21
- export declare const baseCss = "\n:root {\n --e1681-font: inherit;\n --e1681-font-size: 16px;\n --e1681-text: #ece6d6;\n --e1681-muted: #9c968a;\n --e1681-accent: #e8c060;\n --e1681-bg: #1d242e;\n --e1681-well: #131a24;\n --e1681-control-bg: #2a323e;\n --e1681-border: #6a5634;\n --e1681-border-width: 2px;\n --e1681-backdrop: rgba(0, 0, 0, 0.5);\n --e1681-frame: none;\n --e1681-frame-slice: 0;\n --e1681-frame-width: var(--e1681-border-width);\n --e1681-tip-frame: var(--e1681-frame);\n --e1681-tip-frame-slice: var(--e1681-frame-slice);\n --e1681-tip-frame-width: var(--e1681-frame-width);\n --e1681-control-frame: none;\n --e1681-control-frame-slice: 0;\n --e1681-control-frame-width: var(--e1681-border-width);\n --e1681-tab-frame: var(--e1681-control-frame);\n --e1681-tab-active-frame: var(--e1681-tab-frame);\n --e1681-tab-frame-slice: var(--e1681-control-frame-slice);\n --e1681-tab-frame-width: var(--e1681-control-frame-width);\n --e1681-well-frame: none;\n --e1681-well-frame-slice: 0;\n --e1681-well-frame-width: var(--e1681-border-width);\n}\n\n.e1681-frame {\n color: var(--e1681-text);\n font-family: var(--e1681-font);\n font-size: var(--e1681-font-size);\n background: var(--e1681-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-frame-width);\n border-image: var(--e1681-frame) var(--e1681-frame-slice) / var(--e1681-frame-width) stretch;\n box-sizing: border-box;\n}\n.e1681-tip-frame {\n color: var(--e1681-text);\n font-family: var(--e1681-font);\n font-size: var(--e1681-font-size);\n background: var(--e1681-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-tip-frame-width);\n border-image: var(--e1681-tip-frame) var(--e1681-tip-frame-slice) / var(--e1681-tip-frame-width) stretch;\n box-sizing: border-box;\n}\n\n/* windows: placed by useFitToViewport in whole pixels; header kept, body scrolls */\n.e1681-panel {\n position: fixed;\n z-index: 10;\n display: flex;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n pointer-events: auto;\n}\n.e1681-panel-header { display: flex; align-items: center; gap: 8px; flex: none; padding: 2px 4px 6px; }\n.e1681-panel-title { flex: 1; min-width: 0; margin: 0; font-size: 1.25em; font-weight: normal; color: var(--e1681-accent); }\n.e1681-panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 0 4px 4px; }\n.e1681-panel-footer { flex: none; display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; padding: 6px 4px 0; }\n.e1681-close {\n flex: none; padding: 2px; border: 0; background: none; color: var(--e1681-text); cursor: pointer; line-height: 0;\n}\n.e1681-close:hover { color: var(--e1681-accent); }\n/* a touch screen's sheet: the whole screen inside the safe area */\n.e1681-panel.e1681-sheet {\n inset: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);\n width: auto;\n height: auto;\n}\n.e1681-panel.e1681-sheet .e1681-panel-body { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }\n\n/* controls */\n.e1681-button, .e1681-input, .e1681-select {\n color: var(--e1681-text);\n font: inherit;\n background: var(--e1681-control-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-control-frame-width);\n border-image: var(--e1681-control-frame) var(--e1681-control-frame-slice) / var(--e1681-control-frame-width) stretch;\n box-shadow: none;\n}\n.e1681-button { padding: 2px 10px; cursor: pointer; min-height: 28px; }\n.e1681-button.small { padding: 0 6px; min-height: 22px; }\n.e1681-button.ghost { background-color: transparent; }\n.e1681-button:hover:not(:disabled) { color: var(--e1681-accent); }\n/* pressed: the same face a pixel lower, never a transform */\n.e1681-button:active:not(:disabled) { padding-top: 3px; padding-bottom: 1px; }\n.e1681-button:disabled { opacity: 0.55; cursor: default; }\n.e1681-input { padding: 2px 6px; min-width: 0; }\n.e1681-glyph { display: inline-block; flex: none; vertical-align: -1px; }\n\n/* tabs: a row that scrolls sideways, or wraps with .wrap */\n.e1681-tabs { display: flex; gap: 2px; align-items: flex-end; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; margin-bottom: 8px; }\n.e1681-tabs::-webkit-scrollbar { display: none; }\n.e1681-tabs.wrap { flex-wrap: wrap; overflow-x: visible; row-gap: 4px; }\n.e1681-tab {\n flex: 0 0 auto;\n padding: 2px 10px;\n color: var(--e1681-muted);\n font: inherit;\n cursor: pointer;\n white-space: nowrap;\n background: var(--e1681-control-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-tab-frame-width);\n border-image: var(--e1681-tab-frame) var(--e1681-tab-frame-slice) / var(--e1681-tab-frame-width) stretch;\n}\n.e1681-tab:hover:not(.active):not(:disabled) { color: var(--e1681-text); }\n.e1681-tab.active { color: var(--e1681-accent); padding-bottom: 6px; border-image-source: var(--e1681-tab-active-frame); }\n.e1681-tab:disabled { opacity: 0.55; cursor: default; }\n.e1681-tab:focus-visible { outline: 2px solid var(--e1681-accent); outline-offset: -4px; }\n.e1681-tabs.small { margin-bottom: 4px; }\n.e1681-tabs.small .e1681-tab { padding: 0 6px; }\n.e1681-tabs.small .e1681-tab.active { padding-bottom: 4px; }\n\n/* list beside detail */\n.e1681-split {\n display: grid;\n grid-template-columns: var(--e1681-split-list, minmax(0, 1fr)) minmax(0, 1fr);\n gap: 12px;\n height: min(58vh, 620px);\n}\n.e1681-split.fit { height: auto; max-height: min(58vh, 620px); }\n.e1681-split-list, .e1681-split-detail { min-height: 0; overflow-y: auto; overflow-x: hidden; }\n.e1681-split-list { padding-right: 4px; }\n.e1681-split-detail {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 8px 10px;\n background: var(--e1681-well) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-well-frame-width);\n border-image: var(--e1681-well-frame) var(--e1681-well-frame-slice) / var(--e1681-well-frame-width) stretch;\n}\n.e1681-split-empty { flex: 1; display: flex; align-items: center; justify-content: center; text-align: center; color: var(--e1681-muted); }\n.e1681-split.stack { grid-template-columns: minmax(0, 1fr); }\n.e1681-split.stack.show-list .e1681-split-detail, .e1681-split.stack.show-detail .e1681-split-list { display: none; }\n.e1681-split-back { align-self: flex-start; }\n.e1681-row { display: flex; align-items: center; gap: 8px; padding: 4px 6px; margin-bottom: 4px; border: var(--e1681-border-width) solid transparent; }\n.e1681-pickable { cursor: pointer; }\n.e1681-pickable:hover:not(.picked):not(.disabled) { border-color: var(--e1681-border); }\n.e1681-row.picked { border-color: var(--e1681-accent); color: var(--e1681-accent); }\n.e1681-row.disabled { opacity: 0.55; cursor: default; }\n\n/* the select: as wide as its longest label */\n.e1681-select { display: inline-flex; align-items: center; gap: 6px; flex: none; padding: 1px 4px; text-align: left; cursor: pointer; }\n.e1681-select:hover:not(:disabled), .e1681-select.open { color: var(--e1681-accent); }\n.e1681-select:disabled { opacity: 0.6; cursor: default; }\n.e1681-select.grow { flex: 1 1 auto; min-width: 0; }\n.e1681-select.grow .e1681-select-labels { flex: 1 1 auto; min-width: 0; overflow: hidden; }\n.e1681-select.grow .e1681-select-labels > span { overflow: hidden; text-overflow: ellipsis; }\n.e1681-select-labels { display: grid; white-space: nowrap; }\n.e1681-select-labels > span { grid-area: 1 / 1; visibility: hidden; }\n.e1681-select-labels > span.shown { visibility: visible; }\n.e1681-select-list {\n position: fixed;\n z-index: 10000;\n box-sizing: border-box;\n width: max-content;\n padding: 2px;\n overflow-y: auto;\n pointer-events: auto;\n}\n.e1681-select-option { padding: 2px 6px; white-space: nowrap; cursor: pointer; }\n.e1681-select-list.measuring .e1681-select-option { width: max-content; }\n.e1681-select-option.hot { background: var(--e1681-control-bg); }\n.e1681-select-option.picked { color: var(--e1681-accent); }\n\n/* tooltips */\n.e1681-tooltip { position: fixed; z-index: 10001; max-width: 360px; padding: 4px 8px; overflow: hidden; pointer-events: none; }\n.e1681-title-tip { white-space: pre-line; }\n\n/* slider: a square knob, flat fills */\n.e1681-slider-row { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n.e1681-slider { flex: 1; min-width: 0; padding: 6px 7px; cursor: pointer; touch-action: none; user-select: none; pointer-events: auto; }\n.e1681-slider:focus { outline: none; }\n.e1681-slider:focus-visible { outline: 2px solid var(--e1681-accent); outline-offset: 2px; }\n.e1681-slider[aria-disabled='true'] { opacity: 0.55; cursor: default; }\n.e1681-slider-track {\n position: relative;\n height: 6px;\n background: var(--e1681-well) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-well-frame-width);\n border-image: var(--e1681-well-frame) var(--e1681-well-frame-slice) / var(--e1681-well-frame-width) stretch;\n}\n.e1681-slider-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--e1681-accent); }\n/* the knob is offset by half its own whole-pixel width with a margin, so it stays on the pixel grid */\n.e1681-slider-knob { position: absolute; top: -6px; width: 10px; height: 14px; margin-left: -5px; background: var(--e1681-text); border: 2px solid var(--e1681-well); box-sizing: border-box; }\n.e1681-slider-value { min-width: 40px; text-align: right; font-variant-numeric: tabular-nums; }\n\n/* dialogs */\n.e1681-backdrop { position: fixed; inset: 0; z-index: 9000; background: var(--e1681-backdrop); pointer-events: auto; }\n.e1681-dialog { position: fixed; display: flex; flex-direction: column; overflow: hidden; padding: 8px 10px; }\n.e1681-dialog-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }\n.e1681-dialog-actions { flex: none; display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; padding-top: 10px; }\n.e1681-confirm-text { white-space: pre-line; }\n.e1681-confirm-qty { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.e1681-confirm-qty-input { width: 56px; text-align: right; }\n.e1681-choice-list { margin-top: 8px; }\n.e1681-choice-icon { flex: none; line-height: 0; }\n.e1681-choice-label { flex: 1; min-width: 0; }\n.e1681-choice-note { flex: none; margin-left: auto; color: var(--e1681-muted); }\n\n/* sprites at whole multiples */\n.e1681-pixel-image { display: inline-flex; align-items: center; justify-content: center; flex: none; overflow: hidden; }\n.e1681-pixel-image > img { image-rendering: pixelated; flex: none; }\n";
21
+ export declare const baseCss = "\n:root {\n --e1681-font: inherit;\n --e1681-font-size: 16px;\n --e1681-text: #ece6d6;\n --e1681-muted: #9c968a;\n --e1681-accent: #e8c060;\n --e1681-bg: #1d242e;\n --e1681-well: #131a24;\n --e1681-control-bg: #2a323e;\n --e1681-border: #6a5634;\n --e1681-border-width: 2px;\n --e1681-backdrop: rgba(0, 0, 0, 0.5);\n --e1681-frame: none;\n --e1681-frame-slice: 0;\n --e1681-frame-width: var(--e1681-border-width);\n --e1681-tip-frame: var(--e1681-frame);\n --e1681-tip-frame-slice: var(--e1681-frame-slice);\n --e1681-tip-frame-width: var(--e1681-frame-width);\n --e1681-control-frame: none;\n --e1681-control-frame-slice: 0;\n --e1681-control-frame-width: var(--e1681-border-width);\n --e1681-tab-frame: var(--e1681-control-frame);\n --e1681-tab-active-frame: var(--e1681-tab-frame);\n --e1681-tab-frame-slice: var(--e1681-control-frame-slice);\n --e1681-tab-frame-width: var(--e1681-control-frame-width);\n --e1681-well-frame: none;\n --e1681-well-frame-slice: 0;\n --e1681-well-frame-width: var(--e1681-border-width);\n}\n\n.e1681-frame {\n color: var(--e1681-text);\n font-family: var(--e1681-font);\n font-size: var(--e1681-font-size);\n background: var(--e1681-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-frame-width);\n border-image: var(--e1681-frame) var(--e1681-frame-slice) / var(--e1681-frame-width) stretch;\n box-sizing: border-box;\n}\n.e1681-tip-frame {\n color: var(--e1681-text);\n font-family: var(--e1681-font);\n font-size: var(--e1681-font-size);\n background: var(--e1681-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-tip-frame-width);\n border-image: var(--e1681-tip-frame) var(--e1681-tip-frame-slice) / var(--e1681-tip-frame-width) stretch;\n box-sizing: border-box;\n}\n\n/* windows: placed by useFitToViewport in whole pixels; header kept, body scrolls */\n.e1681-panel {\n position: fixed;\n z-index: 10;\n display: flex;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n pointer-events: auto;\n}\n.e1681-panel-header { display: flex; align-items: center; gap: 8px; flex: none; padding: 2px 4px 6px; }\n.e1681-panel-title { flex: 1; min-width: 0; margin: 0; font-size: 1.25em; font-weight: normal; color: var(--e1681-accent); }\n.e1681-panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 0 4px 4px; }\n.e1681-panel-footer { flex: none; display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; padding: 6px 4px 0; }\n.e1681-close {\n flex: none; padding: 2px; border: 0; background: none; color: var(--e1681-text); cursor: pointer; line-height: 0;\n}\n.e1681-close:hover { color: var(--e1681-accent); }\n/* a touch screen's sheet: the whole screen inside the safe area */\n.e1681-panel.e1681-sheet {\n inset: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);\n width: auto;\n height: auto;\n}\n.e1681-panel.e1681-sheet .e1681-panel-body { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }\n\n/* controls */\n.e1681-button, .e1681-input, .e1681-select {\n color: var(--e1681-text);\n font: inherit;\n background: var(--e1681-control-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-control-frame-width);\n border-image: var(--e1681-control-frame) var(--e1681-control-frame-slice) / var(--e1681-control-frame-width) stretch;\n box-shadow: none;\n}\n.e1681-button { padding: 2px 10px; cursor: pointer; min-height: 28px; }\n.e1681-button.small { padding: 0 6px; min-height: 22px; }\n.e1681-button.ghost { background-color: transparent; }\n.e1681-button.e1681-armed { color: var(--e1681-accent); }\n.e1681-button:hover:not(:disabled) { color: var(--e1681-accent); }\n/* pressed: the same face a pixel lower, never a transform */\n.e1681-button:active:not(:disabled) { padding-top: 3px; padding-bottom: 1px; }\n.e1681-button:disabled { opacity: 0.55; cursor: default; }\n.e1681-input { padding: 2px 6px; min-width: 0; }\n.e1681-glyph { display: inline-block; flex: none; vertical-align: -1px; }\n\n/* tabs: a row that scrolls sideways, or wraps with .wrap */\n.e1681-tabs { display: flex; gap: 2px; align-items: flex-end; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; margin-bottom: 8px; }\n.e1681-tabs::-webkit-scrollbar { display: none; }\n.e1681-tabs.wrap { flex-wrap: wrap; overflow-x: visible; row-gap: 4px; }\n.e1681-tab {\n flex: 0 0 auto;\n padding: 2px 10px;\n color: var(--e1681-muted);\n font: inherit;\n cursor: pointer;\n white-space: nowrap;\n background: var(--e1681-control-bg) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-tab-frame-width);\n border-image: var(--e1681-tab-frame) var(--e1681-tab-frame-slice) / var(--e1681-tab-frame-width) stretch;\n}\n.e1681-tab:hover:not(.active):not(:disabled) { color: var(--e1681-text); }\n.e1681-tab.active { color: var(--e1681-accent); padding-bottom: 6px; border-image-source: var(--e1681-tab-active-frame); }\n.e1681-tab:disabled { opacity: 0.55; cursor: default; }\n.e1681-tab:focus-visible { outline: 2px solid var(--e1681-accent); outline-offset: -4px; }\n.e1681-tabs.small { margin-bottom: 4px; }\n.e1681-tabs.small .e1681-tab { padding: 0 6px; }\n.e1681-tabs.small .e1681-tab.active { padding-bottom: 4px; }\n\n/* list beside detail */\n.e1681-split {\n display: grid;\n grid-template-columns: var(--e1681-split-list, minmax(0, 1fr)) minmax(0, 1fr);\n gap: 12px;\n height: min(58vh, 620px);\n}\n.e1681-split.fit { height: auto; max-height: min(58vh, 620px); }\n.e1681-split-list, .e1681-split-detail { min-height: 0; overflow-y: auto; overflow-x: hidden; }\n.e1681-split-list { padding-right: 4px; }\n.e1681-split-detail {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 8px 10px;\n background: var(--e1681-well) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-well-frame-width);\n border-image: var(--e1681-well-frame) var(--e1681-well-frame-slice) / var(--e1681-well-frame-width) stretch;\n}\n.e1681-split-empty { flex: 1; display: flex; align-items: center; justify-content: center; text-align: center; color: var(--e1681-muted); }\n.e1681-split.stack { grid-template-columns: minmax(0, 1fr); }\n.e1681-split.stack.show-list .e1681-split-detail, .e1681-split.stack.show-detail .e1681-split-list { display: none; }\n.e1681-split-back { align-self: flex-start; }\n.e1681-row { display: flex; align-items: center; gap: 8px; padding: 4px 6px; margin-bottom: 4px; border: var(--e1681-border-width) solid transparent; }\n.e1681-pickable { cursor: pointer; }\n.e1681-pickable:hover:not(.picked):not(.disabled) { border-color: var(--e1681-border); }\n.e1681-row.picked { border-color: var(--e1681-accent); color: var(--e1681-accent); }\n.e1681-row.disabled { opacity: 0.55; cursor: default; }\n\n/* the select: as wide as its longest label */\n.e1681-select { display: inline-flex; align-items: center; gap: 6px; flex: none; padding: 1px 4px; text-align: left; cursor: pointer; }\n.e1681-select:hover:not(:disabled), .e1681-select.open { color: var(--e1681-accent); }\n.e1681-select:disabled { opacity: 0.6; cursor: default; }\n.e1681-select.grow { flex: 1 1 auto; min-width: 0; }\n.e1681-select.grow .e1681-select-labels { flex: 1 1 auto; min-width: 0; overflow: hidden; }\n.e1681-select.grow .e1681-select-labels > span { overflow: hidden; text-overflow: ellipsis; }\n.e1681-select-labels { display: grid; white-space: nowrap; }\n.e1681-select-labels > span { grid-area: 1 / 1; visibility: hidden; }\n.e1681-select-labels > span.shown { visibility: visible; }\n.e1681-select-list {\n position: fixed;\n z-index: 10000;\n box-sizing: border-box;\n width: max-content;\n padding: 2px;\n overflow-y: auto;\n pointer-events: auto;\n}\n.e1681-select-option { padding: 2px 6px; white-space: nowrap; cursor: pointer; }\n.e1681-select-list.measuring .e1681-select-option { width: max-content; }\n.e1681-select-option.hot { background: var(--e1681-control-bg); }\n.e1681-select-option.picked { color: var(--e1681-accent); }\n\n/* tooltips */\n.e1681-tooltip { position: fixed; z-index: 10001; max-width: 360px; padding: 4px 8px; overflow: hidden; pointer-events: none; }\n.e1681-title-tip { white-space: pre-line; }\n\n/* slider: a square knob, flat fills */\n.e1681-slider-row { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n.e1681-slider { flex: 1; min-width: 0; padding: 6px 7px; cursor: pointer; touch-action: none; user-select: none; pointer-events: auto; }\n.e1681-slider:focus { outline: none; }\n.e1681-slider:focus-visible { outline: 2px solid var(--e1681-accent); outline-offset: 2px; }\n.e1681-slider[aria-disabled='true'] { opacity: 0.55; cursor: default; }\n.e1681-slider-track {\n position: relative;\n height: 6px;\n background: var(--e1681-well) padding-box;\n border-style: solid; border-color: var(--e1681-border); border-width: var(--e1681-well-frame-width);\n border-image: var(--e1681-well-frame) var(--e1681-well-frame-slice) / var(--e1681-well-frame-width) stretch;\n}\n.e1681-slider-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--e1681-accent); }\n/* the knob is offset by half its own whole-pixel width with a margin, so it stays on the pixel grid */\n.e1681-slider-knob { position: absolute; top: -6px; width: 10px; height: 14px; margin-left: -5px; background: var(--e1681-text); border: 2px solid var(--e1681-well); box-sizing: border-box; }\n.e1681-slider-value { min-width: 40px; text-align: right; font-variant-numeric: tabular-nums; }\n\n/* dialogs */\n.e1681-backdrop { position: fixed; inset: 0; z-index: 9000; background: var(--e1681-backdrop); pointer-events: auto; }\n.e1681-dialog { position: fixed; display: flex; flex-direction: column; overflow: hidden; padding: 8px 10px; }\n.e1681-dialog-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }\n.e1681-dialog-actions { flex: none; display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; padding-top: 10px; }\n.e1681-confirm-text { white-space: pre-line; }\n.e1681-confirm-qty { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.e1681-confirm-qty-input { width: 56px; text-align: right; }\n.e1681-choice-list { margin-top: 8px; }\n.e1681-choice-icon { flex: none; line-height: 0; }\n.e1681-choice-label { flex: 1; min-width: 0; }\n.e1681-choice-note { flex: none; margin-left: auto; color: var(--e1681-muted); }\n\n/* sprites at whole multiples */\n.e1681-pixel-image { display: inline-flex; align-items: center; justify-content: center; flex: none; overflow: hidden; }\n.e1681-pixel-image > img { image-rendering: pixelated; flex: none; }\n";
22
22
  /**
23
23
  * Puts `baseCss` into the page once, first in `<head>` so the game's own rules (and its custom properties) win
24
24
  * without needing more specific selectors. Returns the `<style>` element; nothing on a server.
@@ -1 +1 @@
1
- {"version":3,"file":"baseCss.d.ts","sourceRoot":"","sources":["../../../src/react/baseCss.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,OAAO,giVAiNnB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,QAAQ,GAAG,SAAkE,GAAG,gBAAgB,GAAG,IAAI,CASzI"}
1
+ {"version":3,"file":"baseCss.d.ts","sourceRoot":"","sources":["../../../src/react/baseCss.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,OAAO,2lVAkNnB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,QAAQ,GAAG,SAAkE,GAAG,gBAAgB,GAAG,IAAI,CASzI"}
@@ -11,6 +11,7 @@ export { classJoiner, type ClassJoiner } from './classNames.js';
11
11
  export { DEFAULT_LABELS, fillLabel, type UiLabels } from './labels.js';
12
12
  export { baseCss, injectBaseCss } from './baseCss.js';
13
13
  export { useStore } from './useStore.js';
14
+ export { useJsonSelector, useStoreJson, type SelectingHook } from './useJsonSelector.js';
14
15
  export { useViewport } from './useViewport.js';
15
16
  export { useFitToViewport, SCROLL_CLASS, type FitTarget } from './useFitToViewport.js';
16
17
  export { useFillSheet } from './useFillSheet.js';
@@ -24,6 +25,7 @@ export { Tooltip, type TooltipProps } from './Tooltip.js';
24
25
  export { TitleTips, type TitleTipsProps } from './TitleTips.js';
25
26
  export { Modal, type ModalProps } from './Modal.js';
26
27
  export { ConfirmDialog } from './ConfirmDialog.js';
28
+ export { ConfirmButton, type ConfirmButtonProps } from './ConfirmButton.js';
27
29
  export { askConfirm, askQuantity, answerConfirm, cancelConfirm, confirmStore, parseQuantity, type AskOptions, type ConfirmQuestion } from './confirmStore.js';
28
30
  export { ChoiceDialog } from './ChoiceDialog.js';
29
31
  export { askChoice, answerChoice, cancelChoice, choiceStore, firstChoice, type ChoiceOption, type ChoiceQuestion } from './choiceStore.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAClH,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EACL,WAAW,EACX,eAAe,EACf,SAAS,EACT,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC3J,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACxI,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAClH,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EACL,WAAW,EACX,eAAe,EACf,SAAS,EACT,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC3J,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACxI,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC"}
@@ -17,6 +17,8 @@ export interface UiLabels {
17
17
  quantity: string;
18
18
  /** The choice dialog's confirm button. */
19
19
  choose: string;
20
+ /** What an armed `ConfirmButton` says when the game gives it no words of its own. */
21
+ confirmAgain?: string;
20
22
  }
21
23
  export declare const DEFAULT_LABELS: UiLabels;
22
24
  /** `{0}`, `{1}`… replaced by the arguments, in order. */
@@ -1 +1 @@
1
- {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../src/react/labels.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,cAAc,EAAE,QAS5B,CAAC;AAEF,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE3E"}
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../src/react/labels.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,cAAc,EAAE,QAU5B,CAAC;AAEF,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE3E"}
@@ -0,0 +1,13 @@
1
+ import type { Store } from '../ui/dom/createStore.js';
2
+ /** A store hook that selects (zustand's `useStore`, or `(sel) => useStore(store, sel)`). */
3
+ export type SelectingHook<S> = (select: (state: S) => string) => string;
4
+ /**
5
+ * Selects a small, plain piece of a store by its content: the selector's result is compared as JSON, so a store that
6
+ * hands out a fresh array or object for unchanged content — a game's player state pushed several times a second in a
7
+ * fight — re-renders nothing that reads it, and the value returned keeps its reference until the content changes.
8
+ * Only for small data (a few ids, a list of buffs): the JSON is written once per store change.
9
+ */
10
+ export declare function useJsonSelector<S, T>(useHook: SelectingHook<S>, select: (state: S) => T): T;
11
+ /** `useJsonSelector` over an engine `Store` (`createStore`). */
12
+ export declare function useStoreJson<S extends object, T>(store: Store<S>, select: (state: S) => T): T;
13
+ //# sourceMappingURL=useJsonSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useJsonSelector.d.ts","sourceRoot":"","sources":["../../../src/react/useJsonSelector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGnD,4FAA4F;AAC5F,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,MAAM,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAG3F;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAE7F"}
@@ -16,6 +16,12 @@ export interface TilemapViewOptions {
16
16
  baseDepth?: number;
17
17
  /** Where the layers go (default the stage's world layer); a scene passes its `root` so they leave with it. */
18
18
  parent?: Container;
19
+ /**
20
+ * World position of the map's top-left corner (default 0, 0): an LDtk level's `worldX`/`worldY`, or any map laid
21
+ * beside another. Culling in `update` counts it.
22
+ */
23
+ x?: number;
24
+ y?: number;
19
25
  }
20
26
  /**
21
27
  * Draws a Tiled map's tile layers. Each layer is cut into chunks painted once into textures; a frame only toggles
@@ -30,9 +36,20 @@ export declare class TilemapView {
30
36
  readonly layers: Map<string, Container<import("pixi.js").ContainerChild>>;
31
37
  private readonly chunks;
32
38
  private readonly id;
39
+ private readonly chunkTiles;
40
+ private readonly textureFor;
41
+ private readonly drawn;
42
+ private readonly originX;
43
+ private readonly originY;
33
44
  constructor(stage: Stage, map: TileMap, options?: TilemapViewOptions);
34
45
  /** Shows only the chunks in the camera's view (plus a margin in world px). Call once a frame. */
35
46
  update(margin?: number): void;
47
+ /**
48
+ * Repaints the chunks holding these cells (row-major indices) of a drawn layer, after its `data` changed: a door
49
+ * opening, a wall dug out, a cell autotiled again (`updateAutotile` returns exactly the indices to pass). Costs one
50
+ * chunk's painting per chunk touched, so keep it out of every frame.
51
+ */
52
+ refreshTiles(layerName: string, cells: Iterable<number>): void;
36
53
  /** World size of the map in px. */
37
54
  get widthPx(): number;
38
55
  get heightPx(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"TilemapView.d.ts","sourceRoot":"","sources":["../../../src/tilemap/TilemapView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAA4D,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAE/G,MAAM,WAAW,kBAAkB;IACjC,wHAAwH;IACxH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IAC1C,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAID;;;;;GAKG;AACH,qBAAa,WAAW;IAOpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,QAAQ,CAAC,GAAG,EAAE,OAAO;IAPvB,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,2DAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqF;IAC5G,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAc;gBAGd,KAAK,EAAE,KAAK,EACpB,GAAG,EAAE,OAAO,EACrB,OAAO,GAAE,kBAAuB;IA0BlC,iGAAiG;IACjG,MAAM,CAAC,MAAM,SAAK,GAAG,IAAI;IAOzB,mCAAmC;IACnC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,UAAU;CA0CnB"}
1
+ {"version":3,"file":"TilemapView.d.ts","sourceRoot":"","sources":["../../../src/tilemap/TilemapView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAA4D,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAE/G,MAAM,WAAW,kBAAkB;IACjC,wHAAwH;IACxH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IAC1C,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAID;;;;;GAKG;AACH,qBAAa,WAAW;IAYpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,QAAQ,CAAC,GAAG,EAAE,OAAO;IAZvB,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,2DAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqF;IAC5G,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAGd,KAAK,EAAE,KAAK,EACpB,GAAG,EAAE,OAAO,EACrB,OAAO,GAAE,kBAAuB;IA+BlC,iGAAiG;IACjG,MAAM,CAAC,MAAM,SAAK,GAAG,IAAI;IAOzB;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI;IAuB9D,mCAAmC;IACnC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,UAAU;CA2CnB"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Autotiling: picking each cell's tile from which of its neighbours share its terrain, so a painter only says "wall
3
+ * here, water there" and the borders draw themselves. Two bitmasks are offered:
4
+ *
5
+ * - **edges** (4-bit, 16 tiles): the four sides only. Enough for paths, fences and pipes, and for terrain whose
6
+ * inner corners need no tile of their own.
7
+ * - **blob** (8-bit reduced to the 47-tile set): the sides and the corners, a corner counting only when both sides
8
+ * beside it match. Without that reduction 256 masks would need 256 tiles; with it a full terrain (outer edges,
9
+ * inner corners, thin bridges) needs 47.
10
+ *
11
+ * Pure: no Pixi, no DOM, so a server or a map tool can run the same rules.
12
+ */
13
+ /** The edge bits, clockwise from the top. */
14
+ export declare const EDGE_N = 1;
15
+ export declare const EDGE_E = 2;
16
+ export declare const EDGE_S = 4;
17
+ export declare const EDGE_W = 8;
18
+ /** The blob bits, clockwise from the top. */
19
+ export declare const BLOB_N = 1;
20
+ export declare const BLOB_NE = 2;
21
+ export declare const BLOB_E = 4;
22
+ export declare const BLOB_SE = 8;
23
+ export declare const BLOB_S = 16;
24
+ export declare const BLOB_SW = 32;
25
+ export declare const BLOB_W = 64;
26
+ export declare const BLOB_NW = 128;
27
+ /** A grid of terrain ids, row-major. Any id is fine; the rules say what each one is. */
28
+ export interface TerrainGrid {
29
+ width: number;
30
+ height: number;
31
+ cells: ArrayLike<number> & {
32
+ [i: number]: number;
33
+ };
34
+ }
35
+ export type AutotileMode = 'edges' | 'blob';
36
+ export interface MaskOptions {
37
+ /**
38
+ * Whether a neighbour counts as "the same" for `terrain` (default: the same id). A rule's `connectsTo` builds one:
39
+ * grass that also joins flowers, a wall that also joins a door.
40
+ */
41
+ joins?: (terrain: number, neighbour: number) => boolean;
42
+ /**
43
+ * What lies outside the grid: `'same'` (default) joins the edge so a terrain running off the map shows no border;
44
+ * `'other'` closes it.
45
+ */
46
+ edge?: 'same' | 'other';
47
+ }
48
+ /** Drops each corner bit unless both sides beside it are set: what the 47-tile blob set is drawn for. */
49
+ export declare function reduceBlobMask(mask: number): number;
50
+ /** The 47 reduced blob masks in ascending order; a tileset laid out in that order is indexed by `blob47Index`. */
51
+ export declare const BLOB47_MASKS: readonly number[];
52
+ /** Where a blob mask (reduced or not) sits among the 47: 0…46. */
53
+ export declare function blob47Index(mask: number): number;
54
+ /** The 4-bit edge mask of cell (x, y): `EDGE_*` set for each side whose neighbour joins it. */
55
+ export declare function edgeMask(grid: TerrainGrid, x: number, y: number, options?: MaskOptions): number;
56
+ /** The reduced 8-bit blob mask of cell (x, y): one of `BLOB47_MASKS`. */
57
+ export declare function blobMask(grid: TerrainGrid, x: number, y: number, options?: MaskOptions): number;
58
+ /** How one terrain picks its tiles. */
59
+ export interface AutotileRule {
60
+ /** The terrain id this rule draws. */
61
+ terrain: number;
62
+ /** Which mask picks the tile (default `'blob'`). */
63
+ mode?: AutotileMode;
64
+ /**
65
+ * The tile for a mask: a table by mask (a list picks one of several by the cell's position, the same every time),
66
+ * or a function of the mask (and the cell, for anything fancier). Blob masks are the reduced ones; to lay a
67
+ * 47-tile set out in `BLOB47_MASKS` order use `(m) => first + blob47Index(m)`. Edge masks run 0…15, so a 16-tile
68
+ * strip in mask order is `(m) => first + m`.
69
+ */
70
+ tiles: Readonly<Record<number, number | readonly number[]>> | ((mask: number, x: number, y: number) => number);
71
+ /** The tile when the table has no entry for a mask (default: the entry for the full mask, else `empty`). */
72
+ fallback?: number;
73
+ /** Other terrain ids this one joins as if they were its own (a road meeting a bridge). */
74
+ connectsTo?: readonly number[];
75
+ }
76
+ /** Read once, the first time it is used (compiled lookups are kept per object): build a new set to change the rules. */
77
+ export interface AutotileRuleSet {
78
+ rules: readonly AutotileRule[];
79
+ /** The tile for a terrain no rule draws (default 0, an empty cell). */
80
+ empty?: number;
81
+ /** What lies outside the grid; see `MaskOptions.edge`. */
82
+ edge?: 'same' | 'other';
83
+ }
84
+ /** The tile cell (x, y) gets under `set`. */
85
+ export declare function autotileAt(grid: TerrainGrid, set: AutotileRuleSet, x: number, y: number): number;
86
+ /** Every cell's tile, row-major: the whole grid autotiled. */
87
+ export declare function autotile(grid: TerrainGrid, set: AutotileRuleSet, out?: Uint32Array<ArrayBuffer>): Uint32Array;
88
+ /**
89
+ * After cell (x, y) changed terrain, retiles it and its eight neighbours (the only cells whose masks can change)
90
+ * into `out`. Returns the indices whose tile actually changed, so a view repaints only those.
91
+ */
92
+ export declare function updateAutotile(grid: TerrainGrid, set: AutotileRuleSet, out: Uint32Array, x: number, y: number): number[];
93
+ /** Sets cell (x, y) to `terrain` and retiles around it; the changed indices, as `updateAutotile` returns them. */
94
+ export declare function paintTerrain(grid: TerrainGrid, set: AutotileRuleSet, out: Uint32Array, x: number, y: number, terrain: number): number[];
95
+ //# sourceMappingURL=autotile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autotile.d.ts","sourceRoot":"","sources":["../../../src/tilemap/autotile.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { type CollisionGrid, type CollisionGridOptions } from '../net/movement.js';
2
+ import type { LdtkIntGrid } from './ldtk.js';
2
3
  import { type TileMap } from './tiled.js';
3
4
  export interface TiledCollisionOptions extends Omit<CollisionGridOptions, 'ground'> {
4
5
  /**
@@ -13,4 +14,11 @@ export interface TiledCollisionOptions extends Omit<CollisionGridOptions, 'groun
13
14
  }
14
15
  /** The `CollisionGrid` of a Tiled map, for `stepMover`; cells are the map's tiles. */
15
16
  export declare function collisionFromTiled(map: TileMap, options?: TiledCollisionOptions): CollisionGrid;
17
+ /** Which IntGrid cells are solid: a list of values, or a test given the value and the name LDtk gives it. */
18
+ export type IntGridSolid = readonly number[] | ((value: number, name: string | undefined) => boolean);
19
+ /**
20
+ * The `CollisionGrid` of an LDtk IntGrid layer, for `stepMover`: the same grid `collisionFromTiled` builds, so movement,
21
+ * `navGridFromCollision` and `tileBodiesFromGrid` treat both editors' maps alike. `solid` says which values block.
22
+ */
23
+ export declare function collisionFromIntGrid(grid: LdtkIntGrid, solid: IntGridSolid, options?: Omit<CollisionGridOptions, 'ground'>): CollisionGrid;
16
24
  //# sourceMappingURL=collision.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../../../src/tilemap/collision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAEtD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC;IACjF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,qBAA0B,GAAG,aAAa,CAsBnG"}
1
+ {"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../../../src/tilemap/collision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAEtD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC;IACjF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,qBAA0B,GAAG,aAAa,CAsBnG;AAED,6GAA6G;AAC7G,MAAM,MAAM,YAAY,GAAG,SAAS,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC;AAEtG;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAM,GAAG,aAAa,CAW9I"}