@open-slot-ui/pixi 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/OpenUIPixi-D4Z7emFO.d.cts +202 -0
- package/dist/OpenUIPixi-D4Z7emFO.d.ts +202 -0
- package/dist/art.cjs +269 -0
- package/dist/art.cjs.map +1 -0
- package/dist/art.d.cts +125 -0
- package/dist/art.d.ts +125 -0
- package/dist/art.js +222 -0
- package/dist/art.js.map +1 -0
- package/dist/chunk-PYXZIGXG.js +3733 -0
- package/dist/chunk-PYXZIGXG.js.map +1 -0
- package/dist/index.cjs +146 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -185
- package/dist/index.d.ts +16 -185
- package/dist/index.js +16 -3621
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
package/dist/index.cjs
CHANGED
|
@@ -172,15 +172,14 @@ var SpinView = class extends ControlView {
|
|
|
172
172
|
this.holdDelayMs = opts.holdDelayMs ?? 260;
|
|
173
173
|
this.skin = skinFactory(ui.theme);
|
|
174
174
|
this.art.addChild(this.skin.view);
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
this.fsCount = new pixi_js.Text({ text: "0", style: { fontFamily: ui.theme.type.family, fontSize: 44, fill: c.text, fontWeight: "800" } });
|
|
175
|
+
const fsRing = new pixi_js.Graphics().circle(0, 0, 98).fill({ color: 16777215 }).circle(0, 0, 94).stroke({ width: 8, color: 657930 });
|
|
176
|
+
this.fsCount = new pixi_js.Text({ text: "0", style: { fontFamily: ui.theme.type.family, fontSize: 60, fill: 657930, fontWeight: "900" } });
|
|
178
177
|
this.fsCount.anchor.set(0.5);
|
|
179
|
-
this.fsCount.y = -
|
|
180
|
-
this.fsLabel = new pixi_js.Text({ text: ui.t("openui.freeSpins"), style: { fontFamily: ui.theme.type.family, fontSize:
|
|
178
|
+
this.fsCount.y = -14;
|
|
179
|
+
this.fsLabel = new pixi_js.Text({ text: ui.t("openui.freeSpins"), style: { fontFamily: ui.theme.type.family, fontSize: 24, fill: 657930, fontWeight: "900", letterSpacing: 3 } });
|
|
181
180
|
this.fsLabel.anchor.set(0.5);
|
|
182
|
-
this.fsLabel.y =
|
|
183
|
-
this.fsFace.addChild(
|
|
181
|
+
this.fsLabel.y = 34;
|
|
182
|
+
this.fsFace.addChild(fsRing, this.fsCount, this.fsLabel);
|
|
184
183
|
this.fsFace.visible = false;
|
|
185
184
|
this.art.addChild(this.fsFace);
|
|
186
185
|
const stopRing = new pixi_js.Graphics().circle(0, 0, 96).fill({ color: 16777215 }).stroke({ width: 7, color: 657930 });
|
|
@@ -1220,7 +1219,6 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1220
1219
|
}
|
|
1221
1220
|
build() {
|
|
1222
1221
|
const theme = this.ui.theme;
|
|
1223
|
-
const side = this.side();
|
|
1224
1222
|
if (this.vd.label) {
|
|
1225
1223
|
this.caption = new pixi_js.Text({
|
|
1226
1224
|
// Figma: the label is NOT uppercased — "Баланс" / "Ставка" as authored.
|
|
@@ -1228,19 +1226,32 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1228
1226
|
style: { fontFamily: theme.type.family, fontSize: 28, fill: 16777215, fontWeight: "900", letterSpacing: 0 }
|
|
1229
1227
|
});
|
|
1230
1228
|
this.caption.anchor.set(0.5, 0.5);
|
|
1231
|
-
|
|
1232
|
-
const padY = 8;
|
|
1233
|
-
const pillW = Math.ceil(this.caption.width) + padX * 2;
|
|
1234
|
-
const pillH = Math.ceil(this.caption.height) + padY * 2;
|
|
1235
|
-
const pillX = side === "left" ? 0 : side === "right" ? -pillW : -pillW / 2;
|
|
1236
|
-
const pillY = -DIGIT_H / 2 - pillH - 14;
|
|
1237
|
-
this.captionPill = new pixi_js.Graphics().roundRect(pillX, pillY, pillW, pillH, 12).fill({ color: 0 });
|
|
1238
|
-
this.caption.position.set(pillX + pillW / 2, pillY + pillH / 2);
|
|
1229
|
+
this.captionPill = new pixi_js.Graphics();
|
|
1239
1230
|
this.addChild(this.captionPill, this.caption);
|
|
1231
|
+
this.sizeCaptionPill();
|
|
1232
|
+
if (typeof document !== "undefined" && document.fonts?.ready) {
|
|
1233
|
+
void document.fonts.ready.then(() => {
|
|
1234
|
+
if (!this.destroyed && this.caption) this.sizeCaptionPill();
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1240
1237
|
}
|
|
1241
1238
|
const cur = this.vd.currency.get();
|
|
1242
1239
|
this.buildCounter(core.displayDigits(this.vd.get(), this.vd.digits, cur.decimals), this.vd.minorUnits);
|
|
1243
1240
|
}
|
|
1241
|
+
/** Size the caption pill to the caption's current measured width + padding and centre
|
|
1242
|
+
* the text in it, anchored to the value's side. Re-runnable (fonts-ready / relayout). */
|
|
1243
|
+
sizeCaptionPill() {
|
|
1244
|
+
if (!this.caption || !this.captionPill) return;
|
|
1245
|
+
const side = this.side();
|
|
1246
|
+
const padX = 24;
|
|
1247
|
+
const padY = 8;
|
|
1248
|
+
const pillW = Math.ceil(this.caption.width) + padX * 2;
|
|
1249
|
+
const pillH = Math.ceil(this.caption.height) + padY * 2;
|
|
1250
|
+
const pillX = side === "left" ? 0 : side === "right" ? -pillW : -pillW / 2;
|
|
1251
|
+
const pillY = -DIGIT_H / 2 - pillH - 14;
|
|
1252
|
+
this.captionPill.clear().roundRect(pillX, pillY, pillW, pillH, 12).fill({ color: 0 });
|
|
1253
|
+
this.caption.position.set(pillX + pillW / 2, pillY + pillH / 2);
|
|
1254
|
+
}
|
|
1244
1255
|
/** (Re)create the rolling counter sized to `total` columns, starting at `fromMinor`. */
|
|
1245
1256
|
buildCounter(total, fromMinor) {
|
|
1246
1257
|
this.counter?.destroy();
|
|
@@ -1282,7 +1293,7 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1282
1293
|
const symbolMode = cur.display === "symbol" && !!cur.symbol;
|
|
1283
1294
|
const affix = symbolMode ? cur.symbol : cur.code;
|
|
1284
1295
|
if ((cur.position ?? "suffix") === "prefix") opts.prefix = symbolMode ? affix : `${affix} `;
|
|
1285
|
-
else opts.suffix =
|
|
1296
|
+
else opts.suffix = ` ${affix}`;
|
|
1286
1297
|
if (this.fitGsap) {
|
|
1287
1298
|
opts.fit = {
|
|
1288
1299
|
gsap: this.fitGsap,
|
|
@@ -1297,7 +1308,13 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1297
1308
|
if (this.fitGsap) {
|
|
1298
1309
|
this.counter.x = 0;
|
|
1299
1310
|
} else {
|
|
1300
|
-
|
|
1311
|
+
const budget = core.valueFitMaxWidth(Math.max(this.vd.digits, FIT_BUDGET_COLS), DIGIT_W);
|
|
1312
|
+
const natural = this.counter.width;
|
|
1313
|
+
const k = natural > budget ? Math.max(0.5, budget / natural) : 1;
|
|
1314
|
+
this.counter.scale.set(k);
|
|
1315
|
+
this.counter.y = -DIGIT_H * k / 2;
|
|
1316
|
+
const w = natural * k;
|
|
1317
|
+
this.counter.x = side === "left" ? 0 : side === "right" ? -w : -w / 2;
|
|
1301
1318
|
}
|
|
1302
1319
|
this.addChild(this.counter);
|
|
1303
1320
|
}
|
|
@@ -2390,6 +2407,16 @@ function buildBlockColumn(blocks, controls, ui, ticker, bodyW, opts = {}) {
|
|
|
2390
2407
|
wrap.addChild(txt);
|
|
2391
2408
|
return wrap;
|
|
2392
2409
|
};
|
|
2410
|
+
const hintNode = (s) => {
|
|
2411
|
+
const wrap = new pixi_js.Container();
|
|
2412
|
+
const txt = new pixi_js.Text({
|
|
2413
|
+
text: s,
|
|
2414
|
+
style: { fontFamily: t.type.family, fontSize: 12.5, fill: t.color.textDim, align: "center", wordWrap: true, wordWrapWidth: innerW * 0.86, lineHeight: 17 }
|
|
2415
|
+
});
|
|
2416
|
+
txt.anchor.set(0.5);
|
|
2417
|
+
wrap.addChild(txt);
|
|
2418
|
+
return wrap;
|
|
2419
|
+
};
|
|
2393
2420
|
const makeView = (b, control) => {
|
|
2394
2421
|
const skin = opts.controlSkins?.[b.id];
|
|
2395
2422
|
if (skin) return skin(control, ui, ticker);
|
|
@@ -2475,6 +2502,8 @@ function buildBlockColumn(blocks, controls, ui, ticker, bodyW, opts = {}) {
|
|
|
2475
2502
|
if (b.kind === "slider") view.position.set(-130, -27);
|
|
2476
2503
|
wrap.addChild(view);
|
|
2477
2504
|
placeFixed(wrap, ROW_H);
|
|
2505
|
+
const hint = b.hint;
|
|
2506
|
+
if (hint) placeAuto(hintNode(tr(hint)), 12);
|
|
2478
2507
|
}
|
|
2479
2508
|
}
|
|
2480
2509
|
}
|
|
@@ -2985,6 +3014,8 @@ var ReadoutView = class extends ControlView {
|
|
|
2985
3014
|
const inline = opts.inline ?? false;
|
|
2986
3015
|
this.prefix = opts.prefix ?? false;
|
|
2987
3016
|
const fill = opts.fill ?? (opts.mono ? "#ffffff" : t.color.text);
|
|
3017
|
+
this.baseFill = this.prefix ? opts.fill ?? "#ffffff" : fill;
|
|
3018
|
+
this.accentFill = t.color.accent;
|
|
2988
3019
|
if (this.prefix) {
|
|
2989
3020
|
this.valueText = new pixi_js.Text({
|
|
2990
3021
|
text: "",
|
|
@@ -3003,13 +3034,15 @@ var ReadoutView = class extends ControlView {
|
|
|
3003
3034
|
this.ro.value.subscribe(() => this.render()),
|
|
3004
3035
|
this.ui.locale.subscribe(() => {
|
|
3005
3036
|
if (!this.destroyed) this.render();
|
|
3006
|
-
})
|
|
3037
|
+
}),
|
|
3038
|
+
this.ro.emphasized.subscribe(() => this.applyEmphasis())
|
|
3007
3039
|
);
|
|
3008
3040
|
if (this.ro.currency) this.disposers.push(this.ro.currency.subscribe(() => this.render()));
|
|
3009
3041
|
if (this.ro.kind === "duration") {
|
|
3010
3042
|
this.tick = (tk) => this.ro.tick(tk.deltaMS / 1e3);
|
|
3011
3043
|
this.ticker.add(this.tick);
|
|
3012
3044
|
}
|
|
3045
|
+
this.applyEmphasis();
|
|
3013
3046
|
this.render();
|
|
3014
3047
|
return;
|
|
3015
3048
|
}
|
|
@@ -3044,10 +3077,12 @@ var ReadoutView = class extends ControlView {
|
|
|
3044
3077
|
})
|
|
3045
3078
|
);
|
|
3046
3079
|
if (this.ro.currency) this.disposers.push(this.ro.currency.subscribe(() => this.render()));
|
|
3080
|
+
this.disposers.push(this.ro.emphasized.subscribe(() => this.applyEmphasis()));
|
|
3047
3081
|
if (this.ro.kind === "duration") {
|
|
3048
3082
|
this.tick = (tk) => this.ro.tick(tk.deltaMS / 1e3);
|
|
3049
3083
|
this.ticker.add(this.tick);
|
|
3050
3084
|
}
|
|
3085
|
+
this.applyEmphasis();
|
|
3051
3086
|
this.render();
|
|
3052
3087
|
}
|
|
3053
3088
|
ro;
|
|
@@ -3056,6 +3091,14 @@ var ReadoutView = class extends ControlView {
|
|
|
3056
3091
|
valueText;
|
|
3057
3092
|
tick;
|
|
3058
3093
|
prefix;
|
|
3094
|
+
/** Normal + accent value colours for the `emphasized` (modified) tint. */
|
|
3095
|
+
baseFill;
|
|
3096
|
+
accentFill;
|
|
3097
|
+
/** Tint the value in the theme accent while the readout is emphasized (modified). */
|
|
3098
|
+
applyEmphasis() {
|
|
3099
|
+
if (this.destroyed) return;
|
|
3100
|
+
this.valueText.style.fill = this.ro.emphasized.get() ? this.accentFill : this.baseFill;
|
|
3101
|
+
}
|
|
3059
3102
|
render() {
|
|
3060
3103
|
const v = this.ro.value.get();
|
|
3061
3104
|
let text;
|
|
@@ -3291,6 +3334,10 @@ var OpenUIPixi = class {
|
|
|
3291
3334
|
slideTickFn;
|
|
3292
3335
|
slideBaseY = /* @__PURE__ */ new Map();
|
|
3293
3336
|
slideSign = /* @__PURE__ */ new Map();
|
|
3337
|
+
/** Buy-feature ⇄ total-win swap: only one shows at a time (see `setupBonusSwap`). */
|
|
3338
|
+
bonusView;
|
|
3339
|
+
totalWinView;
|
|
3340
|
+
fadeFns = /* @__PURE__ */ new Map();
|
|
3294
3341
|
/** The bus event log backing `window.__OPENUI__.events` (available after mount). */
|
|
3295
3342
|
get eventLog() {
|
|
3296
3343
|
return this._eventLog;
|
|
@@ -3338,6 +3385,9 @@ var OpenUIPixi = class {
|
|
|
3338
3385
|
const bonusView = new ButtonView(this.ui.bonusButton, this.ui, ticker, { shape: "circle", radius: 60, iconTexture: ic.bonus, iconTarget: 130 });
|
|
3339
3386
|
const betPlusView = new ButtonView(this.ui.betPlus, this.ui, ticker, { shape: "circle", radius: 30, iconTexture: ic.betPlus, iconTarget: 64 });
|
|
3340
3387
|
const betMinusView = new ButtonView(this.ui.betMinus, this.ui, ticker, { shape: "circle", radius: 30, iconTexture: ic.betMinus, iconTarget: 64 });
|
|
3388
|
+
const totalWinView = new ValueDisplayView(this.ui.totalWin, this.ui, ticker, this.opts.gsap);
|
|
3389
|
+
this.bonusView = bonusView;
|
|
3390
|
+
this.totalWinView = totalWinView;
|
|
3341
3391
|
const muteView = new ButtonView(this.ui.muteButton, this.ui, ticker, { shape: "circle", radius: 30, glyph: "speaker", iconTarget: 60, mono: true });
|
|
3342
3392
|
const fullscreenView = new ButtonView(this.ui.fullscreenButton, this.ui, ticker, { shape: "circle", radius: 30, glyph: "fullscreen", iconTarget: 60, mono: true });
|
|
3343
3393
|
muteView.zIndex = 65;
|
|
@@ -3354,6 +3404,7 @@ var OpenUIPixi = class {
|
|
|
3354
3404
|
[this.ui.turbo.id, turboView],
|
|
3355
3405
|
[this.ui.autoplay.id, autoplayView],
|
|
3356
3406
|
[this.ui.bonusButton.id, bonusView],
|
|
3407
|
+
[this.ui.totalWin.id, totalWinView],
|
|
3357
3408
|
[this.ui.betPlus.id, betPlusView],
|
|
3358
3409
|
[this.ui.betMinus.id, betMinusView],
|
|
3359
3410
|
[this.ui.muteButton.id, muteView],
|
|
@@ -3482,9 +3533,81 @@ var OpenUIPixi = class {
|
|
|
3482
3533
|
if (intro === "slide-in") this.setControlsVisible(true);
|
|
3483
3534
|
}
|
|
3484
3535
|
this.disposers.push(() => renderer.off("resize", onResize), unsubScreen);
|
|
3536
|
+
this.setupBonusSwap();
|
|
3485
3537
|
this._eventLog = new core.EventLog(this.ui.bus);
|
|
3486
3538
|
if (this.opts.expose ?? true) this.expose();
|
|
3487
3539
|
}
|
|
3540
|
+
/**
|
|
3541
|
+
* Wire the buy-feature ⇄ total-win swap. In base play the buy button shows (unless
|
|
3542
|
+
* hidden by config/jurisdiction); once the spin button enters free-spins mode
|
|
3543
|
+
* (`setFreeSpins(n > 0)` — you "can't buy" mid-bonus) the buy button fades out and
|
|
3544
|
+
* the localized total-win counter fades in over the same slot, then back on exit.
|
|
3545
|
+
*/
|
|
3546
|
+
setupBonusSwap() {
|
|
3547
|
+
const bonus = this.bonusView;
|
|
3548
|
+
const tw = this.totalWinView;
|
|
3549
|
+
if (!bonus || !tw) return;
|
|
3550
|
+
const apply = (inBonus, animate) => {
|
|
3551
|
+
const bonusShouldShow = !inBonus && !this.ui.hidden.has(this.ui.bonusButton.id);
|
|
3552
|
+
if (animate) {
|
|
3553
|
+
if (inBonus) {
|
|
3554
|
+
tw.visible = true;
|
|
3555
|
+
tw.alpha = 0;
|
|
3556
|
+
this.fadeTo(tw, 1, 220);
|
|
3557
|
+
this.fadeTo(bonus, 0, 160, () => bonus.visible = false);
|
|
3558
|
+
} else {
|
|
3559
|
+
if (bonusShouldShow) {
|
|
3560
|
+
bonus.visible = true;
|
|
3561
|
+
bonus.alpha = 0;
|
|
3562
|
+
this.fadeTo(bonus, this.ui.bonusButton.interactable ? 1 : 0.4, 220);
|
|
3563
|
+
}
|
|
3564
|
+
this.fadeTo(tw, 0, 160, () => tw.visible = false);
|
|
3565
|
+
}
|
|
3566
|
+
} else {
|
|
3567
|
+
this.stopFade(bonus);
|
|
3568
|
+
this.stopFade(tw);
|
|
3569
|
+
bonus.visible = bonusShouldShow;
|
|
3570
|
+
bonus.alpha = this.ui.bonusButton.interactable ? 1 : 0.4;
|
|
3571
|
+
tw.visible = inBonus;
|
|
3572
|
+
tw.alpha = inBonus ? 1 : 0;
|
|
3573
|
+
}
|
|
3574
|
+
};
|
|
3575
|
+
apply(this.ui.spin.freeSpins.get() > 0, false);
|
|
3576
|
+
this.disposers.push(this.ui.spin.freeSpins.subscribe((n) => apply(n > 0, true)));
|
|
3577
|
+
}
|
|
3578
|
+
/** Fade a view's alpha to `to` over `ms` (wall-clock paced); cancels any prior fade
|
|
3579
|
+
* on the same view. `onDone` runs once when it settles. */
|
|
3580
|
+
fadeTo(view, to, ms, onDone) {
|
|
3581
|
+
this.stopFade(view);
|
|
3582
|
+
const t = this.appTicker;
|
|
3583
|
+
const from = view.alpha;
|
|
3584
|
+
if (!t || from === to) {
|
|
3585
|
+
view.alpha = to;
|
|
3586
|
+
onDone?.();
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
const startMs = typeof performance !== "undefined" ? performance.now() : 0;
|
|
3590
|
+
const fn = () => {
|
|
3591
|
+
const nowMs = typeof performance !== "undefined" ? performance.now() : startMs + ms;
|
|
3592
|
+
const k = Math.min(1, (nowMs - startMs) / Math.max(ms, 1));
|
|
3593
|
+
view.alpha = from + (to - from) * k;
|
|
3594
|
+
if (k >= 1) {
|
|
3595
|
+
view.alpha = to;
|
|
3596
|
+
this.stopFade(view);
|
|
3597
|
+
onDone?.();
|
|
3598
|
+
}
|
|
3599
|
+
};
|
|
3600
|
+
this.fadeFns.set(view, fn);
|
|
3601
|
+
t.add(fn);
|
|
3602
|
+
}
|
|
3603
|
+
/** Cancel an in-flight fade on `view` (if any). */
|
|
3604
|
+
stopFade(view) {
|
|
3605
|
+
const fn = this.fadeFns.get(view);
|
|
3606
|
+
if (fn) {
|
|
3607
|
+
this.appTicker?.remove(fn);
|
|
3608
|
+
this.fadeFns.delete(view);
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3488
3611
|
/**
|
|
3489
3612
|
* Build the unified scrollable MENU bound to the ☰ panel. Composed `menu` blocks
|
|
3490
3613
|
* are given by `mountHud`; absent → a default Settings-only menu. Built-in ids
|
|
@@ -3559,6 +3682,8 @@ var OpenUIPixi = class {
|
|
|
3559
3682
|
unmount() {
|
|
3560
3683
|
if (this.slideTickFn && this.appTicker) this.appTicker.remove(this.slideTickFn);
|
|
3561
3684
|
this.slideTickFn = void 0;
|
|
3685
|
+
for (const fn of this.fadeFns.values()) this.appTicker?.remove(fn);
|
|
3686
|
+
this.fadeFns.clear();
|
|
3562
3687
|
for (const v of this.views) v.dispose();
|
|
3563
3688
|
this.views.length = 0;
|
|
3564
3689
|
for (const o of this.overlays) o.dispose();
|
|
@@ -3904,9 +4029,11 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
3904
4029
|
on,
|
|
3905
4030
|
setBalance: (n) => ui.balance.set(n),
|
|
3906
4031
|
setBet: (n) => ui.bet.set(n),
|
|
4032
|
+
setTotalWin: (n) => ui.totalWin.set(n),
|
|
3907
4033
|
setCurrency: (c) => {
|
|
3908
4034
|
ui.balance.setCurrency(c);
|
|
3909
4035
|
ui.bet.setCurrency(c);
|
|
4036
|
+
ui.totalWin.setCurrency(c);
|
|
3910
4037
|
ui.netPosition.setCurrency(c);
|
|
3911
4038
|
},
|
|
3912
4039
|
applyJurisdiction: (j) => ui.applyJurisdiction(j),
|