packing-bingo 0.2.0 → 0.4.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.
- package/README.md +180 -103
- package/dist/{chunk-WGZKPODU.js → chunk-BAA2CFUA.js} +352 -137
- package/dist/core.cjs +353 -137
- package/dist/core.d.cts +82 -13
- package/dist/core.d.ts +82 -13
- package/dist/core.js +3 -1
- package/dist/index.cjs +360 -139
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +10 -3
- package/dist/packing-bingo.global.js +43 -33
- package/package.json +2 -2
package/dist/core.cjs
CHANGED
|
@@ -23,6 +23,7 @@ var core_exports = {};
|
|
|
23
23
|
__export(core_exports, {
|
|
24
24
|
DEFAULT_ITEMS: () => DEFAULT_ITEMS,
|
|
25
25
|
LINES: () => LINES,
|
|
26
|
+
bingoLines: () => bingoLines,
|
|
26
27
|
createPackingBingo: () => createPackingBingo,
|
|
27
28
|
en: () => en,
|
|
28
29
|
ja: () => ja
|
|
@@ -31,38 +32,109 @@ module.exports = __toCommonJS(core_exports);
|
|
|
31
32
|
|
|
32
33
|
// src/items.ts
|
|
33
34
|
var DEFAULT_ITEMS = [
|
|
34
|
-
{ emoji: "\u{
|
|
35
|
-
{ emoji: "\u{
|
|
36
|
-
{ emoji: "\u{
|
|
37
|
-
{ emoji: "\u{
|
|
38
|
-
{ emoji: "\u{
|
|
39
|
-
{ emoji: "\u{
|
|
40
|
-
{ emoji: "\u{1F9E5}", label: "\u4E0A\u7740" },
|
|
41
|
-
{ emoji: "\u{1FAA5}", label: "\u6D17\u9762\u7528\u5177" },
|
|
42
|
-
{ emoji: "\u{1F6C1}", label: "\u30BF\u30AA\u30EB" },
|
|
43
|
-
{ emoji: "\u{1F927}", label: "\u30CF\u30F3\u30AB\u30C1\u30FB\u30C6\u30A3\u30C3\u30B7\u30E5" },
|
|
35
|
+
{ emoji: "\u{1F45B}", label: "\u8CA1\u5E03" },
|
|
36
|
+
{ emoji: "\u{1F4F1}", label: "\u30B9\u30DE\u30DB" },
|
|
37
|
+
{ emoji: "\u{1F50B}", label: "\u30E2\u30D0\u30A4\u30EB\u200B\u5145\u96FB\u5668" },
|
|
38
|
+
{ emoji: "\u{1F4CB}", label: "\u5065\u5EB7\u8ABF\u67FB\u7968" },
|
|
39
|
+
{ emoji: "\u{1FAAA}", label: "\u30DE\u30A4\u30CA\u30AB\u30FC\u30C9\u200B\u307E\u305F\u306F\u4FDD\u967A\u8A3C" },
|
|
40
|
+
{ emoji: "\u{1F4D6}", label: "\u3057\u304A\u308A" },
|
|
44
41
|
{ emoji: "\u{1F637}", label: "\u30DE\u30B9\u30AF" },
|
|
45
|
-
{ emoji: "\u{
|
|
46
|
-
{ emoji: "\
|
|
47
|
-
{ emoji: "\u270F\uFE0F", label: "\u7B46\u8A18\u7528\u5177" },
|
|
42
|
+
{ emoji: "\u{1F927}", label: "\u30CF\u30F3\u30AB\u30C1" },
|
|
43
|
+
{ emoji: "\u{1F48A}", label: "\u5E38\u5099\u85AC" },
|
|
48
44
|
{ emoji: "\u{1F6CD}\uFE0F", label: "\u30D3\u30CB\u30FC\u30EB\u888B" },
|
|
49
|
-
{ emoji: "\u{
|
|
45
|
+
{ emoji: "\u{1F9E4}", label: "\u8ECD\u624B\uFF08\u5B66\u6821\u652F\u7D66\uFF09" },
|
|
46
|
+
{ emoji: "\u{1F526}", label: "\u30D8\u30C3\u30C9\u30E9\u30A4\u30C8" },
|
|
47
|
+
{ emoji: "\u{1F455}", label: "\u30B8\u30E3\u30FC\u30B8" },
|
|
48
|
+
{ emoji: "\u2614", label: "\u96E8\u5177" },
|
|
49
|
+
{ emoji: "\u{1F6C1}", label: "\u30BF\u30AA\u30EB" },
|
|
50
|
+
{ emoji: "\u{1F9F4}", label: "\u65E5\u713C\u3051\u6B62\u3081" }
|
|
50
51
|
];
|
|
51
52
|
|
|
53
|
+
// src/layout.ts
|
|
54
|
+
var MIN_SIZE = 2;
|
|
55
|
+
var MAX_SIZE = 10;
|
|
56
|
+
var fail = (msg) => {
|
|
57
|
+
throw new Error(`[packing-bingo] ${msg}`);
|
|
58
|
+
};
|
|
59
|
+
function layoutItems(options) {
|
|
60
|
+
if (options.items) return options.items;
|
|
61
|
+
const n = options.size;
|
|
62
|
+
if (n == null || !Number.isInteger(n) || n < MIN_SIZE) return DEFAULT_ITEMS;
|
|
63
|
+
return DEFAULT_ITEMS.slice(0, n * n - (options.free ? 1 : 0));
|
|
64
|
+
}
|
|
65
|
+
function checkSize(size, free) {
|
|
66
|
+
if (!Number.isInteger(size) || size < MIN_SIZE || size > MAX_SIZE)
|
|
67
|
+
fail(`"size" must be a whole number from ${MIN_SIZE} to ${MAX_SIZE} (got ${size}).`);
|
|
68
|
+
if (free && size % 2 === 0) fail(`"free" needs an odd size such as 3 or 5, so that the card has a center (got ${size}).`);
|
|
69
|
+
}
|
|
70
|
+
function shape(n, free) {
|
|
71
|
+
const seq = (f) => Array.from({ length: n }, (_, k) => f(k));
|
|
72
|
+
const cellLines = [
|
|
73
|
+
...seq((r) => seq((c) => r * n + c)),
|
|
74
|
+
// rows
|
|
75
|
+
...seq((c) => seq((r) => r * n + c)),
|
|
76
|
+
// columns
|
|
77
|
+
seq((k) => k * (n + 1)),
|
|
78
|
+
// top left to bottom right
|
|
79
|
+
seq((k) => (k + 1) * (n - 1))
|
|
80
|
+
// top right to bottom left
|
|
81
|
+
];
|
|
82
|
+
const center = free ? (n * n - 1) / 2 : -1;
|
|
83
|
+
const toItem = (c) => free && c > center ? c - 1 : c;
|
|
84
|
+
return { center, cellLines, lines: cellLines.map((l) => l.filter((c) => c !== center).map(toItem)) };
|
|
85
|
+
}
|
|
86
|
+
function resolveLayout(options) {
|
|
87
|
+
const items = layoutItems(options);
|
|
88
|
+
const free = !!options.free;
|
|
89
|
+
let size = options.size;
|
|
90
|
+
if (size == null) {
|
|
91
|
+
const len = items.length;
|
|
92
|
+
const sideOf = (cells) => {
|
|
93
|
+
const r = Math.round(Math.sqrt(cells));
|
|
94
|
+
return r * r === cells && r >= MIN_SIZE && r <= MAX_SIZE ? r : 0;
|
|
95
|
+
};
|
|
96
|
+
size = sideOf(len + (free ? 1 : 0));
|
|
97
|
+
if (!size) {
|
|
98
|
+
const other = sideOf(len + (free ? 0 : 1));
|
|
99
|
+
const hint = free ? other ? `; ${len} items fill a ${other}\xD7${other} card without "free"` : "" : other % 2 ? `, or set "free" for a ${other}\xD7${other} card with a FREE center` : "";
|
|
100
|
+
fail(
|
|
101
|
+
free ? `With "free", "items" must have one less than an odd square number of entries (8, 24, 48, 80)${hint} (got ${len}).` : `"items" must have a square number of entries (4, 9, 16, 25, \u2026, 100)${hint} (got ${len}).`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
checkSize(size, free);
|
|
106
|
+
const want = size * size - (free ? 1 : 0);
|
|
107
|
+
if (items.length !== want) {
|
|
108
|
+
const card = `a ${size}\xD7${size} card${free ? " with a FREE center" : ""}`;
|
|
109
|
+
fail(
|
|
110
|
+
options.items ? `"items" must have exactly ${want} entries for ${card} (got ${items.length}).` : `A ${card.slice(2)} needs ${want} items, but DEFAULT_ITEMS has only ${DEFAULT_ITEMS.length}. Pass "items".`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const { center, cellLines, lines } = shape(size, free);
|
|
114
|
+
const itemCell = items.map((_, i) => free && i >= center ? i + 1 : i);
|
|
115
|
+
return { size, free, items, itemCell, center, cellLines, lines };
|
|
116
|
+
}
|
|
117
|
+
function bingoLines(size, free = false) {
|
|
118
|
+
checkSize(size, free);
|
|
119
|
+
return shape(size, free).lines;
|
|
120
|
+
}
|
|
121
|
+
|
|
52
122
|
// src/messages.ts
|
|
53
123
|
var ja = {
|
|
54
124
|
title: "\u6301\u3061\u3082\u306E\u30D3\u30F3\u30B4",
|
|
55
|
-
tag: "
|
|
56
|
-
subtitle: "
|
|
125
|
+
tag: "",
|
|
126
|
+
subtitle: "",
|
|
57
127
|
packed: "\u305D\u308D\u3063\u305F",
|
|
58
128
|
bingo: "BINGO",
|
|
59
129
|
score: "SCORE",
|
|
60
130
|
combo: (n) => `${n} COMBO`,
|
|
61
131
|
comboPop: (n) => `${n} COMBO!`,
|
|
62
132
|
reset: "\u30EA\u30BB\u30C3\u30C8",
|
|
133
|
+
shuffle: "\u{1F500} \u30B7\u30E3\u30C3\u30D5\u30EB",
|
|
63
134
|
soundOn: "\u{1F50A} \u97F3\u3042\u308A",
|
|
64
135
|
soundOff: "\u{1F507} \u97F3\u306A\u3057",
|
|
65
136
|
stamp: "OK",
|
|
137
|
+
free: "FREE",
|
|
66
138
|
reachBadge: "\u30EA\u30FC\u30C1",
|
|
67
139
|
reachPop: "\u30EA\u30FC\u30C1!",
|
|
68
140
|
bannerSingle: "BINGO!",
|
|
@@ -70,14 +142,15 @@ var ja = {
|
|
|
70
142
|
bannerTriple: "\u30C8\u30EA\u30D7\u30EB\u30D3\u30F3\u30B4!",
|
|
71
143
|
bannerNth: (n) => `${n} \u30E9\u30A4\u30F3\u76EE\uFF01`,
|
|
72
144
|
bannerMulti: (n) => `\u4E00\u6C17\u306B ${n} \u30E9\u30A4\u30F3\uFF01`,
|
|
73
|
-
statusStart: (
|
|
145
|
+
statusStart: () => "",
|
|
74
146
|
statusLines: (lines, left) => `\u30D3\u30F3\u30B4 ${lines} \u30E9\u30A4\u30F3\uFF01 \u306E\u3053\u308A ${left} \u3053`,
|
|
75
|
-
statusReach: (
|
|
147
|
+
statusReach: () => "",
|
|
76
148
|
statusDone: "\u{1F389} \u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01\u5FD8\u308C\u7269\u30BC\u30ED\u3067\u51FA\u767A\u3067\u304D\u307E\u3059",
|
|
77
149
|
perfectTag: "\u{1F3C6} PERFECT",
|
|
78
150
|
perfectStamp: "\u6E96\u5099\n\u5B8C\u4E86",
|
|
79
151
|
perfectTitle: "\u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01",
|
|
80
|
-
perfectBody:
|
|
152
|
+
perfectBody: (n) => `${n}\u3053 \u305C\u3093\u3076\u305D\u308D\u3063\u305F\uFF01
|
|
153
|
+
\u5FD8\u308C\u7269\u30BC\u30ED\u3067\u3001\u3044\u3063\u3066\u3089\u3063\u3057\u3083\u3044\uFF01`,
|
|
81
154
|
perfectBonus: (n) => `PERFECT BONUS +${n}`,
|
|
82
155
|
statScore: "SCORE",
|
|
83
156
|
statCombo: "MAX COMBO",
|
|
@@ -90,17 +163,19 @@ var ja = {
|
|
|
90
163
|
};
|
|
91
164
|
var en = {
|
|
92
165
|
title: "Packing Bingo",
|
|
93
|
-
tag: "
|
|
94
|
-
subtitle: "
|
|
166
|
+
tag: "",
|
|
167
|
+
subtitle: "",
|
|
95
168
|
packed: "PACKED",
|
|
96
169
|
bingo: "BINGO",
|
|
97
170
|
score: "SCORE",
|
|
98
171
|
combo: (n) => `${n} COMBO`,
|
|
99
172
|
comboPop: (n) => `${n} COMBO!`,
|
|
100
173
|
reset: "Reset",
|
|
174
|
+
shuffle: "\u{1F500} Shuffle",
|
|
101
175
|
soundOn: "\u{1F50A} Sound on",
|
|
102
176
|
soundOff: "\u{1F507} Muted",
|
|
103
177
|
stamp: "OK",
|
|
178
|
+
free: "FREE",
|
|
104
179
|
reachBadge: "REACH",
|
|
105
180
|
reachPop: "Reach!",
|
|
106
181
|
bannerSingle: "BINGO!",
|
|
@@ -108,14 +183,15 @@ var en = {
|
|
|
108
183
|
bannerTriple: "TRIPLE BINGO!",
|
|
109
184
|
bannerNth: (n) => `Line ${n}!`,
|
|
110
185
|
bannerMulti: (n) => `${n} lines at once!`,
|
|
111
|
-
statusStart: (
|
|
186
|
+
statusStart: () => "",
|
|
112
187
|
statusLines: (lines, left) => `${lines} bingo line${lines === 1 ? "" : "s"}! ${left} to go`,
|
|
113
|
-
statusReach: (
|
|
188
|
+
statusReach: () => "",
|
|
114
189
|
statusDone: "\u{1F389} Perfect! Nothing left behind.",
|
|
115
190
|
perfectTag: "\u{1F3C6} PERFECT",
|
|
116
191
|
perfectStamp: "ALL\nSET",
|
|
117
192
|
perfectTitle: "Perfect!",
|
|
118
|
-
perfectBody:
|
|
193
|
+
perfectBody: (n) => `All ${n} packed!
|
|
194
|
+
Have a great trip!`,
|
|
119
195
|
perfectBonus: (n) => `PERFECT BONUS +${n}`,
|
|
120
196
|
statScore: "SCORE",
|
|
121
197
|
statCombo: "MAX COMBO",
|
|
@@ -215,6 +291,11 @@ function createSound(isMuted) {
|
|
|
215
291
|
},
|
|
216
292
|
tick: () => tone(1760, 0, 0.03, "square", 0.03),
|
|
217
293
|
note: (k, at = 0) => tone(step(k), at, 0.12, "square", 0.05),
|
|
294
|
+
shuffle() {
|
|
295
|
+
for (let i = 0; i < 7; i++) noise(i * 0.042, 0.05, 0.16, 1600 + i * 260);
|
|
296
|
+
tone(hz(7), 0.34, 0.12, "triangle", 0.14);
|
|
297
|
+
tone(hz(12), 0.42, 0.2, "triangle", 0.14);
|
|
298
|
+
},
|
|
218
299
|
close() {
|
|
219
300
|
if (ac) void ac.close().catch(() => {
|
|
220
301
|
});
|
|
@@ -229,7 +310,7 @@ function resolveStorageKey(options) {
|
|
|
229
310
|
if (options.controlled) return null;
|
|
230
311
|
if (options.storageKey !== void 0) return options.storageKey || null;
|
|
231
312
|
if (options.demo) return null;
|
|
232
|
-
return itemsKey(options
|
|
313
|
+
return itemsKey(layoutItems(options));
|
|
233
314
|
}
|
|
234
315
|
function itemsKey(items) {
|
|
235
316
|
const text = items.map((it) => `${it.emoji}\0${it.label}`).join("");
|
|
@@ -242,24 +323,24 @@ function itemsKey(items) {
|
|
|
242
323
|
}
|
|
243
324
|
|
|
244
325
|
// src/styles.ts
|
|
245
|
-
var FONT_URL = "https://fonts.googleapis.com/css2?family=Dela+Gothic+One&family=M+PLUS+Rounded+1c:wght@500;800&display=swap";
|
|
246
326
|
var CSS = `
|
|
247
|
-
.pkb{--pk-sun:var(--pkb-sun,#FFD54F);--pk-ink:var(--pkb-ink,#2A1F14);--pk-paper:var(--pkb-paper,#FFFDF6);--pk-red:var(--pkb-red,#E8473B);--pk-mint:var(--pkb-mint,#BDEBD2);--pk-display:"Dela Gothic One",var(--pkb-font-fallback,sans-serif);--pk-body:"M PLUS Rounded 1c","Hiragino Maru Gothic ProN",var(--pkb-font-fallback,sans-serif);container-type:inline-size;isolation:isolate;width:100%}
|
|
327
|
+
.pkb{--pk-sun:var(--pkb-sun,#FFD54F);--pk-ink:var(--pkb-ink,#2A1F14);--pk-paper:var(--pkb-paper,#FFFDF6);--pk-red:var(--pkb-red,#E8473B);--pk-mint:var(--pkb-mint,#BDEBD2);--pk-display:"Dela Gothic One",var(--pkb-font-fallback,sans-serif);--pk-body:"M PLUS Rounded 1c","Hiragino Maru Gothic ProN",var(--pkb-font-fallback,sans-serif);--pk-n:4;--pk-s:1;--pk-d:1;container-type:inline-size;isolation:isolate;width:100%}
|
|
248
328
|
.pkb,.pkb *{box-sizing:border-box;margin:0;padding:0}
|
|
249
329
|
.pkb-board{position:relative;overflow:hidden;max-width:720px;margin:0 auto;padding:22px 26px 20px;border-radius:24px;background-color:var(--pk-sun);background-image:radial-gradient(rgba(42,31,20,.12) 1.3px,transparent 1.6px);background-size:16px 16px;border:2.5px solid var(--pk-ink);color:var(--pk-ink);font-family:var(--pk-body);line-height:1.4;text-align:left}
|
|
250
330
|
.pkb-board.pkb-shake{animation:pkb-shake .45s cubic-bezier(.36,.07,.19,.97)}
|
|
251
331
|
@keyframes pkb-shake{10%,90%{transform:translate(-1px,1px)}20%,80%{transform:translate(3px,-2px)}30%,50%,70%{transform:translate(-6px,2px)}40%,60%{transform:translate(6px,-1px)}}
|
|
252
332
|
.pkb-board.pkb-punch{animation:pkb-punch .4s cubic-bezier(.3,1.6,.5,1)}
|
|
253
333
|
@keyframes pkb-punch{30%{transform:scale(1.018)}}
|
|
254
|
-
.pkb-head{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:18px}
|
|
334
|
+
.pkb-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px 16px;margin-bottom:18px}
|
|
255
335
|
.pkb-tags{display:flex;gap:8px;align-items:center}
|
|
256
336
|
.pkb-kicker{display:inline-block;background:var(--pk-ink);color:var(--pk-sun);font-weight:800;font-size:11px;letter-spacing:.14em;padding:4px 10px;border-radius:999px}
|
|
337
|
+
.pkb-kicker:empty{display:none}
|
|
257
338
|
.pkb-kicker.pkb-gold{color:#fff;background:linear-gradient(90deg,#E8473B,#FF9F1C,#1FA971,#2F6FED,#E8473B);background-size:200% 100%;animation:pkb-rb 2s linear infinite}
|
|
258
339
|
@keyframes pkb-rb{to{background-position:-200% 0}}
|
|
259
340
|
.pkb button{font-family:var(--pk-body)}
|
|
260
341
|
.pkb-snd{appearance:none;border:2px solid var(--pk-ink);background:var(--pk-paper);border-radius:999px;padding:2px 9px;font-weight:800;font-size:11px;line-height:1.4;color:var(--pk-ink);cursor:pointer}
|
|
261
342
|
.pkb-title{font-family:var(--pk-display);font-weight:400;font-size:34px;line-height:1.15;margin-top:8px;letter-spacing:.02em;color:inherit}
|
|
262
|
-
.pkb-sub{font-weight:800;font-size:13px;margin-top:4px}
|
|
343
|
+
.pkb-sub{font-weight:800;font-size:13px;margin-top:4px;word-break:auto-phrase}
|
|
263
344
|
.pkb-side{display:flex;flex-direction:column;gap:8px;flex:none}
|
|
264
345
|
.pkb-score{display:flex;gap:10px}
|
|
265
346
|
.pkb-pill{min-width:78px;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:14px;padding:6px 10px 5px;text-align:center;box-shadow:3px 3px 0 var(--pk-ink)}
|
|
@@ -278,16 +359,18 @@ var CSS = `
|
|
|
278
359
|
.pkb-combo.pkb-on .pkb-bar i{animation:pkb-drain 2.5s linear forwards}
|
|
279
360
|
@keyframes pkb-drain{from{transform:scaleX(1)}to{transform:scaleX(0)}}
|
|
280
361
|
.pkb-gw{position:relative}
|
|
281
|
-
.pkb-grid{display:grid;grid-template-columns:repeat(
|
|
282
|
-
.pkb-tile{position:relative;aspect-ratio:1/.82;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:16px;box-shadow:4px 4px 0 var(--pk-ink);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;transition:transform .1s,box-shadow .1s,background-color .25s}
|
|
283
|
-
.pkb-tile:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--pk-ink)}
|
|
362
|
+
.pkb-grid{display:grid;grid-template-columns:repeat(var(--pk-n),minmax(0,1fr));gap:calc(12px*var(--pk-d))}
|
|
363
|
+
.pkb-tile{position:relative;min-width:0;place-self:stretch;aspect-ratio:1/.82;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:calc(16px*var(--pk-d));box-shadow:4px 4px 0 var(--pk-ink);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(6px*var(--pk-d));cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;transition:transform .1s,box-shadow .1s,background-color .25s}
|
|
364
|
+
.pkb-tile:active:not(.pkb-free){transform:translate(3px,3px);box-shadow:1px 1px 0 var(--pk-ink)}
|
|
284
365
|
.pkb-tile input{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px}
|
|
285
366
|
.pkb-tile:has(input:focus-visible){outline:3px solid var(--pk-ink);outline-offset:3px}
|
|
286
|
-
.pkb-emo{font-size:32px;line-height:1;transition:opacity .2s}
|
|
287
|
-
.pkb-lbl{font-weight:800;font-size:13px;line-height:1.25;text-align:center;padding:0 6px;transition:opacity .2s;word-break:keep-all;overflow-wrap:anywhere}
|
|
288
|
-
.pkb-stamp{position:absolute;left:50%;top:50%;width:64%;aspect-ratio:1;border-radius:50%;border:3px solid var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-paper),inset 0 0 0 4px var(--pk-red);color:var(--pk-red);display:grid;place-items:center;font-family:var(--pk-display);font-size:20px;letter-spacing:.04em;opacity:0;transform:translate(-50%,-50%) rotate(-16deg) scale(1.7);transition:transform .25s cubic-bezier(.3,1.5,.5,1),opacity .15s;pointer-events:none}
|
|
367
|
+
.pkb-emo{font-size:max(14px,calc(32px*var(--pk-s)));line-height:1;transition:opacity .2s}
|
|
368
|
+
.pkb-lbl{font-weight:800;font-size:max(9px,calc(13px*var(--pk-s)));line-height:1.25;text-align:center;padding:0 calc(6px*var(--pk-d));transition:opacity .2s;word-break:keep-all;overflow-wrap:anywhere}
|
|
369
|
+
.pkb-stamp{position:absolute;left:50%;top:50%;width:64%;aspect-ratio:1;border-radius:50%;border:3px solid var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-paper),inset 0 0 0 4px var(--pk-red);color:var(--pk-red);display:grid;place-items:center;font-family:var(--pk-display);font-size:max(9px,calc(20px*var(--pk-s)));letter-spacing:.04em;opacity:0;transform:translate(-50%,-50%) rotate(-16deg) scale(1.7);transition:transform .25s cubic-bezier(.3,1.5,.5,1),opacity .15s;pointer-events:none}
|
|
289
370
|
.pkb-tile.pkb-on .pkb-stamp{opacity:.9;transform:translate(-50%,-50%) rotate(-16deg) scale(1)}
|
|
290
371
|
.pkb-tile.pkb-on .pkb-emo,.pkb-tile.pkb-on .pkb-lbl{opacity:.35}
|
|
372
|
+
.pkb-tile.pkb-free{cursor:default;container-type:inline-size}
|
|
373
|
+
.pkb-tile.pkb-free .pkb-stamp{width:72%;opacity:1;transition:none;font-size:17cqi;letter-spacing:.02em;line-height:1;text-align:center;background:var(--pk-red);color:var(--pk-paper);border-color:var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-red),inset 0 0 0 4px var(--pk-paper)}
|
|
291
374
|
.pkb-tile.pkb-line{background-color:var(--pk-mint)}
|
|
292
375
|
.pkb-tile.pkb-line::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:linear-gradient(110deg,transparent 30%,rgba(255,255,255,.9) 45%,transparent 60%) no-repeat;background-size:250% 100%;background-position:200% 0;animation:pkb-glint 3.2s ease-in-out var(--pkb-gd,0s) infinite}
|
|
293
376
|
@keyframes pkb-glint{0%{background-position:200% 0}30%,100%{background-position:-100% 0}}
|
|
@@ -304,12 +387,17 @@ var CSS = `
|
|
|
304
387
|
.pkb-lines{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;z-index:2;transition:opacity .4s}
|
|
305
388
|
.pkb-board.pkb-all .pkb-lines{opacity:0}
|
|
306
389
|
.pkb-lines line{fill:none;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0}
|
|
307
|
-
.pkb-lines .pkb-u{stroke:var(--pk-paper);stroke-width:
|
|
308
|
-
.pkb-lines .pkb-o{stroke:var(--pk-ink);stroke-width:
|
|
390
|
+
.pkb-lines .pkb-u{stroke:var(--pk-paper);stroke-width:calc(13px*var(--pk-d))}
|
|
391
|
+
.pkb-lines .pkb-o{stroke:var(--pk-ink);stroke-width:calc(6px*var(--pk-d))}
|
|
309
392
|
.pkb-lines .pkb-draw line{animation:pkb-draw .45s ease-out .3s both}
|
|
310
393
|
@keyframes pkb-draw{from{stroke-dashoffset:1}}
|
|
311
|
-
.pkb-foot{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:18px;font-weight:800;font-size:13px}
|
|
312
|
-
.pkb-
|
|
394
|
+
.pkb-foot{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 10px;margin-top:18px;font-weight:800;font-size:13px;word-break:auto-phrase}
|
|
395
|
+
.pkb-foot>span{flex:1 1 14em}
|
|
396
|
+
.pkb-foot>span:empty{flex-basis:0}
|
|
397
|
+
.pkb-acts{display:flex;gap:8px;flex:none;margin-left:auto}
|
|
398
|
+
.pkb-reset,.pkb-shuf{appearance:none;flex:none;border:2px solid var(--pk-ink);background:transparent;border-radius:999px;padding:5px 12px;font-weight:800;font-size:12px;line-height:1.4;color:var(--pk-ink);cursor:pointer}
|
|
399
|
+
.pkb-shuf{background:var(--pk-paper);box-shadow:2px 2px 0 var(--pk-ink)}
|
|
400
|
+
.pkb-shuf:active{transform:translate(2px,2px);box-shadow:none}
|
|
313
401
|
.pkb-flash{position:absolute;inset:0;z-index:7;background:#fff;opacity:0;pointer-events:none}
|
|
314
402
|
.pkb-flash.pkb-go{animation:pkb-flash .4s ease-out}
|
|
315
403
|
@keyframes pkb-flash{0%{opacity:.8}100%{opacity:0}}
|
|
@@ -323,7 +411,7 @@ var CSS = `
|
|
|
323
411
|
.pkb-float{position:absolute;z-index:11;pointer-events:none;white-space:nowrap;font-family:var(--pk-display);font-weight:400;line-height:1;-webkit-text-stroke:4px var(--pk-ink);paint-order:stroke fill;transform:translate(-50%,-50%);animation:pkb-rise .95s cubic-bezier(.2,.9,.3,1) both}
|
|
324
412
|
.pkb-float.pkb-pt{font-size:22px;color:var(--pk-paper)}
|
|
325
413
|
.pkb-float.pkb-cmb{font-size:17px}
|
|
326
|
-
.pkb-float.pkb-big{font-size:clamp(
|
|
414
|
+
.pkb-float.pkb-big{font-size:clamp(14px,5.6cqi,34px);color:#FFE066}
|
|
327
415
|
.pkb-float.pkb-rch{font-size:20px;color:var(--pk-red);-webkit-text-stroke:4px var(--pk-paper)}
|
|
328
416
|
@keyframes pkb-rise{0%{opacity:0;transform:translate(-50%,-20%) scale(.4)}18%{opacity:1;transform:translate(-50%,-60%) scale(1.2)}30%{transform:translate(-50%,-70%) scale(1)}75%{opacity:1}100%{opacity:0;transform:translate(-50%,-190%) scale(1)}}
|
|
329
417
|
.pkb-perfect{position:absolute;inset:0;z-index:8;display:grid;place-items:center;padding:20px;background:rgba(42,31,20,.5);opacity:0;visibility:hidden;transition:opacity .3s,visibility .3s}
|
|
@@ -334,7 +422,7 @@ var CSS = `
|
|
|
334
422
|
.pkb-perfect.pkb-show .pkb-medal{animation:pkb-slam .38s cubic-bezier(.5,0,.75,0) .35s forwards}
|
|
335
423
|
@keyframes pkb-slam{to{opacity:1;transform:rotate(-14deg) scale(1)}}
|
|
336
424
|
.pkb-ptitle{font-family:var(--pk-display);font-weight:400;font-size:30px;line-height:1.3;color:inherit}
|
|
337
|
-
.pkb-pbody{font-weight:800;font-size:13.5px;line-height:1.6;margin:6px 0 14px;white-space:pre-line}
|
|
425
|
+
.pkb-pbody{font-weight:800;font-size:13.5px;line-height:1.6;margin:6px 0 14px;white-space:pre-line;word-break:auto-phrase}
|
|
338
426
|
.pkb-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:16px}
|
|
339
427
|
.pkb-stats>div{border:2px solid var(--pk-ink);border-radius:12px;padding:6px 4px 5px;background:#fff}
|
|
340
428
|
.pkb-stats small{display:block;font-size:9.5px;font-weight:800;letter-spacing:.1em}
|
|
@@ -344,32 +432,21 @@ var CSS = `
|
|
|
344
432
|
.pkb-fx{position:absolute;inset:0;width:100%;height:100%;z-index:10;pointer-events:none}
|
|
345
433
|
.pkb-demo{max-width:720px;margin:12px auto 4px;display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-family:var(--pk-body);font-size:12px;color:#666}
|
|
346
434
|
.pkb-demo button{appearance:none;border:1px solid #ccc;background:#f3f3f3;color:#222;border-radius:999px;padding:5px 12px;font-size:12px;cursor:pointer}
|
|
347
|
-
@container (max-width:560px){.pkb-board{padding:18px 14px 16px}.pkb-head{flex-direction:column;align-items:stretch;gap:12px}.pkb-score{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.pkb-pill,.pkb-pill.pkb-sc{min-width:0;padding:5px 4px 4px}.pkb-pill b{font-size:19px}.pkb-title{font-size:26px}.pkb-grid{gap:8px}.pkb-tile{border-radius:12px;box-shadow:3px 3px 0 var(--pk-ink);gap:3px;aspect-ratio:1/1}.pkb-emo{font-size:24px}.pkb-lbl{font-size:10.5px;padding:0 2px}.pkb-stamp{font-size:14px}.pkb-tile.pkb-reach::after{font-size:9px;padding:2px 5px;top:-9px;right:-5px}.pkb-lines .pkb-u{stroke-width:
|
|
435
|
+
@container (max-width:560px){.pkb-board{padding:18px 14px 16px}.pkb-head{flex-direction:column;align-items:stretch;gap:12px}.pkb-score{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.pkb-pill,.pkb-pill.pkb-sc{min-width:0;padding:5px 4px 4px}.pkb-pill b{font-size:19px}.pkb-title{font-size:26px}.pkb-grid{gap:max(3px,calc(8px*var(--pk-d)))}.pkb-tile{border-radius:calc(12px*var(--pk-d));box-shadow:3px 3px 0 var(--pk-ink);gap:calc(3px*var(--pk-d));aspect-ratio:1/1}.pkb-emo{font-size:max(13px,calc(24px*var(--pk-s)))}.pkb-lbl{font-size:max(8.5px,calc(10.5px*var(--pk-s)));padding:0 calc(2px*var(--pk-d))}.pkb-stamp{font-size:max(9px,calc(14px*var(--pk-s)))}.pkb-tile.pkb-reach::after{font-size:9px;padding:2px 5px;top:-9px;right:-5px}.pkb-lines .pkb-u{stroke-width:calc(10px*var(--pk-d))}.pkb-lines .pkb-o{stroke-width:calc(5px*var(--pk-d))}.pkb-banner::before{width:380px;height:380px;margin:-190px 0 0 -190px}.pkb-banner span{font-size:12px}.pkb-medal{width:96px;height:96px;font-size:20px}.pkb-card{padding:20px 14px 16px}.pkb-ptitle{font-size:24px}.pkb-stats b{font-size:17px}.pkb-float.pkb-pt{font-size:17px}.pkb-float.pkb-cmb{font-size:13px}}
|
|
436
|
+
@container (max-width:400px){.pkb-board{padding:16px 10px 14px}.pkb-grid{gap:max(3px,calc(6px*var(--pk-d)))}.pkb-lbl{font-size:max(8.5px,calc(10px*var(--pk-s)));padding:0 calc(1px*var(--pk-d))}.pkb-emo{font-size:max(12px,calc(22px*var(--pk-s)))}.pkb-stamp{font-size:max(9px,calc(13px*var(--pk-s)))}.pkb-foot{margin-top:14px;font-size:12px}.pkb-perfect{padding:12px}.pkb-stats{gap:6px}.pkb-stats>div{padding:6px 2px 5px}.pkb-stats small{letter-spacing:.02em}}
|
|
437
|
+
@container (max-width:320px){.pkb-board{padding-inline:8px}.pkb-grid{gap:max(3px,calc(5px*var(--pk-d)))}.pkb-lbl{font-size:max(8.5px,calc(9.5px*var(--pk-s)));padding:0}}
|
|
348
438
|
@media (prefers-reduced-motion:reduce){.pkb-board.pkb-shake,.pkb-board.pkb-punch,.pkb-flash.pkb-go,.pkb-tile.pkb-hop,.pkb-tile.pkb-squash,.pkb-tile.pkb-reach,.pkb-tile.pkb-line::before,.pkb-pill.pkb-hot,.pkb-bump,.pkb-tile.pkb-reach::after,.pkb-banner::before,.pkb-lines .pkb-draw line,.pkb-kicker.pkb-gold{animation:none}.pkb-banner.pkb-show{animation:pkb-fade 1.8s forwards}.pkb-float{animation:pkb-fade 1s both}.pkb-perfect.pkb-show .pkb-medal{animation:none;opacity:1;transform:rotate(-14deg)}.pkb-card{transition:none}}
|
|
349
439
|
@keyframes pkb-fade{0%,100%{opacity:0}15%,80%{opacity:1}}
|
|
350
440
|
`;
|
|
351
441
|
|
|
352
442
|
// src/core.ts
|
|
353
|
-
var LINES =
|
|
354
|
-
[0, 1, 2, 3],
|
|
355
|
-
[4, 5, 6, 7],
|
|
356
|
-
[8, 9, 10, 11],
|
|
357
|
-
[12, 13, 14, 15],
|
|
358
|
-
[0, 4, 8, 12],
|
|
359
|
-
[1, 5, 9, 13],
|
|
360
|
-
[2, 6, 10, 14],
|
|
361
|
-
[3, 7, 11, 15],
|
|
362
|
-
[0, 5, 10, 15],
|
|
363
|
-
[3, 6, 9, 12]
|
|
364
|
-
];
|
|
365
|
-
var DEMO_START = [0, 1, 2, 3, 5, 10];
|
|
443
|
+
var LINES = bingoLines(4);
|
|
366
444
|
var CONFETTI = ["#E8473B", "#2F6FED", "#1FA971", "#FFFDF6", "#2A1F14", "#FF9F1C"];
|
|
367
445
|
var COMBO_COLORS = ["#FF9F1C", "#1FA971", "#2F6FED", "#9B5DE5", "#E8473B"];
|
|
368
446
|
var COMBO_MS = 2500;
|
|
369
447
|
var MUTE_KEY = "packing-bingo-muted";
|
|
448
|
+
var ORDER_PREFIX = "packing-bingo-order:";
|
|
370
449
|
var esc = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
371
|
-
var normalize = (v) => Array.from({ length: 16 }, (_, i) => !!v?.[i]);
|
|
372
|
-
var demoStart = () => Array.from({ length: 16 }, (_, i) => DEMO_START.includes(i));
|
|
373
450
|
function readStore(key) {
|
|
374
451
|
try {
|
|
375
452
|
return localStorage.getItem(key);
|
|
@@ -383,30 +460,32 @@ function writeStore(key, value) {
|
|
|
383
460
|
} catch {
|
|
384
461
|
}
|
|
385
462
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
l.id = "pkb-fonts";
|
|
396
|
-
l.rel = "stylesheet";
|
|
397
|
-
l.href = FONT_URL;
|
|
398
|
-
document.head.appendChild(l);
|
|
399
|
-
}
|
|
463
|
+
var glintDelay = (c, n) => `${+((Math.floor(c / n) + c % n) * 0.36 / Math.max(1, n - 1)).toFixed(3)}s`;
|
|
464
|
+
var lineKey = (l) => l.slice().sort((a, b) => a - b).join(",");
|
|
465
|
+
var FLY_MS = 560;
|
|
466
|
+
function ensureStyles() {
|
|
467
|
+
if (document.getElementById("pkb-styles")) return;
|
|
468
|
+
const s = document.createElement("style");
|
|
469
|
+
s.id = "pkb-styles";
|
|
470
|
+
s.textContent = CSS;
|
|
471
|
+
document.head.appendChild(s);
|
|
400
472
|
}
|
|
401
|
-
function template(
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
473
|
+
function template(L, M, { demo, shuffle, vibrate }) {
|
|
474
|
+
const n = L.size;
|
|
475
|
+
const input = vibrate ? `<input type="checkbox" switch role="checkbox">` : `<input type="checkbox">`;
|
|
476
|
+
const tiles = Array.from({ length: n * n }, (_, c) => {
|
|
477
|
+
const gd = `--pkb-gd:${glintDelay(c, n)}`;
|
|
478
|
+
if (c === L.center)
|
|
479
|
+
return `<div class="pkb-tile pkb-free pkb-on" style="${gd}"><span class="pkb-stamp">${esc(M.free)}</span></div>`;
|
|
480
|
+
const it = L.items[L.itemCell.indexOf(c)];
|
|
481
|
+
return `<label class="pkb-tile" data-reach="${esc(M.reachBadge)}" style="${gd}">${input}<span class="pkb-emo" aria-hidden="true">${esc(it.emoji)}</span><span class="pkb-lbl">${esc(it.label).replace(/・/g, "\u30FB<wbr>")}</span><span class="pkb-stamp" aria-hidden="true">${esc(M.stamp)}</span></label>`;
|
|
482
|
+
}).join("");
|
|
483
|
+
const scale = `--pk-n:${n};--pk-s:${+Math.min(1.35, 4 / n).toFixed(3)};--pk-d:${+Math.min(1, 4 / n).toFixed(3)}`;
|
|
405
484
|
const demoBar = demo ? `<div class="pkb-demo"><span>${esc(M.demoLabel)}</span><button type="button" data-r="dB">${esc(M.demoBingo)}</button><button type="button" data-r="dP">${esc(M.demoPerfect)}</button><button type="button" data-r="dR">${esc(M.demoRestore)}</button></div>` : "";
|
|
406
|
-
return `<div class="pkb"><div class="pkb-board">
|
|
485
|
+
return `<div class="pkb" style="${scale}"><div class="pkb-board">
|
|
407
486
|
<div class="pkb-head"><div>
|
|
408
487
|
<div class="pkb-tags"><span class="pkb-kicker" data-r="kick">${esc(M.tag)}</span><button type="button" class="pkb-snd" data-r="snd"></button></div>
|
|
409
|
-
<h2 class="pkb-title">${esc(M.title)}</h2
|
|
488
|
+
<h2 class="pkb-title">${esc(M.title)}</h2>${M.subtitle ? `<p class="pkb-sub">${esc(M.subtitle)}</p>` : ""}</div>
|
|
410
489
|
<div class="pkb-side"><div class="pkb-score">
|
|
411
490
|
<div class="pkb-pill"><small>${esc(M.packed)}</small><b data-r="cnt"></b></div>
|
|
412
491
|
<div class="pkb-pill" data-r="bp"><small>${esc(M.bingo)}</small><b data-r="bng"></b></div>
|
|
@@ -414,24 +493,44 @@ function template(items, M, demo) {
|
|
|
414
493
|
<div class="pkb-combo" data-r="combo"><b data-r="cmbN"></b><span class="pkb-bar"><i data-r="cbar"></i></span></div></div></div>
|
|
415
494
|
<div class="pkb-gw"><div class="pkb-grid">${tiles}</div><svg class="pkb-lines" aria-hidden="true"></svg>
|
|
416
495
|
<div class="pkb-banner" data-r="banner" aria-hidden="true"><b data-r="bT"></b><span data-r="bS"></span></div></div>
|
|
417
|
-
<div class="pkb-foot"><span data-r="msg" aria-live="polite"></span><button type="button" class="pkb-reset" data-r="reset">${esc(M.reset)}</button></div>
|
|
496
|
+
<div class="pkb-foot"><span data-r="msg" aria-live="polite"></span><div class="pkb-acts">${shuffle ? `<button type="button" class="pkb-shuf" data-r="shuf">${esc(M.shuffle)}</button>` : ""}<button type="button" class="pkb-reset" data-r="reset">${esc(M.reset)}</button></div></div>
|
|
418
497
|
<div class="pkb-flash" data-r="flash"></div>
|
|
419
498
|
<div class="pkb-perfect" data-r="perfect"><div class="pkb-card" role="dialog" aria-label="${esc(M.perfectTitle)}">
|
|
420
|
-
<div class="pkb-medal">${esc(M.perfectStamp)}</div><h3 class="pkb-ptitle">${esc(M.perfectTitle)}</h3><p class="pkb-pbody">${esc(M.
|
|
499
|
+
<div class="pkb-medal">${esc(M.perfectStamp)}</div><h3 class="pkb-ptitle">${esc(M.perfectTitle)}</h3><p class="pkb-pbody" data-r="pbody">${esc(perfectText(M, L.items.length))}</p>
|
|
421
500
|
<div class="pkb-stats"><div><small>${esc(M.statScore)}</small><b data-r="sScore">0</b></div><div><small>${esc(M.statCombo)}</small><b data-r="sCombo">\xD70</b></div><div><small>${esc(M.statLines)}</small><b data-r="sBingo">0</b></div></div>
|
|
422
501
|
<button type="button" class="pkb-close" data-r="close">${esc(M.close)}</button></div></div>
|
|
423
502
|
<canvas class="pkb-fx"></canvas></div>${demoBar}</div>`;
|
|
424
503
|
}
|
|
504
|
+
var perfectText = (M, total) => typeof M.perfectBody === "function" ? M.perfectBody(total) : M.perfectBody;
|
|
425
505
|
function createPackingBingo(container, options = {}) {
|
|
426
|
-
const
|
|
427
|
-
|
|
506
|
+
const L = resolveLayout(options);
|
|
507
|
+
const { items, cellLines } = L;
|
|
508
|
+
const n = L.size, N = items.length;
|
|
509
|
+
const normalize = (v) => Array.from({ length: N }, (_, i) => !!v?.[i]);
|
|
510
|
+
const identity = () => Array.from({ length: N }, (_, s) => s);
|
|
511
|
+
const isIdentity = (o) => o.every((v, s) => v === s);
|
|
512
|
+
const validOrder = (o) => Array.isArray(o) && o.length === N && o.every((v) => Number.isInteger(v) && v >= 0 && v < N) && new Set(o).size === N;
|
|
513
|
+
let order = identity();
|
|
514
|
+
const slotOf = identity();
|
|
515
|
+
let lines = L.lines;
|
|
516
|
+
const demoCells = [...cellLines[0], ...cellLines[2 * n].slice(1, -1)];
|
|
517
|
+
const demoSlots = L.itemCell.flatMap((c, s) => demoCells.includes(c) ? [s] : []);
|
|
518
|
+
const demoStart = () => {
|
|
519
|
+
const on = normalize(void 0);
|
|
520
|
+
demoSlots.forEach((s) => on[order[s]] = true);
|
|
521
|
+
return on;
|
|
522
|
+
};
|
|
523
|
+
const far = (c) => Math.floor(c / n) + c % n;
|
|
524
|
+
const dScale = Math.min(1, 4 / n);
|
|
428
525
|
const M = { ...ja, ...options.messages };
|
|
429
526
|
if (options.title != null) M.title = options.title;
|
|
430
527
|
if (options.tag != null) M.tag = options.tag;
|
|
431
528
|
if (options.subtitle != null) M.subtitle = options.subtitle;
|
|
432
529
|
const controlled = !!options.controlled;
|
|
433
530
|
const storageKey = resolveStorageKey(options);
|
|
531
|
+
const orderKey = storageKey && ORDER_PREFIX + storageKey;
|
|
434
532
|
const demo = !!options.demo;
|
|
533
|
+
const vibrate = options.vibrate !== false;
|
|
435
534
|
const calm = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
436
535
|
let dead = false;
|
|
437
536
|
const timers = /* @__PURE__ */ new Set();
|
|
@@ -444,8 +543,8 @@ function createPackingBingo(container, options = {}) {
|
|
|
444
543
|
};
|
|
445
544
|
const wait = (ms) => new Promise((r) => window.setTimeout(r, ms));
|
|
446
545
|
let gen = 0;
|
|
447
|
-
|
|
448
|
-
container.innerHTML = template(
|
|
546
|
+
ensureStyles();
|
|
547
|
+
container.innerHTML = template(L, M, { demo, shuffle: options.shuffle !== false, vibrate });
|
|
449
548
|
const $ = (r) => {
|
|
450
549
|
const el = container.querySelector(`[data-r="${r}"]`);
|
|
451
550
|
if (!el) throw new Error(`[packing-bingo] internal: missing element "${r}"`);
|
|
@@ -457,7 +556,9 @@ function createPackingBingo(container, options = {}) {
|
|
|
457
556
|
const svg = container.querySelector(".pkb-lines");
|
|
458
557
|
const cv = container.querySelector(".pkb-fx");
|
|
459
558
|
const ctx = cv.getContext("2d");
|
|
460
|
-
const
|
|
559
|
+
const cellTiles = Array.from(grid.children);
|
|
560
|
+
const tiles = L.itemCell.map((c) => cellTiles[c]);
|
|
561
|
+
const freeTile = L.center >= 0 ? cellTiles[L.center] : null;
|
|
461
562
|
const ins = tiles.map((t) => t.querySelector("input"));
|
|
462
563
|
const kick = $("kick"), snd = $("snd"), perfectEl = $("perfect");
|
|
463
564
|
let checked = normalize(void 0);
|
|
@@ -492,14 +593,14 @@ function createPackingBingo(container, options = {}) {
|
|
|
492
593
|
cv.width = Math.round(BW * dpr);
|
|
493
594
|
cv.height = Math.round(BH * dpr);
|
|
494
595
|
};
|
|
495
|
-
const piece = (x, y, vx, vy, g, s, life,
|
|
596
|
+
const piece = (x, y, vx, vy, g, s, life, shape2) => ({
|
|
496
597
|
x,
|
|
497
598
|
y,
|
|
498
599
|
vx,
|
|
499
600
|
vy,
|
|
500
601
|
g,
|
|
501
602
|
life,
|
|
502
|
-
shape,
|
|
603
|
+
shape: shape2,
|
|
503
604
|
w: (5 + Math.random() * 6) * s,
|
|
504
605
|
h: (3 + Math.random() * 5) * s,
|
|
505
606
|
r: Math.random() * 6,
|
|
@@ -509,9 +610,9 @@ function createPackingBingo(container, options = {}) {
|
|
|
509
610
|
const go = () => {
|
|
510
611
|
if (!raf && ctx) raf = requestAnimationFrame(tick);
|
|
511
612
|
};
|
|
512
|
-
function burst(x, y,
|
|
613
|
+
function burst(x, y, n2, o = {}) {
|
|
513
614
|
if (calm) return;
|
|
514
|
-
for (let i = 0; i <
|
|
615
|
+
for (let i = 0; i < n2; i++) {
|
|
515
616
|
const a = (o.angle ?? -Math.PI / 2) + (Math.random() - 0.5) * (o.spread ?? Math.PI * 2);
|
|
516
617
|
const v = (o.speed ?? 10) * (0.35 + Math.random() * 0.85);
|
|
517
618
|
const sh = Math.random() < (o.star ?? 0.15) ? "star" : Math.random() < 0.3 ? "round" : "rect";
|
|
@@ -602,11 +703,11 @@ function createPackingBingo(container, options = {}) {
|
|
|
602
703
|
void el.offsetWidth;
|
|
603
704
|
el.classList.add(cls);
|
|
604
705
|
};
|
|
605
|
-
const hop = (
|
|
706
|
+
const hop = (t, d) => {
|
|
606
707
|
if (calm) return;
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
replay(
|
|
708
|
+
t.classList.remove("pkb-squash");
|
|
709
|
+
t.style.setProperty("--pkb-d", d + "ms");
|
|
710
|
+
replay(t, "pkb-hop");
|
|
610
711
|
};
|
|
611
712
|
grid.addEventListener("animationend", (e) => {
|
|
612
713
|
const t = e.target;
|
|
@@ -620,6 +721,7 @@ function createPackingBingo(container, options = {}) {
|
|
|
620
721
|
r.addEventListener("animationend", () => r.remove());
|
|
621
722
|
};
|
|
622
723
|
const buzz = (pattern) => {
|
|
724
|
+
if (!vibrate) return;
|
|
623
725
|
const ua = navigator.userActivation;
|
|
624
726
|
if (ua && !ua.hasBeenActive) return;
|
|
625
727
|
try {
|
|
@@ -654,8 +756,8 @@ function createPackingBingo(container, options = {}) {
|
|
|
654
756
|
st(t0);
|
|
655
757
|
if (!calm) replay($("sp"), "pkb-bump");
|
|
656
758
|
}
|
|
657
|
-
const showGain = (
|
|
658
|
-
floatText(`+${
|
|
759
|
+
const showGain = (pts, x, y, cls = "pt") => {
|
|
760
|
+
floatText(`+${pts}`, x, y, cls);
|
|
659
761
|
countScore();
|
|
660
762
|
};
|
|
661
763
|
function countUp(el, a, b, d, fmt, ticks = false) {
|
|
@@ -675,15 +777,19 @@ function createPackingBingo(container, options = {}) {
|
|
|
675
777
|
};
|
|
676
778
|
st(t0);
|
|
677
779
|
}
|
|
678
|
-
const ctr = (
|
|
679
|
-
const t = tiles[i];
|
|
780
|
+
const ctr = (t) => {
|
|
680
781
|
return { x: t.offsetLeft + t.offsetWidth / 2, y: t.offsetTop + t.offsetHeight / 2 };
|
|
681
782
|
};
|
|
783
|
+
let landing = 0;
|
|
682
784
|
function drawLines(fresh = []) {
|
|
785
|
+
if (landing) {
|
|
786
|
+
svg.innerHTML = "";
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
683
789
|
svg.setAttribute("viewBox", `0 0 ${gw.clientWidth} ${gw.clientHeight}`);
|
|
684
790
|
svg.innerHTML = cur.map((k) => {
|
|
685
|
-
const a = ctr(
|
|
686
|
-
const dx = b.x - a.x, dy = b.y - a.y, d = Math.hypot(dx, dy) || 1, ex = dx / d *
|
|
791
|
+
const a = ctr(cellTiles[cellLines[k][0]]), b = ctr(cellTiles[cellLines[k][n - 1]]);
|
|
792
|
+
const dx = b.x - a.x, dy = b.y - a.y, d = Math.hypot(dx, dy) || 1, r = 26 * dScale, ex = dx / d * r, ey = dy / d * r;
|
|
687
793
|
const at = `x1="${a.x - ex}" y1="${a.y - ey}" x2="${b.x + ex}" y2="${b.y + ey}" pathLength="1"`;
|
|
688
794
|
return `<g${fresh.includes(k) ? ' class="pkb-draw"' : ""}><line class="pkb-u" ${at}/><line class="pkb-o" ${at}/></g>`;
|
|
689
795
|
}).join("");
|
|
@@ -694,6 +800,7 @@ function createPackingBingo(container, options = {}) {
|
|
|
694
800
|
combo = 0;
|
|
695
801
|
$("combo").classList.remove("pkb-on");
|
|
696
802
|
sfx.off();
|
|
803
|
+
buzz(8);
|
|
697
804
|
return;
|
|
698
805
|
}
|
|
699
806
|
const now = performance.now();
|
|
@@ -716,7 +823,7 @@ function createPackingBingo(container, options = {}) {
|
|
|
716
823
|
$("cmbN").textContent = M.combo(combo);
|
|
717
824
|
replay($("combo"), "pkb-on");
|
|
718
825
|
}
|
|
719
|
-
buzz(
|
|
826
|
+
buzz(18);
|
|
720
827
|
}
|
|
721
828
|
$("cbar").addEventListener("animationend", () => {
|
|
722
829
|
$("combo").classList.remove("pkb-on");
|
|
@@ -730,29 +837,29 @@ function createPackingBingo(container, options = {}) {
|
|
|
730
837
|
later(() => sfx.reach(), 150);
|
|
731
838
|
}
|
|
732
839
|
function bingo(fresh, pts) {
|
|
733
|
-
const
|
|
734
|
-
const seq = [...new Set(fresh.flatMap((k) =>
|
|
840
|
+
const nl = fresh.length;
|
|
841
|
+
const seq = [...new Set(fresh.flatMap((k) => cellLines[k]))].map((c) => cellTiles[c]);
|
|
735
842
|
const step = Math.min(70, 300 / seq.length);
|
|
736
843
|
seq.forEach(
|
|
737
|
-
(
|
|
738
|
-
hop(
|
|
739
|
-
const p = rel(
|
|
844
|
+
(t, j) => later(() => {
|
|
845
|
+
hop(t, 0);
|
|
846
|
+
const p = rel(t);
|
|
740
847
|
burst(p.x, p.y, 14, { speed: 5, g: 0.15, life: 30, size: 0.7, star: 0.8 });
|
|
741
848
|
sfx.note(j + 3);
|
|
742
849
|
}, j * step)
|
|
743
850
|
);
|
|
744
851
|
later(() => {
|
|
745
|
-
$("bT").textContent =
|
|
746
|
-
$("bS").textContent =
|
|
852
|
+
$("bT").textContent = nl >= 3 ? M.bannerTriple : nl === 2 ? M.bannerDouble : M.bannerSingle;
|
|
853
|
+
$("bS").textContent = nl > 1 ? M.bannerMulti(nl) : M.bannerNth(cur.length);
|
|
747
854
|
replay($("banner"), "pkb-show");
|
|
748
855
|
if (!calm) {
|
|
749
856
|
replay($("flash"), "pkb-go");
|
|
750
857
|
replay(board, "pkb-punch");
|
|
751
858
|
}
|
|
752
859
|
const c = rel(gw);
|
|
753
|
-
burst(c.x, c.y,
|
|
754
|
-
sfx.bingo(
|
|
755
|
-
buzz(
|
|
860
|
+
burst(c.x, c.y, nl > 1 ? 180 : 110, { speed: nl > 1 ? 16 : 13, star: 0.3 });
|
|
861
|
+
sfx.bingo(nl);
|
|
862
|
+
buzz(nl > 1 ? [40, 60, 40, 60, 90] : [40, 60, 40]);
|
|
756
863
|
if (pts) later(() => showGain(pts, c.x, c.y + 105, "big"), 350);
|
|
757
864
|
}, seq.length * step + 60);
|
|
758
865
|
}
|
|
@@ -760,9 +867,10 @@ function createPackingBingo(container, options = {}) {
|
|
|
760
867
|
const bonus = gotP ? 0 : 1e3;
|
|
761
868
|
gotP = true;
|
|
762
869
|
score += bonus;
|
|
763
|
-
|
|
870
|
+
cellTiles.forEach((t, c) => hop(t, far(c) * 180 / Math.max(1, n - 1)));
|
|
764
871
|
sfx.perfect();
|
|
765
872
|
if (!calm) replay($("flash"), "pkb-go");
|
|
873
|
+
$("pbody").textContent = perfectText(M, N);
|
|
766
874
|
$("sScore").textContent = "0";
|
|
767
875
|
$("sCombo").textContent = "\xD70";
|
|
768
876
|
$("sBingo").textContent = "0";
|
|
@@ -809,30 +917,32 @@ function createPackingBingo(container, options = {}) {
|
|
|
809
917
|
$("combo").classList.remove("pkb-on");
|
|
810
918
|
perfectEl.classList.remove("pkb-show");
|
|
811
919
|
}
|
|
920
|
+
const completeLines = () => lines.flatMap((l, k) => l.every((i) => checked[i]) ? [k] : []);
|
|
812
921
|
function render(src, quiet) {
|
|
813
922
|
const events = [];
|
|
814
923
|
const on = checked, c = on.filter(Boolean).length;
|
|
815
|
-
cur =
|
|
924
|
+
cur = completeLines();
|
|
816
925
|
const fresh = cur.filter((k) => !prevLines.has(k));
|
|
817
926
|
if ([...prevLines].some((k) => !cur.includes(k))) {
|
|
818
927
|
cancelFx();
|
|
819
|
-
if (c <
|
|
928
|
+
if (c < N) perfectEl.classList.remove("pkb-show");
|
|
820
929
|
}
|
|
821
|
-
const hit = new Set(cur.flatMap((k) =>
|
|
930
|
+
const hit = new Set(cur.flatMap((k) => cellLines[k]));
|
|
822
931
|
const reach = /* @__PURE__ */ new Set();
|
|
823
|
-
for (const l of
|
|
932
|
+
for (const l of lines) {
|
|
824
933
|
const m = l.filter((i) => !on[i]);
|
|
825
934
|
if (m.length === 1) reach.add(m[0]);
|
|
826
935
|
}
|
|
827
936
|
tiles.forEach((t, i) => {
|
|
828
937
|
t.classList.toggle("pkb-on", on[i]);
|
|
829
|
-
t.classList.toggle("pkb-line", hit.has(i));
|
|
938
|
+
t.classList.toggle("pkb-line", hit.has(L.itemCell[slotOf[i]]));
|
|
830
939
|
t.classList.toggle("pkb-reach", reach.has(i));
|
|
831
940
|
});
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
kick.
|
|
835
|
-
|
|
941
|
+
freeTile?.classList.toggle("pkb-line", hit.has(L.center));
|
|
942
|
+
board.classList.toggle("pkb-all", c === N);
|
|
943
|
+
kick.classList.toggle("pkb-gold", c === N);
|
|
944
|
+
kick.textContent = c === N ? M.perfectTag : M.tag;
|
|
945
|
+
$("cnt").textContent = `${c}/${N}`;
|
|
836
946
|
$("bng").textContent = String(cur.length);
|
|
837
947
|
const bp = $("bp");
|
|
838
948
|
if (cur.length > lastN) {
|
|
@@ -843,13 +953,13 @@ function createPackingBingo(container, options = {}) {
|
|
|
843
953
|
lastN = cur.length;
|
|
844
954
|
drawLines(fresh);
|
|
845
955
|
if (src !== null) tapFx(src, on[src]);
|
|
846
|
-
const newL = fresh.
|
|
847
|
-
newL.forEach((
|
|
956
|
+
const newL = fresh.map((k) => lineKey(lines[k])).filter((key) => !gotL.has(key));
|
|
957
|
+
newL.forEach((key) => gotL.add(key));
|
|
848
958
|
const linePts = 100 * newL.length * newL.length;
|
|
849
959
|
score += linePts;
|
|
850
960
|
if (quiet) {
|
|
851
961
|
if (linePts) countScore();
|
|
852
|
-
} else if (c ===
|
|
962
|
+
} else if (c === N && !prevAll) perfect(events);
|
|
853
963
|
else if (fresh.length) {
|
|
854
964
|
bingo(fresh, linePts);
|
|
855
965
|
const e = { newLines: fresh, totalLines: cur.length, score };
|
|
@@ -860,9 +970,9 @@ function createPackingBingo(container, options = {}) {
|
|
|
860
970
|
}
|
|
861
971
|
prevLines = new Set(cur);
|
|
862
972
|
prevReach = reach;
|
|
863
|
-
prevAll = c ===
|
|
973
|
+
prevAll = c === N;
|
|
864
974
|
const labels = [...reach].map((i) => items[i].label);
|
|
865
|
-
$("msg").textContent = c ===
|
|
975
|
+
$("msg").textContent = c === N ? M.statusDone : labels.length ? M.statusReach(labels) : cur.length ? M.statusLines(cur.length, N - c) : M.statusStart(N - c);
|
|
866
976
|
return events;
|
|
867
977
|
}
|
|
868
978
|
const flush = (events) => {
|
|
@@ -889,8 +999,9 @@ function createPackingBingo(container, options = {}) {
|
|
|
889
999
|
got.clear();
|
|
890
1000
|
gotL.clear();
|
|
891
1001
|
checked.forEach((v, i) => v && got.add(i));
|
|
892
|
-
|
|
893
|
-
|
|
1002
|
+
const done = completeLines();
|
|
1003
|
+
done.forEach((k) => gotL.add(lineKey(lines[k])));
|
|
1004
|
+
prevLines = new Set(done);
|
|
894
1005
|
prevReach = /* @__PURE__ */ new Set();
|
|
895
1006
|
prevAll = checked.every(Boolean);
|
|
896
1007
|
gotP = prevAll;
|
|
@@ -913,6 +1024,77 @@ function createPackingBingo(container, options = {}) {
|
|
|
913
1024
|
options.onChange?.(checked.slice());
|
|
914
1025
|
flush(events);
|
|
915
1026
|
}
|
|
1027
|
+
function place(next) {
|
|
1028
|
+
order = next;
|
|
1029
|
+
order.forEach((i, s) => {
|
|
1030
|
+
slotOf[i] = s;
|
|
1031
|
+
cellTiles[L.itemCell[s]] = tiles[i];
|
|
1032
|
+
});
|
|
1033
|
+
lines = L.lines.map((l) => l.map((s) => order[s]));
|
|
1034
|
+
const focused = document.activeElement;
|
|
1035
|
+
cellTiles.forEach((t, c) => {
|
|
1036
|
+
t.style.setProperty("--pkb-gd", glintDelay(c, n));
|
|
1037
|
+
grid.appendChild(t);
|
|
1038
|
+
});
|
|
1039
|
+
if (focused instanceof HTMLElement && grid.contains(focused) && document.activeElement !== focused)
|
|
1040
|
+
focused.focus({ preventScroll: true });
|
|
1041
|
+
}
|
|
1042
|
+
const saveOrder = () => {
|
|
1043
|
+
if (!orderKey) return;
|
|
1044
|
+
writeStore(orderKey, JSON.stringify(order));
|
|
1045
|
+
};
|
|
1046
|
+
let flights = [];
|
|
1047
|
+
function arrange(next) {
|
|
1048
|
+
if (!checked.every(Boolean)) cancelFx();
|
|
1049
|
+
const from = calm ? null : tiles.map((t) => t.getBoundingClientRect());
|
|
1050
|
+
flights.forEach((a) => a.cancel());
|
|
1051
|
+
flights = [];
|
|
1052
|
+
place(next);
|
|
1053
|
+
lines.forEach((l) => {
|
|
1054
|
+
if (l.every((i) => got.has(i))) gotL.add(lineKey(l));
|
|
1055
|
+
});
|
|
1056
|
+
const done = completeLines();
|
|
1057
|
+
done.forEach((k) => gotL.add(lineKey(lines[k])));
|
|
1058
|
+
prevLines = new Set(done);
|
|
1059
|
+
render(null, true);
|
|
1060
|
+
saveOrder();
|
|
1061
|
+
if (!from || typeof Element.prototype.animate !== "function") return;
|
|
1062
|
+
tiles.forEach((t, i) => {
|
|
1063
|
+
const a = from[i], b = t.getBoundingClientRect();
|
|
1064
|
+
const dx = a.left - b.left, dy = a.top - b.top;
|
|
1065
|
+
if (Math.abs(dx) + Math.abs(dy) < 1) return;
|
|
1066
|
+
flights.push(
|
|
1067
|
+
t.animate([{ transform: `translate(${dx}px,${dy}px)` }, { transform: "none" }], {
|
|
1068
|
+
duration: FLY_MS - 140,
|
|
1069
|
+
delay: Math.random() * 140,
|
|
1070
|
+
easing: "cubic-bezier(.3,1.25,.5,1)",
|
|
1071
|
+
fill: "backwards"
|
|
1072
|
+
})
|
|
1073
|
+
);
|
|
1074
|
+
});
|
|
1075
|
+
clearTimeout(landing);
|
|
1076
|
+
landing = window.setTimeout(() => {
|
|
1077
|
+
landing = 0;
|
|
1078
|
+
flights = [];
|
|
1079
|
+
if (!dead) drawLines(cur);
|
|
1080
|
+
}, FLY_MS);
|
|
1081
|
+
svg.innerHTML = "";
|
|
1082
|
+
}
|
|
1083
|
+
function shuffleCard() {
|
|
1084
|
+
let next = order.slice();
|
|
1085
|
+
do {
|
|
1086
|
+
for (let s = N - 1; s > 0; s--) {
|
|
1087
|
+
const r = Math.floor(Math.random() * (s + 1));
|
|
1088
|
+
[next[s], next[r]] = [next[r], next[s]];
|
|
1089
|
+
}
|
|
1090
|
+
} while (next.every((v, s) => v === order[s]));
|
|
1091
|
+
arrange(next);
|
|
1092
|
+
sfx.shuffle();
|
|
1093
|
+
buzz([10, 40, 10, 40, 10, 40, 24]);
|
|
1094
|
+
}
|
|
1095
|
+
const unshuffle = () => {
|
|
1096
|
+
if (!isIdentity(order)) arrange(identity());
|
|
1097
|
+
};
|
|
916
1098
|
grid.addEventListener("change", (e) => {
|
|
917
1099
|
const i = ins.indexOf(e.target);
|
|
918
1100
|
if (i < 0) return;
|
|
@@ -920,7 +1102,11 @@ function createPackingBingo(container, options = {}) {
|
|
|
920
1102
|
next[i] = !next[i];
|
|
921
1103
|
request(next, i);
|
|
922
1104
|
});
|
|
923
|
-
|
|
1105
|
+
container.querySelector('[data-r="shuf"]')?.addEventListener("click", shuffleCard);
|
|
1106
|
+
$("reset").addEventListener("click", () => {
|
|
1107
|
+
unshuffle();
|
|
1108
|
+
request(normalize(void 0), null, { reset: true });
|
|
1109
|
+
});
|
|
924
1110
|
$("close").addEventListener("click", () => perfectEl.classList.remove("pkb-show"));
|
|
925
1111
|
perfectEl.addEventListener("click", (e) => {
|
|
926
1112
|
if (e.target === perfectEl) perfectEl.classList.remove("pkb-show");
|
|
@@ -949,18 +1135,31 @@ function createPackingBingo(container, options = {}) {
|
|
|
949
1135
|
}
|
|
950
1136
|
};
|
|
951
1137
|
$("dB").addEventListener("click", () => {
|
|
952
|
-
const open = () =>
|
|
953
|
-
const pick = checked.every(Boolean) ? [...
|
|
1138
|
+
const open = () => lines.map((l) => l.filter((i) => !checked[i])).filter((m) => m.length).sort((a, b) => a.length - b.length)[0] ?? [];
|
|
1139
|
+
const pick = checked.every(Boolean) ? [...lines[0]] : open();
|
|
954
1140
|
void run(pick.map((i) => ({ i, delay: 320 })));
|
|
955
1141
|
});
|
|
956
1142
|
$("dP").addEventListener("click", () => {
|
|
957
|
-
const
|
|
1143
|
+
const all = items.map((_, i) => i);
|
|
1144
|
+
const miss = checked.every(Boolean) ? all : all.filter((i) => !checked[i]);
|
|
958
1145
|
void run(miss.map((i, k) => k < miss.length - 1 ? { i, delay: 170, quiet: true } : { i, delay: 450 }));
|
|
959
1146
|
});
|
|
960
1147
|
$("dR").addEventListener("click", () => {
|
|
961
|
-
if (
|
|
1148
|
+
if (busy) return;
|
|
1149
|
+
unshuffle();
|
|
1150
|
+
request(demoStart(), null, { reset: true });
|
|
962
1151
|
});
|
|
963
1152
|
}
|
|
1153
|
+
let startOrder = null;
|
|
1154
|
+
if (orderKey) {
|
|
1155
|
+
try {
|
|
1156
|
+
const saved = JSON.parse(readStore(orderKey) ?? "null");
|
|
1157
|
+
if (validOrder(saved)) startOrder = saved;
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (!startOrder && validOrder(options.defaultOrder)) startOrder = options.defaultOrder.slice();
|
|
1162
|
+
if (startOrder && !isIdentity(startOrder)) place(startOrder);
|
|
964
1163
|
let initial = null;
|
|
965
1164
|
if (storageKey) {
|
|
966
1165
|
try {
|
|
@@ -982,29 +1181,45 @@ function createPackingBingo(container, options = {}) {
|
|
|
982
1181
|
return {
|
|
983
1182
|
setChecked(next, opts = {}) {
|
|
984
1183
|
if (dead) return;
|
|
985
|
-
const
|
|
986
|
-
const changed =
|
|
1184
|
+
const n2 = normalize(next);
|
|
1185
|
+
const changed = n2.flatMap((v, i) => v !== checked[i] ? [i] : []);
|
|
987
1186
|
if (!changed.length) return;
|
|
988
1187
|
if (!opts.animate || changed.length !== 1) {
|
|
989
|
-
baseline(
|
|
1188
|
+
baseline(n2);
|
|
990
1189
|
return;
|
|
991
1190
|
}
|
|
992
|
-
flush(apply(
|
|
1191
|
+
flush(apply(n2, changed[0], false));
|
|
993
1192
|
},
|
|
994
1193
|
reset() {
|
|
995
|
-
if (
|
|
1194
|
+
if (dead) return;
|
|
1195
|
+
unshuffle();
|
|
1196
|
+
request(normalize(void 0), null, { reset: true });
|
|
1197
|
+
},
|
|
1198
|
+
shuffle() {
|
|
1199
|
+
if (!dead) shuffleCard();
|
|
996
1200
|
},
|
|
997
1201
|
refresh() {
|
|
998
1202
|
if (!dead) render(null, true);
|
|
999
1203
|
},
|
|
1000
1204
|
getState() {
|
|
1001
|
-
return {
|
|
1205
|
+
return {
|
|
1206
|
+
checked: checked.slice(),
|
|
1207
|
+
lines: cur.slice(),
|
|
1208
|
+
score,
|
|
1209
|
+
maxCombo,
|
|
1210
|
+
complete: checked.every(Boolean),
|
|
1211
|
+
size: n,
|
|
1212
|
+
free: L.free,
|
|
1213
|
+
order: order.slice()
|
|
1214
|
+
};
|
|
1002
1215
|
},
|
|
1003
1216
|
destroy() {
|
|
1004
1217
|
if (dead) return;
|
|
1005
1218
|
dead = true;
|
|
1006
1219
|
timers.forEach((id) => clearTimeout(id));
|
|
1007
1220
|
timers.clear();
|
|
1221
|
+
clearTimeout(landing);
|
|
1222
|
+
flights.forEach((a) => a.cancel());
|
|
1008
1223
|
cancelAnimationFrame(raf);
|
|
1009
1224
|
cancelAnimationFrame(tw);
|
|
1010
1225
|
ro?.disconnect();
|
|
@@ -1017,6 +1232,7 @@ function createPackingBingo(container, options = {}) {
|
|
|
1017
1232
|
0 && (module.exports = {
|
|
1018
1233
|
DEFAULT_ITEMS,
|
|
1019
1234
|
LINES,
|
|
1235
|
+
bingoLines,
|
|
1020
1236
|
createPackingBingo,
|
|
1021
1237
|
en,
|
|
1022
1238
|
ja
|