@adiakys/feeling-lucky 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +227 -2
  3. package/dist/config/resolve.d.ts +4 -0
  4. package/dist/config/types.d.ts +62 -0
  5. package/dist/de-B56NsnDF.js +458 -0
  6. package/dist/developer/panel.d.ts +61 -0
  7. package/dist/developer/rig.d.ts +2 -0
  8. package/dist/developer/settings.d.ts +30 -0
  9. package/dist/engine/awards.d.ts +12 -0
  10. package/dist/engine/cards.d.ts +44 -0
  11. package/dist/engine/cashout.d.ts +32 -0
  12. package/dist/engine/dealer.d.ts +21 -0
  13. package/dist/engine/outcome.d.ts +13 -0
  14. package/dist/engine/pachinko.d.ts +58 -0
  15. package/dist/engine/random.d.ts +6 -0
  16. package/dist/engine/rig.d.ts +28 -0
  17. package/dist/engine/roulette.d.ts +53 -0
  18. package/dist/engine/scratch.d.ts +40 -0
  19. package/dist/engine/slot.d.ts +19 -0
  20. package/dist/engine/themes.d.ts +30 -0
  21. package/dist/engine/tiers.d.ts +64 -0
  22. package/dist/engine/wheel.d.ts +47 -0
  23. package/dist/es-9iWwCe8s.js +458 -0
  24. package/dist/feeling-lucky.iife.js +1494 -0
  25. package/dist/feeling-lucky.js +65 -0
  26. package/dist/fr-Y2BcCS3U.js +458 -0
  27. package/dist/games/blackjack/blackjack.d.ts +48 -0
  28. package/dist/games/cards/card.d.ts +5 -0
  29. package/dist/games/cards/dealer.d.ts +9 -0
  30. package/dist/games/cards/table.d.ts +12 -0
  31. package/dist/games/holdem/holdem.d.ts +29 -0
  32. package/dist/games/index.d.ts +9 -0
  33. package/dist/games/pachinko/pachinko.d.ts +53 -0
  34. package/dist/games/roulette/roulette.d.ts +63 -0
  35. package/dist/games/roulette/table.d.ts +19 -0
  36. package/dist/games/roulette/track.d.ts +18 -0
  37. package/dist/games/roulette/wheel.d.ts +9 -0
  38. package/dist/games/scratch/covers.d.ts +3 -0
  39. package/dist/games/scratch/double.d.ts +3 -0
  40. package/dist/games/scratch/forever.d.ts +3 -0
  41. package/dist/games/scratch/scratch.d.ts +39 -0
  42. package/dist/games/slot/breakaway.d.ts +32 -0
  43. package/dist/games/slot/machine.d.ts +18 -0
  44. package/dist/games/slot/slot.d.ts +32 -0
  45. package/dist/games/slot/takeoff.d.ts +28 -0
  46. package/dist/games/wheel/coin.d.ts +19 -0
  47. package/dist/games/wheel/face.d.ts +18 -0
  48. package/dist/games/wheel/hunt.d.ts +15 -0
  49. package/dist/games/wheel/wheel.d.ts +64 -0
  50. package/dist/i18n-it2FlmVZ.js +490 -0
  51. package/dist/index.d.ts +4 -0
  52. package/dist/it-CNSOLgaT.js +458 -0
  53. package/dist/locales/de/cards.d.ts +68 -0
  54. package/dist/locales/de/developer.d.ts +71 -0
  55. package/dist/locales/de/index.d.ts +2 -0
  56. package/dist/locales/de/pachinko.d.ts +26 -0
  57. package/dist/locales/de/room.d.ts +86 -0
  58. package/dist/locales/de/roulette.d.ts +77 -0
  59. package/dist/locales/de/scratch.d.ts +56 -0
  60. package/dist/locales/de/slot.d.ts +61 -0
  61. package/dist/locales/de/wheel.d.ts +45 -0
  62. package/dist/locales/en/cards.d.ts +68 -0
  63. package/dist/locales/en/developer.d.ts +71 -0
  64. package/dist/locales/en/index.d.ts +2 -0
  65. package/dist/locales/en/pachinko.d.ts +26 -0
  66. package/dist/locales/en/room.d.ts +86 -0
  67. package/dist/locales/en/roulette.d.ts +77 -0
  68. package/dist/locales/en/scratch.d.ts +56 -0
  69. package/dist/locales/en/slot.d.ts +61 -0
  70. package/dist/locales/en/wheel.d.ts +45 -0
  71. package/dist/locales/es/cards.d.ts +68 -0
  72. package/dist/locales/es/developer.d.ts +71 -0
  73. package/dist/locales/es/index.d.ts +2 -0
  74. package/dist/locales/es/pachinko.d.ts +26 -0
  75. package/dist/locales/es/room.d.ts +86 -0
  76. package/dist/locales/es/roulette.d.ts +77 -0
  77. package/dist/locales/es/scratch.d.ts +56 -0
  78. package/dist/locales/es/slot.d.ts +61 -0
  79. package/dist/locales/es/wheel.d.ts +45 -0
  80. package/dist/locales/fr/cards.d.ts +68 -0
  81. package/dist/locales/fr/developer.d.ts +71 -0
  82. package/dist/locales/fr/index.d.ts +2 -0
  83. package/dist/locales/fr/pachinko.d.ts +26 -0
  84. package/dist/locales/fr/room.d.ts +86 -0
  85. package/dist/locales/fr/roulette.d.ts +77 -0
  86. package/dist/locales/fr/scratch.d.ts +56 -0
  87. package/dist/locales/fr/slot.d.ts +61 -0
  88. package/dist/locales/fr/wheel.d.ts +45 -0
  89. package/dist/locales/index.d.ts +7 -0
  90. package/dist/locales/it/cards.d.ts +68 -0
  91. package/dist/locales/it/developer.d.ts +71 -0
  92. package/dist/locales/it/index.d.ts +2 -0
  93. package/dist/locales/it/pachinko.d.ts +26 -0
  94. package/dist/locales/it/room.d.ts +86 -0
  95. package/dist/locales/it/roulette.d.ts +77 -0
  96. package/dist/locales/it/scratch.d.ts +56 -0
  97. package/dist/locales/it/slot.d.ts +61 -0
  98. package/dist/locales/it/wheel.d.ts +45 -0
  99. package/dist/locales/merge.d.ts +2 -0
  100. package/dist/merge-iGSNfZkz.js +10 -0
  101. package/dist/mount-CBUkAcVV.js +7109 -0
  102. package/dist/panel-tWJMt9kl.js +545 -0
  103. package/dist/room/boost.d.ts +2 -0
  104. package/dist/room/certificate.d.ts +22 -0
  105. package/dist/room/chips.d.ts +21 -0
  106. package/dist/room/lobby.d.ts +45 -0
  107. package/dist/room/mount.d.ts +6 -0
  108. package/dist/room/room.d.ts +74 -0
  109. package/dist/room/stage.d.ts +18 -0
  110. package/dist/room/theme.d.ts +15 -0
  111. package/dist/runtime/context.d.ts +34 -0
  112. package/dist/runtime/element.d.ts +15 -0
  113. package/dist/runtime/fx.d.ts +43 -0
  114. package/dist/runtime/i18n.d.ts +8 -0
  115. package/dist/runtime/icons.d.ts +2 -0
  116. package/dist/runtime/motion.d.ts +2 -0
  117. package/dist/runtime/signal.d.ts +6 -0
  118. package/dist/runtime/sound.d.ts +11 -0
  119. package/dist/signal-CAveEGrG.js +19 -0
  120. package/dist/styles/index.d.ts +1 -0
  121. package/package.json +56 -4
package/README.md CHANGED
@@ -1,3 +1,228 @@
1
- # Temporary Holding Version
1
+ # feeling-lucky
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A casino room for any web app: players try their luck on classic casino games and win the prizes you configure.
4
+
5
+ **[Live demo](https://adiakys.github.io/feeling-lucky/)**: Ctrl+Shift+L in the room opens the developer menu.
6
+
7
+ - **Framework-free:** a single entry point that works with React, Angular, Vue or plain HTML.
8
+ - **No runtime dependencies:** built with [Lit](https://lit.dev) and [Lucide](https://lucide.dev) icons, both bundled.
9
+ - **Isolated:** the room lives in a shadow root mounted on `body`, so the host's CSS never reaches it and its CSS never leaks out.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @adiakys/feeling-lucky
15
+ ```
16
+
17
+ Without a bundler, the IIFE build exposes a global:
18
+
19
+ ```html
20
+ <script src="https://cdn.jsdelivr.net/npm/@adiakys/feeling-lucky/dist/feeling-lucky.iife.js"></script>
21
+ <script>
22
+ const lucky = FeelingLucky.createFeelingLucky({ prizes: [/* … */] });
23
+ </script>
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```ts
29
+ import { createFeelingLucky } from '@adiakys/feeling-lucky';
30
+
31
+ const lucky = createFeelingLucky({
32
+ prizes: [
33
+ {
34
+ id: 'pro',
35
+ name: 'Pro',
36
+ icon: '/icons/pro.svg',
37
+ variants: [
38
+ { tier: 'small', label: '7 days', short: '7D' },
39
+ { tier: 'big', label: '1 year', short: '1Y' },
40
+ ],
41
+ },
42
+ { id: 'basic', name: 'Basic', icon: '/icons/basic.svg' },
43
+ ],
44
+ onWin: (win) => console.log(win),
45
+ });
46
+
47
+ button.addEventListener('click', (event) => lucky.open({ from: event.currentTarget }));
48
+ ```
49
+
50
+ | Method | |
51
+ |---|---|
52
+ | `open({ from? })` | Opens the room, growing out of `from` (an element or `{ x, y }`) |
53
+ | `close()` | Closes the room |
54
+ | `update(config)` | Merges a partial config |
55
+ | `destroy()` | Removes the room and its listeners |
56
+
57
+ ## Config
58
+
59
+ Every field takes a value, a function, or a function returning a Promise.
60
+
61
+ | Field | Type | Default |
62
+ |---|---|---|
63
+ | `prizes` | `Prize[]`, 1 to n | required |
64
+ | `locale` | language code, e.g. `'it'` or `'pt-BR'` | follows the host page, see [Languages](#languages) |
65
+ | `messages` | `{ [locale]: Messages }`: new languages, or overrides of the built-in ones | none |
66
+ | `logo` | image URL of your brand mark, on the certificate, the wheel's hub and the scratch card | a clover |
67
+ | `dealers` | `Dealer[]`: the dealers who take the Salon Privé's shifts, see [Dealers](#dealers) | the library's own dealer |
68
+ | `player` | `{ name, avatar? }`, shown at the card tables | anonymous seat |
69
+ | `onWin` | `(win: Win) => void` | none |
70
+ | `onClaim` | `(win: Win) => Promise<void>`; shows **Claim** on the certificate | no claim button |
71
+ | `developer` | `true` or `{ passwordHash? }`: enables the developer menu (Ctrl+Shift+L), behind a password when the hash is given | disabled |
72
+
73
+ ```ts
74
+ interface Prize {
75
+ id: string;
76
+ name: string;
77
+ icon: string; // image URL
78
+ color?: string; // chip colour
79
+ variants?: Variant[] | ((tier: PrizeTier) => Variant | Promise<Variant>);
80
+ }
81
+
82
+ type PrizeTier = 'small' | 'big' | 'jackpot';
83
+
84
+ interface Variant {
85
+ tier: PrizeTier;
86
+ label: string; // certificate: "7 days"
87
+ short?: string; // game boards: "7D"
88
+ details?: { label: string; value: string }[];
89
+ }
90
+
91
+ interface Win {
92
+ prize: Prize;
93
+ variant: Variant | null; // null: the full prize
94
+ tier: PrizeTier;
95
+ game: GameId;
96
+ }
97
+ ```
98
+
99
+ ### Prizes and variants
100
+
101
+ - **Every play draws a tier first** (`none`, `small`, `big` or `jackpot`), then the game stages it.
102
+ - **Variants are optional.** A prize without variants is won in full, whatever the tier.
103
+ - **Board labels:** game boards (wheel segments, pachinko pockets, cash-out steps, scratch tickets) show the variants' `short` labels.
104
+ - **Tier symbol fallback:** a prize without variants, or with a variants function, shows the tier symbol on the board instead. Its variant is revealed on the certificate.
105
+ - **No signing or issuing.** `onClaim` hands the win to the host, which does whatever claiming means for it, e.g. closing the room and opening its own page, prefilled from the variant.
106
+ - **Your own fields:** variants can carry fields of yours. The win hands back the very object you gave, typed as yours:
107
+
108
+ ```ts
109
+ interface Plan extends Variant {
110
+ months: number;
111
+ }
112
+
113
+ const lucky = createFeelingLucky<Plan>({
114
+ prizes: [{ id: 'pro', name: 'Pro', icon: '/pro.svg', variants: [{ tier: 'big', label: '1 year', months: 12 }] }],
115
+ onClaim: async (win) => {
116
+ lucky.close();
117
+ router.push(`/redeem/${win.prize.id}?months=${win.variant?.months ?? 'all'}`);
118
+ },
119
+ });
120
+ ```
121
+
122
+ ### Developer menu
123
+
124
+ Ctrl+Shift+L in the room opens a password-gated panel that forces outcomes, themes and bonuses, for demos and testing. Without `passwordHash` it opens without a password. With it, only the password's SHA-256 hex goes in the config; checking it needs a secure context (https or localhost):
125
+
126
+ ```bash
127
+ printf '%s' 'my password' | sha256sum
128
+ ```
129
+
130
+ ## Languages
131
+
132
+ Every text, game names included, comes from the locale. Built in: `en`, `it`, `es`, `fr`, `de`. English ships with the library; the others load on demand, only when the room speaks them.
133
+
134
+ - **Default locale:** without `locale`, the room follows `<html lang>` and switches when the host app changes it, falling back to `navigator.language`.
135
+ - **Matching:** `pt-BR` uses `pt-BR`, then `pt`, then `en`.
136
+ - **New languages:** add them through `messages`. Missing keys fall back to `en`.
137
+
138
+ ```ts
139
+ import { createFeelingLucky, en } from '@adiakys/feeling-lucky';
140
+
141
+ createFeelingLucky({
142
+ prizes,
143
+ messages: {
144
+ pt: { ...en, room: 'Sala de jogos' /* … */ },
145
+ it: { games: { wheel: { name: 'Ruota d’oro' } } },
146
+ },
147
+ });
148
+ ```
149
+
150
+ ## Games
151
+
152
+ | Room | Games |
153
+ |---|---|
154
+ | Main hall | Grand Wheel (Prize Hunt, Heads or Tails, Pachinko bonus), Roulette, Slot, Pachinko, Scratch card |
155
+ | Salon Privé | Blackjack, Texas Hold'em, single player against the house |
156
+
157
+ - **Bonus of the day:** one main-hall game per day, the same for everyone, gets its own variant and boosted odds:
158
+ - Storm Roulette
159
+ - Booster on the Grand Wheel
160
+ - Takeoff or Breakaway in place of the slot
161
+ - Double Luck or Forever in place of the scratch card
162
+ - colour Pachinko
163
+ - **Dealers:** three shifts a day, the same for everyone, from the date's hash, see [Dealers](#dealers).
164
+ - **Room themes:** Christmas, Halloween, Easter and August, taken from the calendar.
165
+
166
+ ## Dealers
167
+
168
+ A dealer stands at the Salon Privé's tables during three shifts a day of 30 to 90 minutes between 10:00 and 23:00, local time. The shifts come from the date's hash, and the dealers in the list take them in turn. While a dealer is on shift, Blackjack and Texas Hold'em win twice as often. A dealer arriving or leaving mid-game walks in or out of the table, and the odds change from the next hand.
169
+
170
+ ```ts
171
+ interface Dealer {
172
+ image: string; // waist-up portrait, transparent background, forearms resting forward at the bottom
173
+ name?: string;
174
+ hands?: string; // CSS clip-path of the forearms and hands, drawn over the table's rim
175
+ }
176
+ ```
177
+
178
+ Without `dealers`, the library's own illustrated dealer takes every shift; `dealers: []` leaves the tables without one.
179
+
180
+ ## Structure
181
+
182
+ ```
183
+ src/
184
+ index.ts public API
185
+ config/ config types, defaults
186
+ engine/ outcomes, no DOM
187
+ runtime/ i18n, icons, sound, fx
188
+ room/ room, lobby, certificate
189
+ games/ one folder per game:
190
+ wheel, roulette, slot, pachinko,
191
+ scratch, blackjack, holdem
192
+ developer/ developer menu, lazy
193
+ styles/ CSS per area
194
+ locales/ en, it, es, fr, de
195
+ playground/ demo with sample prizes
196
+ tests/ unit (engine), e2e
197
+ ```
198
+
199
+ ### Rules
200
+
201
+ - **`engine/` decides every outcome** and never touches the DOM. Games only stage what it decides.
202
+ - **Rig seam:** the developer menu reaches the outcomes only through `engine/rig` (`decide(key, context, draw)`). Games don't know it exists.
203
+ - **Lit elements render into the room's shadow root, not into their own.** One stylesheet styles the whole room.
204
+ - **Every text lives in `locales/`.** Icons are inline SVG.
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ npm install
210
+ npm run dev # playground
211
+ npm test # unit tests
212
+ npm run test:e2e # one smoke test per game
213
+ npm run typecheck
214
+ npm run build # dist/: ESM + IIFE
215
+ npm run build:demo # site/: the playground, as on GitHub Pages
216
+ ```
217
+
218
+ ## Release
219
+
220
+ Publish a GitHub release or pre-release on a `v<version>` tag, e.g. `v1.2.0` or `v1.3.0-beta.1`: the version comes from the tag, `package.json` only holds a placeholder. The release workflow:
221
+ - runs the checks;
222
+ - publishes the package to npm: `latest` for a release, `next` for a pre-release;
223
+ - attaches the packed `.tgz` to the release;
224
+ - deploys the playground to GitHub Pages, for releases only.
225
+
226
+ ## License
227
+
228
+ [GPL-3.0-or-later](LICENSE)
@@ -0,0 +1,4 @@
1
+ import type { FeelingLuckyConfig, Resolvable } from './types';
2
+ import type { RoomConfig } from '../room/room';
3
+ export declare const resolve: <T>(value: Resolvable<T>) => Promise<T>;
4
+ export declare function resolveConfig(config: FeelingLuckyConfig): Promise<RoomConfig>;
@@ -0,0 +1,62 @@
1
+ export type Tier = 'none' | 'small' | 'big' | 'jackpot';
2
+ export type PrizeTier = Exclude<Tier, 'none'>;
3
+ export type GameId = 'wheel' | 'slot' | 'roulette' | 'pachinko' | 'scratch' | 'blackjack' | 'holdem';
4
+ export type Resolvable<T> = T | (() => T | Promise<T>);
5
+ export interface Variant {
6
+ tier: PrizeTier;
7
+ label: string;
8
+ short?: string;
9
+ details?: {
10
+ label: string;
11
+ value: string;
12
+ }[];
13
+ }
14
+ export interface Prize<V extends Variant = Variant> {
15
+ id: string;
16
+ name: string;
17
+ icon: string;
18
+ color?: string;
19
+ variants?: V[] | ((tier: PrizeTier) => V | Promise<V>);
20
+ }
21
+ export interface Win<V extends Variant = Variant> {
22
+ prize: Prize<V>;
23
+ variant: V | null;
24
+ tier: PrizeTier;
25
+ game: GameId;
26
+ }
27
+ export interface Dealer {
28
+ image: string;
29
+ name?: string;
30
+ hands?: string;
31
+ }
32
+ export interface Player {
33
+ name: string;
34
+ avatar?: string;
35
+ }
36
+ export type Messages = {
37
+ [key: string]: string | Messages;
38
+ };
39
+ export interface FeelingLuckyConfig<V extends Variant = Variant> {
40
+ prizes: Resolvable<Prize<V>[]>;
41
+ locale?: Resolvable<string>;
42
+ messages?: Resolvable<Record<string, Messages>>;
43
+ player?: Resolvable<Player>;
44
+ logo?: Resolvable<string>;
45
+ dealers?: Resolvable<Dealer[]>;
46
+ onWin?: (win: Win<V>) => void;
47
+ onClaim?: (win: Win<V>) => Promise<void>;
48
+ developer?: Resolvable<boolean | {
49
+ passwordHash?: string;
50
+ }>;
51
+ }
52
+ export interface FeelingLucky<V extends Variant = Variant> {
53
+ open(options?: {
54
+ from?: Element | {
55
+ x: number;
56
+ y: number;
57
+ };
58
+ }): void;
59
+ close(): void;
60
+ update(config: Partial<FeelingLuckyConfig<V>>): void;
61
+ destroy(): void;
62
+ }