@open-slot-ui/core 0.4.2 → 0.5.1
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/dist/index.cjs +250 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -19
- package/dist/index.d.ts +133 -19
- package/dist/index.js +248 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -188,6 +188,13 @@ declare function extendTheme(base: Theme, patch: DeepPartial<Theme>): Theme;
|
|
|
188
188
|
type Orientation = 'landscape' | 'portrait';
|
|
189
189
|
/** A named device bucket. Config can target these to restyle per device. */
|
|
190
190
|
type Breakpoint = 'mobile' | 'tablet' | 'desktop';
|
|
191
|
+
/** The uniformly-scaled DESIGN FRAME ("stage") rect, in screen pixels. */
|
|
192
|
+
interface StageRect {
|
|
193
|
+
x: number;
|
|
194
|
+
y: number;
|
|
195
|
+
width: number;
|
|
196
|
+
height: number;
|
|
197
|
+
}
|
|
191
198
|
interface ScreenState {
|
|
192
199
|
width: number;
|
|
193
200
|
height: number;
|
|
@@ -196,6 +203,15 @@ interface ScreenState {
|
|
|
196
203
|
breakpoint: Breakpoint;
|
|
197
204
|
/** Multiply reference-px sizes by this to fit the current screen. */
|
|
198
205
|
scale: number;
|
|
206
|
+
/**
|
|
207
|
+
* The reference design frame, scaled UNIFORMLY by `scale` and placed in the viewport
|
|
208
|
+
* (letterboxed by `stageAnchor` when the aspect ratio differs). Every control anchors
|
|
209
|
+
* to THIS rect — not the raw screen — so the whole HUD scales as one homogeneous unit
|
|
210
|
+
* and the relative gaps between controls never change with aspect ratio. At the
|
|
211
|
+
* reference resolution `stage` exactly equals the screen, so authored layouts are
|
|
212
|
+
* pixel-identical there.
|
|
213
|
+
*/
|
|
214
|
+
stage: StageRect;
|
|
199
215
|
}
|
|
200
216
|
interface LayoutConfig {
|
|
201
217
|
/** Reference design resolution for landscape / portrait. */
|
|
@@ -212,6 +228,14 @@ interface LayoutConfig {
|
|
|
212
228
|
mobile: number;
|
|
213
229
|
tablet: number;
|
|
214
230
|
};
|
|
231
|
+
/**
|
|
232
|
+
* Where the uniformly-scaled design frame sits in the viewport when the aspect ratio
|
|
233
|
+
* doesn't match the reference (i.e. how the letterbox margins are distributed), as
|
|
234
|
+
* `[x, y]` factors in `0..1`. `[0.5, 1]` (default) = bottom-centre: the bottom bar
|
|
235
|
+
* always hugs the screen bottom and any extra vertical room opens ABOVE (the reel
|
|
236
|
+
* area, filled by the game); horizontal slack splits evenly. `[0.5, 0.5]` centres it.
|
|
237
|
+
*/
|
|
238
|
+
stageAnchor: [number, number];
|
|
215
239
|
}
|
|
216
240
|
declare const defaultLayoutConfig: LayoutConfig;
|
|
217
241
|
/** Classify the shorter edge into a named device bucket. Pure, total. */
|
|
@@ -236,7 +260,16 @@ interface Placement {
|
|
|
236
260
|
/** Rotation in radians (resolved from `LayoutSpec.rotation`, which is degrees). */
|
|
237
261
|
rotation: number;
|
|
238
262
|
}
|
|
239
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Resolve a control's layout against the current screen. Pure math.
|
|
265
|
+
*
|
|
266
|
+
* Anchors to the uniformly-scaled `screen.stage` frame — NOT the raw screen — so the
|
|
267
|
+
* whole HUD scales as one homogeneous unit: the gap between two controls is always a
|
|
268
|
+
* fixed fraction of the (uniformly-scaled) frame, never a function of the viewport's
|
|
269
|
+
* aspect ratio. That's what stops a growing value or a narrow window from letting
|
|
270
|
+
* controls drift into each other. At the reference resolution `stage` equals the
|
|
271
|
+
* screen, so authored offsets land pixel-identically.
|
|
272
|
+
*/
|
|
240
273
|
declare function resolvePlacement(spec: LayoutSpec, screen: ScreenState): Placement;
|
|
241
274
|
|
|
242
275
|
/**
|
|
@@ -800,6 +833,10 @@ declare class ReadoutControl extends Control {
|
|
|
800
833
|
readonly value: Signal<number>;
|
|
801
834
|
/** Whether a `'duration'` readout is currently advancing. */
|
|
802
835
|
readonly running: Signal<boolean>;
|
|
836
|
+
/** Accent emphasis: the renderer tints the value in the theme accent while on — for
|
|
837
|
+
* a MODIFIED readout (e.g. net position while a bet boost is active). Mirrors
|
|
838
|
+
* {@link ValueDisplay.emphasized}. */
|
|
839
|
+
readonly emphasized: Signal<boolean>;
|
|
803
840
|
readonly kind: ReadoutKind;
|
|
804
841
|
readonly label?: string;
|
|
805
842
|
readonly decimals: number;
|
|
@@ -809,6 +846,8 @@ declare class ReadoutControl extends Control {
|
|
|
809
846
|
constructor(opts: ReadoutOptions);
|
|
810
847
|
/** Never-reject: malformed input keeps the last good value (P11). */
|
|
811
848
|
set(v: number): void;
|
|
849
|
+
/** Accent-tint the value ("this readout is modified"). Strict boolean. */
|
|
850
|
+
setEmphasis(on: boolean): void;
|
|
812
851
|
get(): number;
|
|
813
852
|
setCurrency(spec: CurrencySpec): void;
|
|
814
853
|
/** Advance an elapsed-time readout by `deltaSec` (the renderer calls this each frame). */
|
|
@@ -1224,6 +1263,9 @@ declare class OpenUI {
|
|
|
1224
1263
|
readonly spin: SpinControl;
|
|
1225
1264
|
readonly balance: ValueDisplay;
|
|
1226
1265
|
readonly bet: ValueDisplay;
|
|
1266
|
+
/** Bonus "total win" readout — shown in the buy-feature slot during a bonus/free-
|
|
1267
|
+
* spins round (the renderer swaps it for the buy button). Same money logic as `bet`. */
|
|
1268
|
+
readonly totalWin: ValueDisplay;
|
|
1227
1269
|
readonly settingsButton: ButtonControl;
|
|
1228
1270
|
readonly settingsPanel: PanelControl;
|
|
1229
1271
|
readonly musicSlider: SliderControl;
|
|
@@ -1440,11 +1482,13 @@ type BlockSpec = {
|
|
|
1440
1482
|
id: string;
|
|
1441
1483
|
label?: string;
|
|
1442
1484
|
initial?: number;
|
|
1485
|
+
hint?: string;
|
|
1443
1486
|
} | {
|
|
1444
1487
|
kind: 'toggle';
|
|
1445
1488
|
id: string;
|
|
1446
1489
|
label?: string;
|
|
1447
1490
|
on?: boolean;
|
|
1491
|
+
hint?: string;
|
|
1448
1492
|
} | {
|
|
1449
1493
|
kind: 'button';
|
|
1450
1494
|
id: string;
|
|
@@ -1452,18 +1496,21 @@ type BlockSpec = {
|
|
|
1452
1496
|
action?: 'closePanel' | 'openPanel' | 'emit';
|
|
1453
1497
|
target?: string;
|
|
1454
1498
|
role?: string;
|
|
1499
|
+
hint?: string;
|
|
1455
1500
|
} | {
|
|
1456
1501
|
kind: 'select';
|
|
1457
1502
|
id: string;
|
|
1458
1503
|
label?: string;
|
|
1459
1504
|
options: SelectOption[];
|
|
1460
1505
|
index?: number;
|
|
1506
|
+
hint?: string;
|
|
1461
1507
|
} | {
|
|
1462
1508
|
kind: 'stepper';
|
|
1463
1509
|
id: string;
|
|
1464
1510
|
label?: string;
|
|
1465
1511
|
levels: number[];
|
|
1466
1512
|
index?: number;
|
|
1513
|
+
hint?: string;
|
|
1467
1514
|
} | {
|
|
1468
1515
|
kind: 'value';
|
|
1469
1516
|
id: string;
|
|
@@ -1712,6 +1759,60 @@ declare function resolveTurboModes(modes: TurboSpec['modes']): string[];
|
|
|
1712
1759
|
declare function defineUI(spec: UISpec): UISpec;
|
|
1713
1760
|
declare function createUI(spec?: UISpec, hooks?: HostHooks): OpenUI;
|
|
1714
1761
|
|
|
1762
|
+
/**
|
|
1763
|
+
* Social-mode FORBIDDEN-PHRASE checker (Charter B8/P11). Stake US social/sweepstakes
|
|
1764
|
+
* jurisdiction restricts gambling wording; a game must not surface "bet", "pay(table)",
|
|
1765
|
+
* "funds", "cash", etc. anywhere in its copy. This scans the ENGLISH strings a game
|
|
1766
|
+
* ships (menu blocks, rules, section titles, control labels/hints, the `en` dictionary,
|
|
1767
|
+
* the game name) and reports every restricted phrase with a compliant replacement, so
|
|
1768
|
+
* the classic "we shipped a *paytable* while `pay` is banned" slips through no longer.
|
|
1769
|
+
*
|
|
1770
|
+
* It's a lint, not a gate — never throws; `createUI` runs it automatically in social
|
|
1771
|
+
* mode and forwards findings to `HostHooks.onDataIssue` (+ a console warning), and a
|
|
1772
|
+
* game's own test can call {@link checkSocialPhrases} directly.
|
|
1773
|
+
*
|
|
1774
|
+
* See Stake's "Jurisdiction Requirements → forbidden phrases" for the authoritative
|
|
1775
|
+
* list; this covers the common roots and their recommended replacements.
|
|
1776
|
+
*/
|
|
1777
|
+
|
|
1778
|
+
interface ForbiddenMatch {
|
|
1779
|
+
/** The restricted root that matched ("pay*", "bet", "funds", …). */
|
|
1780
|
+
term: string;
|
|
1781
|
+
/** The recommended compliant replacement. */
|
|
1782
|
+
replacement: string;
|
|
1783
|
+
}
|
|
1784
|
+
interface SocialPhraseIssue {
|
|
1785
|
+
/** Where the copy lives (e.g. `menu.rules[3]`, `locale.en["Paytable"]`). */
|
|
1786
|
+
source: string;
|
|
1787
|
+
/** The offending string. */
|
|
1788
|
+
text: string;
|
|
1789
|
+
/** Every restricted phrase found in it. */
|
|
1790
|
+
matches: ForbiddenMatch[];
|
|
1791
|
+
}
|
|
1792
|
+
/** Every restricted phrase in `text` (empty when clean). Pure + total. */
|
|
1793
|
+
declare function findForbiddenPhrases(text: string): ForbiddenMatch[];
|
|
1794
|
+
/** A collected string. `text` is the base English (what renders with no social
|
|
1795
|
+
* override); `key` is the i18n key used to look up a social override — it defaults
|
|
1796
|
+
* to `text`, since a game's menu/rules copy doubles as its own key. */
|
|
1797
|
+
type Entry = {
|
|
1798
|
+
source: string;
|
|
1799
|
+
text: string;
|
|
1800
|
+
key?: string;
|
|
1801
|
+
};
|
|
1802
|
+
/** Collect every English string a spec ships (menu/rules blocks, titles, labels+hints,
|
|
1803
|
+
* game name, the `en` dictionary) with a source path — the input to {@link checkSocialPhrases}. */
|
|
1804
|
+
declare function collectSocialCopy(spec: UISpec): Entry[];
|
|
1805
|
+
/**
|
|
1806
|
+
* Scan a spec's English copy AS IT RENDERS IN SOCIAL MODE and return every restricted
|
|
1807
|
+
* phrase. Each collected string is first resolved through the social dictionary
|
|
1808
|
+
* (`locale.socialMessages.en` → built-in `openuiSocialDefaults` → the base text) —
|
|
1809
|
+
* exactly like the translator does — so a game that already swaps "bet"/"pay(table)"
|
|
1810
|
+
* for compliant wording in social mode is NOT flagged, while a phrase with NO social
|
|
1811
|
+
* override (the classic slipped-through "paytable") IS. English by design: the check
|
|
1812
|
+
* targets the base `en` copy that every jurisdiction review starts from.
|
|
1813
|
+
*/
|
|
1814
|
+
declare function checkSocialPhrases(spec: UISpec): SocialPhraseIssue[];
|
|
1815
|
+
|
|
1715
1816
|
/**
|
|
1716
1817
|
* The responsive layer: re-apply per-device / per-orientation control overrides
|
|
1717
1818
|
* every time the screen bucket changes. Pure assembly over the existing layout
|
|
@@ -1772,36 +1873,49 @@ declare class EventLog {
|
|
|
1772
1873
|
/**
|
|
1773
1874
|
* Currency display metadata + a pure formatter (Charter P11: data, not code).
|
|
1774
1875
|
*
|
|
1775
|
-
* Stake Engine
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1876
|
+
* This is the **Stake Engine currency table**: every code Stake supports, mapped to
|
|
1877
|
+
* its display SYMBOL, minor-unit decimals, and symbol side (before/after the number).
|
|
1878
|
+
* A game shouldn't hand-tune any of this — it either passes a full `CurrencySpec`, or
|
|
1879
|
+
* just the CODE (`currency: 'CNY'`) and gets the Stake formatting for free
|
|
1880
|
+
* ("I use the Stake currency formatter"). Unknown codes fall back to a 2-decimal,
|
|
1881
|
+
* code-suffix spec so nothing ever breaks. The UI computes no money — it only formats
|
|
1882
|
+
* what the game sets.
|
|
1780
1883
|
*/
|
|
1781
1884
|
|
|
1782
1885
|
interface CurrencyInfo {
|
|
1783
|
-
/**
|
|
1886
|
+
/** The glyph shown to the player ("$", "CN¥", "GC"). */
|
|
1887
|
+
symbol: string;
|
|
1888
|
+
/** Fractional digits to show (JPY/KRW/IDR = 0, USD = 2, BTC = 8). */
|
|
1784
1889
|
decimals: number;
|
|
1785
|
-
/**
|
|
1786
|
-
|
|
1787
|
-
/** A social / sweepstakes coin
|
|
1890
|
+
/** Symbol AFTER the number ("10,00 zł") rather than before ("$10.00"). Default before. */
|
|
1891
|
+
symbolAfter?: boolean;
|
|
1892
|
+
/** A social / sweepstakes coin (Gold Coins / Stake Cash) — never fiat wording. */
|
|
1788
1893
|
social?: boolean;
|
|
1789
1894
|
}
|
|
1790
|
-
/**
|
|
1895
|
+
/**
|
|
1896
|
+
* The Stake Engine supported-currency matrix (symbol · decimals · placement), 1:1 with
|
|
1897
|
+
* the platform's `CurrencyMeta`. Symbol placement: prefix by default, SUFFIX for the
|
|
1898
|
+
* few that render after the amount (DKK/PLN/VND/CLP/ARS/PEN). Crypto is included for
|
|
1899
|
+
* completeness (8-dp with a symbol) so high-precision balances also format right.
|
|
1900
|
+
*/
|
|
1791
1901
|
declare const CURRENCY_TABLE: Readonly<Record<string, CurrencyInfo>>;
|
|
1792
|
-
/** True if `code` is a Stake social/sweepstakes coin (
|
|
1902
|
+
/** True if `code` is a Stake social/sweepstakes coin (displayed "GC"/"SC"). */
|
|
1793
1903
|
declare function isSocialCurrency(code: string): boolean;
|
|
1794
1904
|
/**
|
|
1795
|
-
* Resolve a currency code to a complete, display-ready {@link CurrencySpec}
|
|
1796
|
-
*
|
|
1797
|
-
* Anything in `overrides` wins
|
|
1905
|
+
* Resolve a currency code to a complete, display-ready {@link CurrencySpec} using the
|
|
1906
|
+
* Stake table: fills the SYMBOL (rendered tight, `display:'symbol'`), its side
|
|
1907
|
+
* (`position`), and the minor-unit `decimals`. Anything in `overrides` wins so a game
|
|
1908
|
+
* can still hand-tune (e.g. force more decimals for sub-cent payouts). An unknown code
|
|
1909
|
+
* degrades to a 2-decimal code-suffix spec. Never throws.
|
|
1798
1910
|
*/
|
|
1799
1911
|
declare function resolveCurrency(code: string, overrides?: Partial<CurrencySpec>): CurrencySpec;
|
|
1800
1912
|
/**
|
|
1801
1913
|
* Format an amount (major units) per a {@link CurrencySpec}: grouped integer part,
|
|
1802
|
-
* fixed decimals, the
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
1914
|
+
* fixed decimals, and the affix on the configured side. When `display:'symbol'` (and a
|
|
1915
|
+
* symbol is set) the SYMBOL sits tight against the number (`CN¥1,234.56` · `1.234,56 zł`);
|
|
1916
|
+
* otherwise the ISO code is spaced (`1,234.56 USD`). `signed` adds an explicit "+" for
|
|
1917
|
+
* non-negative values (used by the net-position readout). Pure + total: a malformed
|
|
1918
|
+
* number renders as "0".
|
|
1805
1919
|
*/
|
|
1806
1920
|
declare function formatAmount(value: number, spec: CurrencySpec, opts?: {
|
|
1807
1921
|
signed?: boolean;
|
|
@@ -1834,4 +1948,4 @@ declare function buildBetLadder(cfg: RgsBetConfig, divisor?: number): {
|
|
|
1834
1948
|
/** Clamp a stake (major units) to the RGS min/max and snap to `stepBet`. Pure. */
|
|
1835
1949
|
declare function clampBet(amount: number, cfg: RgsBetConfig, divisor?: number): number;
|
|
1836
1950
|
|
|
1837
|
-
export { API_AMOUNT_DIVISOR, type Anchor, AutoplayControl, type AutoplayLimits, type AutoplayMode, type AutoplayOptions, BLOCK_KINDS, type BlockFactory, type BlockSpec, type Breakpoint, type BuiltPanel, ButtonControl, type ButtonOptions, CURRENCY_TABLE, CardControl, type CardOptions, type ComposeMenuOptions, Control, type ControlOptions, type ControlOverride, ControlRegistry, type ControlSnapshot, type CurrencyInfo, type CurrencySpec, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, type DeepPartial, DictionaryTranslator, type Dispose, EventBus, EventLog, type EventLogOptions, type EventMap, Fade, type HostHooks, type JurisdictionConfig, type KnownControlId, LOCALE_LABELS, type LayoutConfig, type LayoutSpec, type LoggedEvent, type MenuSpec, type NoticeAction, type NoticeOptions, OpenUI, type OpenUIEvents, type OpenUIOptions, type Orientation, PanelControl, type PanelOptions, type PanelSpec, type PanelVariant, Parallel, type Placement, Pulse, RGS_ERROR_KEYS, ReadoutControl, type ReadoutKind, type ReadoutOptions, type RealityCheckOptions, type Rect, type ResponsiveKey, type ResponsiveOverride, type RgsBetConfig, type RgsErrorCode, type RgsErrorOptions, type ScreenState, SelectControl, type SelectControlOptions, type SelectOption, Sequence, Signal, SliderControl, type SliderOptions, type SpecIssue, SpinControl, type SpinPress, type SpinSpec, Squish, type StateDef, type StateMap, StepperControl, type StepperOptions, type Subscribable, type Theme, type ThemeChoice, type ThemeIssue, type ThemeOverrides, type ThemePreset, ToggleControl, type ToggleOptions, type Transition, type Translator, TurboControl, type TurboOptions, type TurboSpec, Turn, type UISpec, ValueDisplay, type ValueDisplayOptions, type ViewInspect, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, clampBet, clampDecimals, clampDigits, clampMinDigits, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
|
|
1951
|
+
export { API_AMOUNT_DIVISOR, type Anchor, AutoplayControl, type AutoplayLimits, type AutoplayMode, type AutoplayOptions, BLOCK_KINDS, type BlockFactory, type BlockSpec, type Breakpoint, type BuiltPanel, ButtonControl, type ButtonOptions, CURRENCY_TABLE, CardControl, type CardOptions, type ComposeMenuOptions, Control, type ControlOptions, type ControlOverride, ControlRegistry, type ControlSnapshot, type CurrencyInfo, type CurrencySpec, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, type DeepPartial, DictionaryTranslator, type Dispose, EventBus, EventLog, type EventLogOptions, type EventMap, Fade, type ForbiddenMatch, type HostHooks, type JurisdictionConfig, type KnownControlId, LOCALE_LABELS, type LayoutConfig, type LayoutSpec, type LoggedEvent, type MenuSpec, type NoticeAction, type NoticeOptions, OpenUI, type OpenUIEvents, type OpenUIOptions, type Orientation, PanelControl, type PanelOptions, type PanelSpec, type PanelVariant, Parallel, type Placement, Pulse, RGS_ERROR_KEYS, ReadoutControl, type ReadoutKind, type ReadoutOptions, type RealityCheckOptions, type Rect, type ResponsiveKey, type ResponsiveOverride, type RgsBetConfig, type RgsErrorCode, type RgsErrorOptions, type ScreenState, SelectControl, type SelectControlOptions, type SelectOption, Sequence, Signal, SliderControl, type SliderOptions, type SocialPhraseIssue, type SpecIssue, SpinControl, type SpinPress, type SpinSpec, Squish, type StageRect, type StateDef, type StateMap, StepperControl, type StepperOptions, type Subscribable, type Theme, type ThemeChoice, type ThemeIssue, type ThemeOverrides, type ThemePreset, ToggleControl, type ToggleOptions, type Transition, type Translator, TurboControl, type TurboOptions, type TurboSpec, Turn, type UISpec, ValueDisplay, type ValueDisplayOptions, type ViewInspect, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, checkSocialPhrases, clampBet, clampDecimals, clampDigits, clampMinDigits, collectSocialCopy, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, findForbiddenPhrases, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
|
package/dist/index.d.ts
CHANGED
|
@@ -188,6 +188,13 @@ declare function extendTheme(base: Theme, patch: DeepPartial<Theme>): Theme;
|
|
|
188
188
|
type Orientation = 'landscape' | 'portrait';
|
|
189
189
|
/** A named device bucket. Config can target these to restyle per device. */
|
|
190
190
|
type Breakpoint = 'mobile' | 'tablet' | 'desktop';
|
|
191
|
+
/** The uniformly-scaled DESIGN FRAME ("stage") rect, in screen pixels. */
|
|
192
|
+
interface StageRect {
|
|
193
|
+
x: number;
|
|
194
|
+
y: number;
|
|
195
|
+
width: number;
|
|
196
|
+
height: number;
|
|
197
|
+
}
|
|
191
198
|
interface ScreenState {
|
|
192
199
|
width: number;
|
|
193
200
|
height: number;
|
|
@@ -196,6 +203,15 @@ interface ScreenState {
|
|
|
196
203
|
breakpoint: Breakpoint;
|
|
197
204
|
/** Multiply reference-px sizes by this to fit the current screen. */
|
|
198
205
|
scale: number;
|
|
206
|
+
/**
|
|
207
|
+
* The reference design frame, scaled UNIFORMLY by `scale` and placed in the viewport
|
|
208
|
+
* (letterboxed by `stageAnchor` when the aspect ratio differs). Every control anchors
|
|
209
|
+
* to THIS rect — not the raw screen — so the whole HUD scales as one homogeneous unit
|
|
210
|
+
* and the relative gaps between controls never change with aspect ratio. At the
|
|
211
|
+
* reference resolution `stage` exactly equals the screen, so authored layouts are
|
|
212
|
+
* pixel-identical there.
|
|
213
|
+
*/
|
|
214
|
+
stage: StageRect;
|
|
199
215
|
}
|
|
200
216
|
interface LayoutConfig {
|
|
201
217
|
/** Reference design resolution for landscape / portrait. */
|
|
@@ -212,6 +228,14 @@ interface LayoutConfig {
|
|
|
212
228
|
mobile: number;
|
|
213
229
|
tablet: number;
|
|
214
230
|
};
|
|
231
|
+
/**
|
|
232
|
+
* Where the uniformly-scaled design frame sits in the viewport when the aspect ratio
|
|
233
|
+
* doesn't match the reference (i.e. how the letterbox margins are distributed), as
|
|
234
|
+
* `[x, y]` factors in `0..1`. `[0.5, 1]` (default) = bottom-centre: the bottom bar
|
|
235
|
+
* always hugs the screen bottom and any extra vertical room opens ABOVE (the reel
|
|
236
|
+
* area, filled by the game); horizontal slack splits evenly. `[0.5, 0.5]` centres it.
|
|
237
|
+
*/
|
|
238
|
+
stageAnchor: [number, number];
|
|
215
239
|
}
|
|
216
240
|
declare const defaultLayoutConfig: LayoutConfig;
|
|
217
241
|
/** Classify the shorter edge into a named device bucket. Pure, total. */
|
|
@@ -236,7 +260,16 @@ interface Placement {
|
|
|
236
260
|
/** Rotation in radians (resolved from `LayoutSpec.rotation`, which is degrees). */
|
|
237
261
|
rotation: number;
|
|
238
262
|
}
|
|
239
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Resolve a control's layout against the current screen. Pure math.
|
|
265
|
+
*
|
|
266
|
+
* Anchors to the uniformly-scaled `screen.stage` frame — NOT the raw screen — so the
|
|
267
|
+
* whole HUD scales as one homogeneous unit: the gap between two controls is always a
|
|
268
|
+
* fixed fraction of the (uniformly-scaled) frame, never a function of the viewport's
|
|
269
|
+
* aspect ratio. That's what stops a growing value or a narrow window from letting
|
|
270
|
+
* controls drift into each other. At the reference resolution `stage` equals the
|
|
271
|
+
* screen, so authored offsets land pixel-identically.
|
|
272
|
+
*/
|
|
240
273
|
declare function resolvePlacement(spec: LayoutSpec, screen: ScreenState): Placement;
|
|
241
274
|
|
|
242
275
|
/**
|
|
@@ -800,6 +833,10 @@ declare class ReadoutControl extends Control {
|
|
|
800
833
|
readonly value: Signal<number>;
|
|
801
834
|
/** Whether a `'duration'` readout is currently advancing. */
|
|
802
835
|
readonly running: Signal<boolean>;
|
|
836
|
+
/** Accent emphasis: the renderer tints the value in the theme accent while on — for
|
|
837
|
+
* a MODIFIED readout (e.g. net position while a bet boost is active). Mirrors
|
|
838
|
+
* {@link ValueDisplay.emphasized}. */
|
|
839
|
+
readonly emphasized: Signal<boolean>;
|
|
803
840
|
readonly kind: ReadoutKind;
|
|
804
841
|
readonly label?: string;
|
|
805
842
|
readonly decimals: number;
|
|
@@ -809,6 +846,8 @@ declare class ReadoutControl extends Control {
|
|
|
809
846
|
constructor(opts: ReadoutOptions);
|
|
810
847
|
/** Never-reject: malformed input keeps the last good value (P11). */
|
|
811
848
|
set(v: number): void;
|
|
849
|
+
/** Accent-tint the value ("this readout is modified"). Strict boolean. */
|
|
850
|
+
setEmphasis(on: boolean): void;
|
|
812
851
|
get(): number;
|
|
813
852
|
setCurrency(spec: CurrencySpec): void;
|
|
814
853
|
/** Advance an elapsed-time readout by `deltaSec` (the renderer calls this each frame). */
|
|
@@ -1224,6 +1263,9 @@ declare class OpenUI {
|
|
|
1224
1263
|
readonly spin: SpinControl;
|
|
1225
1264
|
readonly balance: ValueDisplay;
|
|
1226
1265
|
readonly bet: ValueDisplay;
|
|
1266
|
+
/** Bonus "total win" readout — shown in the buy-feature slot during a bonus/free-
|
|
1267
|
+
* spins round (the renderer swaps it for the buy button). Same money logic as `bet`. */
|
|
1268
|
+
readonly totalWin: ValueDisplay;
|
|
1227
1269
|
readonly settingsButton: ButtonControl;
|
|
1228
1270
|
readonly settingsPanel: PanelControl;
|
|
1229
1271
|
readonly musicSlider: SliderControl;
|
|
@@ -1440,11 +1482,13 @@ type BlockSpec = {
|
|
|
1440
1482
|
id: string;
|
|
1441
1483
|
label?: string;
|
|
1442
1484
|
initial?: number;
|
|
1485
|
+
hint?: string;
|
|
1443
1486
|
} | {
|
|
1444
1487
|
kind: 'toggle';
|
|
1445
1488
|
id: string;
|
|
1446
1489
|
label?: string;
|
|
1447
1490
|
on?: boolean;
|
|
1491
|
+
hint?: string;
|
|
1448
1492
|
} | {
|
|
1449
1493
|
kind: 'button';
|
|
1450
1494
|
id: string;
|
|
@@ -1452,18 +1496,21 @@ type BlockSpec = {
|
|
|
1452
1496
|
action?: 'closePanel' | 'openPanel' | 'emit';
|
|
1453
1497
|
target?: string;
|
|
1454
1498
|
role?: string;
|
|
1499
|
+
hint?: string;
|
|
1455
1500
|
} | {
|
|
1456
1501
|
kind: 'select';
|
|
1457
1502
|
id: string;
|
|
1458
1503
|
label?: string;
|
|
1459
1504
|
options: SelectOption[];
|
|
1460
1505
|
index?: number;
|
|
1506
|
+
hint?: string;
|
|
1461
1507
|
} | {
|
|
1462
1508
|
kind: 'stepper';
|
|
1463
1509
|
id: string;
|
|
1464
1510
|
label?: string;
|
|
1465
1511
|
levels: number[];
|
|
1466
1512
|
index?: number;
|
|
1513
|
+
hint?: string;
|
|
1467
1514
|
} | {
|
|
1468
1515
|
kind: 'value';
|
|
1469
1516
|
id: string;
|
|
@@ -1712,6 +1759,60 @@ declare function resolveTurboModes(modes: TurboSpec['modes']): string[];
|
|
|
1712
1759
|
declare function defineUI(spec: UISpec): UISpec;
|
|
1713
1760
|
declare function createUI(spec?: UISpec, hooks?: HostHooks): OpenUI;
|
|
1714
1761
|
|
|
1762
|
+
/**
|
|
1763
|
+
* Social-mode FORBIDDEN-PHRASE checker (Charter B8/P11). Stake US social/sweepstakes
|
|
1764
|
+
* jurisdiction restricts gambling wording; a game must not surface "bet", "pay(table)",
|
|
1765
|
+
* "funds", "cash", etc. anywhere in its copy. This scans the ENGLISH strings a game
|
|
1766
|
+
* ships (menu blocks, rules, section titles, control labels/hints, the `en` dictionary,
|
|
1767
|
+
* the game name) and reports every restricted phrase with a compliant replacement, so
|
|
1768
|
+
* the classic "we shipped a *paytable* while `pay` is banned" slips through no longer.
|
|
1769
|
+
*
|
|
1770
|
+
* It's a lint, not a gate — never throws; `createUI` runs it automatically in social
|
|
1771
|
+
* mode and forwards findings to `HostHooks.onDataIssue` (+ a console warning), and a
|
|
1772
|
+
* game's own test can call {@link checkSocialPhrases} directly.
|
|
1773
|
+
*
|
|
1774
|
+
* See Stake's "Jurisdiction Requirements → forbidden phrases" for the authoritative
|
|
1775
|
+
* list; this covers the common roots and their recommended replacements.
|
|
1776
|
+
*/
|
|
1777
|
+
|
|
1778
|
+
interface ForbiddenMatch {
|
|
1779
|
+
/** The restricted root that matched ("pay*", "bet", "funds", …). */
|
|
1780
|
+
term: string;
|
|
1781
|
+
/** The recommended compliant replacement. */
|
|
1782
|
+
replacement: string;
|
|
1783
|
+
}
|
|
1784
|
+
interface SocialPhraseIssue {
|
|
1785
|
+
/** Where the copy lives (e.g. `menu.rules[3]`, `locale.en["Paytable"]`). */
|
|
1786
|
+
source: string;
|
|
1787
|
+
/** The offending string. */
|
|
1788
|
+
text: string;
|
|
1789
|
+
/** Every restricted phrase found in it. */
|
|
1790
|
+
matches: ForbiddenMatch[];
|
|
1791
|
+
}
|
|
1792
|
+
/** Every restricted phrase in `text` (empty when clean). Pure + total. */
|
|
1793
|
+
declare function findForbiddenPhrases(text: string): ForbiddenMatch[];
|
|
1794
|
+
/** A collected string. `text` is the base English (what renders with no social
|
|
1795
|
+
* override); `key` is the i18n key used to look up a social override — it defaults
|
|
1796
|
+
* to `text`, since a game's menu/rules copy doubles as its own key. */
|
|
1797
|
+
type Entry = {
|
|
1798
|
+
source: string;
|
|
1799
|
+
text: string;
|
|
1800
|
+
key?: string;
|
|
1801
|
+
};
|
|
1802
|
+
/** Collect every English string a spec ships (menu/rules blocks, titles, labels+hints,
|
|
1803
|
+
* game name, the `en` dictionary) with a source path — the input to {@link checkSocialPhrases}. */
|
|
1804
|
+
declare function collectSocialCopy(spec: UISpec): Entry[];
|
|
1805
|
+
/**
|
|
1806
|
+
* Scan a spec's English copy AS IT RENDERS IN SOCIAL MODE and return every restricted
|
|
1807
|
+
* phrase. Each collected string is first resolved through the social dictionary
|
|
1808
|
+
* (`locale.socialMessages.en` → built-in `openuiSocialDefaults` → the base text) —
|
|
1809
|
+
* exactly like the translator does — so a game that already swaps "bet"/"pay(table)"
|
|
1810
|
+
* for compliant wording in social mode is NOT flagged, while a phrase with NO social
|
|
1811
|
+
* override (the classic slipped-through "paytable") IS. English by design: the check
|
|
1812
|
+
* targets the base `en` copy that every jurisdiction review starts from.
|
|
1813
|
+
*/
|
|
1814
|
+
declare function checkSocialPhrases(spec: UISpec): SocialPhraseIssue[];
|
|
1815
|
+
|
|
1715
1816
|
/**
|
|
1716
1817
|
* The responsive layer: re-apply per-device / per-orientation control overrides
|
|
1717
1818
|
* every time the screen bucket changes. Pure assembly over the existing layout
|
|
@@ -1772,36 +1873,49 @@ declare class EventLog {
|
|
|
1772
1873
|
/**
|
|
1773
1874
|
* Currency display metadata + a pure formatter (Charter P11: data, not code).
|
|
1774
1875
|
*
|
|
1775
|
-
* Stake Engine
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1876
|
+
* This is the **Stake Engine currency table**: every code Stake supports, mapped to
|
|
1877
|
+
* its display SYMBOL, minor-unit decimals, and symbol side (before/after the number).
|
|
1878
|
+
* A game shouldn't hand-tune any of this — it either passes a full `CurrencySpec`, or
|
|
1879
|
+
* just the CODE (`currency: 'CNY'`) and gets the Stake formatting for free
|
|
1880
|
+
* ("I use the Stake currency formatter"). Unknown codes fall back to a 2-decimal,
|
|
1881
|
+
* code-suffix spec so nothing ever breaks. The UI computes no money — it only formats
|
|
1882
|
+
* what the game sets.
|
|
1780
1883
|
*/
|
|
1781
1884
|
|
|
1782
1885
|
interface CurrencyInfo {
|
|
1783
|
-
/**
|
|
1886
|
+
/** The glyph shown to the player ("$", "CN¥", "GC"). */
|
|
1887
|
+
symbol: string;
|
|
1888
|
+
/** Fractional digits to show (JPY/KRW/IDR = 0, USD = 2, BTC = 8). */
|
|
1784
1889
|
decimals: number;
|
|
1785
|
-
/**
|
|
1786
|
-
|
|
1787
|
-
/** A social / sweepstakes coin
|
|
1890
|
+
/** Symbol AFTER the number ("10,00 zł") rather than before ("$10.00"). Default before. */
|
|
1891
|
+
symbolAfter?: boolean;
|
|
1892
|
+
/** A social / sweepstakes coin (Gold Coins / Stake Cash) — never fiat wording. */
|
|
1788
1893
|
social?: boolean;
|
|
1789
1894
|
}
|
|
1790
|
-
/**
|
|
1895
|
+
/**
|
|
1896
|
+
* The Stake Engine supported-currency matrix (symbol · decimals · placement), 1:1 with
|
|
1897
|
+
* the platform's `CurrencyMeta`. Symbol placement: prefix by default, SUFFIX for the
|
|
1898
|
+
* few that render after the amount (DKK/PLN/VND/CLP/ARS/PEN). Crypto is included for
|
|
1899
|
+
* completeness (8-dp with a symbol) so high-precision balances also format right.
|
|
1900
|
+
*/
|
|
1791
1901
|
declare const CURRENCY_TABLE: Readonly<Record<string, CurrencyInfo>>;
|
|
1792
|
-
/** True if `code` is a Stake social/sweepstakes coin (
|
|
1902
|
+
/** True if `code` is a Stake social/sweepstakes coin (displayed "GC"/"SC"). */
|
|
1793
1903
|
declare function isSocialCurrency(code: string): boolean;
|
|
1794
1904
|
/**
|
|
1795
|
-
* Resolve a currency code to a complete, display-ready {@link CurrencySpec}
|
|
1796
|
-
*
|
|
1797
|
-
* Anything in `overrides` wins
|
|
1905
|
+
* Resolve a currency code to a complete, display-ready {@link CurrencySpec} using the
|
|
1906
|
+
* Stake table: fills the SYMBOL (rendered tight, `display:'symbol'`), its side
|
|
1907
|
+
* (`position`), and the minor-unit `decimals`. Anything in `overrides` wins so a game
|
|
1908
|
+
* can still hand-tune (e.g. force more decimals for sub-cent payouts). An unknown code
|
|
1909
|
+
* degrades to a 2-decimal code-suffix spec. Never throws.
|
|
1798
1910
|
*/
|
|
1799
1911
|
declare function resolveCurrency(code: string, overrides?: Partial<CurrencySpec>): CurrencySpec;
|
|
1800
1912
|
/**
|
|
1801
1913
|
* Format an amount (major units) per a {@link CurrencySpec}: grouped integer part,
|
|
1802
|
-
* fixed decimals, the
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
1914
|
+
* fixed decimals, and the affix on the configured side. When `display:'symbol'` (and a
|
|
1915
|
+
* symbol is set) the SYMBOL sits tight against the number (`CN¥1,234.56` · `1.234,56 zł`);
|
|
1916
|
+
* otherwise the ISO code is spaced (`1,234.56 USD`). `signed` adds an explicit "+" for
|
|
1917
|
+
* non-negative values (used by the net-position readout). Pure + total: a malformed
|
|
1918
|
+
* number renders as "0".
|
|
1805
1919
|
*/
|
|
1806
1920
|
declare function formatAmount(value: number, spec: CurrencySpec, opts?: {
|
|
1807
1921
|
signed?: boolean;
|
|
@@ -1834,4 +1948,4 @@ declare function buildBetLadder(cfg: RgsBetConfig, divisor?: number): {
|
|
|
1834
1948
|
/** Clamp a stake (major units) to the RGS min/max and snap to `stepBet`. Pure. */
|
|
1835
1949
|
declare function clampBet(amount: number, cfg: RgsBetConfig, divisor?: number): number;
|
|
1836
1950
|
|
|
1837
|
-
export { API_AMOUNT_DIVISOR, type Anchor, AutoplayControl, type AutoplayLimits, type AutoplayMode, type AutoplayOptions, BLOCK_KINDS, type BlockFactory, type BlockSpec, type Breakpoint, type BuiltPanel, ButtonControl, type ButtonOptions, CURRENCY_TABLE, CardControl, type CardOptions, type ComposeMenuOptions, Control, type ControlOptions, type ControlOverride, ControlRegistry, type ControlSnapshot, type CurrencyInfo, type CurrencySpec, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, type DeepPartial, DictionaryTranslator, type Dispose, EventBus, EventLog, type EventLogOptions, type EventMap, Fade, type HostHooks, type JurisdictionConfig, type KnownControlId, LOCALE_LABELS, type LayoutConfig, type LayoutSpec, type LoggedEvent, type MenuSpec, type NoticeAction, type NoticeOptions, OpenUI, type OpenUIEvents, type OpenUIOptions, type Orientation, PanelControl, type PanelOptions, type PanelSpec, type PanelVariant, Parallel, type Placement, Pulse, RGS_ERROR_KEYS, ReadoutControl, type ReadoutKind, type ReadoutOptions, type RealityCheckOptions, type Rect, type ResponsiveKey, type ResponsiveOverride, type RgsBetConfig, type RgsErrorCode, type RgsErrorOptions, type ScreenState, SelectControl, type SelectControlOptions, type SelectOption, Sequence, Signal, SliderControl, type SliderOptions, type SpecIssue, SpinControl, type SpinPress, type SpinSpec, Squish, type StateDef, type StateMap, StepperControl, type StepperOptions, type Subscribable, type Theme, type ThemeChoice, type ThemeIssue, type ThemeOverrides, type ThemePreset, ToggleControl, type ToggleOptions, type Transition, type Translator, TurboControl, type TurboOptions, type TurboSpec, Turn, type UISpec, ValueDisplay, type ValueDisplayOptions, type ViewInspect, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, clampBet, clampDecimals, clampDigits, clampMinDigits, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
|
|
1951
|
+
export { API_AMOUNT_DIVISOR, type Anchor, AutoplayControl, type AutoplayLimits, type AutoplayMode, type AutoplayOptions, BLOCK_KINDS, type BlockFactory, type BlockSpec, type Breakpoint, type BuiltPanel, ButtonControl, type ButtonOptions, CURRENCY_TABLE, CardControl, type CardOptions, type ComposeMenuOptions, Control, type ControlOptions, type ControlOverride, ControlRegistry, type ControlSnapshot, type CurrencyInfo, type CurrencySpec, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, type DeepPartial, DictionaryTranslator, type Dispose, EventBus, EventLog, type EventLogOptions, type EventMap, Fade, type ForbiddenMatch, type HostHooks, type JurisdictionConfig, type KnownControlId, LOCALE_LABELS, type LayoutConfig, type LayoutSpec, type LoggedEvent, type MenuSpec, type NoticeAction, type NoticeOptions, OpenUI, type OpenUIEvents, type OpenUIOptions, type Orientation, PanelControl, type PanelOptions, type PanelSpec, type PanelVariant, Parallel, type Placement, Pulse, RGS_ERROR_KEYS, ReadoutControl, type ReadoutKind, type ReadoutOptions, type RealityCheckOptions, type Rect, type ResponsiveKey, type ResponsiveOverride, type RgsBetConfig, type RgsErrorCode, type RgsErrorOptions, type ScreenState, SelectControl, type SelectControlOptions, type SelectOption, Sequence, Signal, SliderControl, type SliderOptions, type SocialPhraseIssue, type SpecIssue, SpinControl, type SpinPress, type SpinSpec, Squish, type StageRect, type StateDef, type StateMap, StepperControl, type StepperOptions, type Subscribable, type Theme, type ThemeChoice, type ThemeIssue, type ThemeOverrides, type ThemePreset, ToggleControl, type ToggleOptions, type Transition, type Translator, TurboControl, type TurboOptions, type TurboSpec, Turn, type UISpec, ValueDisplay, type ValueDisplayOptions, type ViewInspect, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, checkSocialPhrases, clampBet, clampDecimals, clampDigits, clampMinDigits, collectSocialCopy, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, findForbiddenPhrases, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
|