packing-bingo 0.0.0-stage → 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jin-hiroo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,181 @@
1
- # Temporary Holding Version
1
+ # Packing Bingo (持ちものビンゴ)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **A packing checklist for school trips that plays like bingo: stamp each item as it goes in the bag, line them up, and get combos, fanfares and fireworks. Drop it into a React site as one component, or open the single-file HTML page.**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/packing-bingo?logo=npm)](https://www.npmjs.com/package/packing-bingo)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
+ [![React 18 or later](https://img.shields.io/badge/React-%E2%89%A518-61DAFB?logo=react&logoColor=black)](#use-it-in-react)
8
+ [![TypeScript types included](https://img.shields.io/badge/types-TypeScript-3178C6?logo=typescript&logoColor=white)](src/index.ts)
9
+ [![Standalone single HTML file](https://img.shields.io/badge/standalone-single%20HTML%20file-E34F26?logo=html5&logoColor=white)](index.html)
10
+
11
+ [Use it in React](#use-it-in-react) · [Standalone page](#standalone-page) · [Customize](#customize) · [Good to know](#good-to-know) · [日本語](#日本語) · [License](#license)
12
+
13
+ <p align="center">
14
+ <a href="docs/images/bingo-desktop.png"><img src="docs/images/bingo-desktop.png" alt="A 4×4 bingo card of packing items. A diagonal line has just been completed: a large BINGO! banner, a +100 score popup and confetti are on screen, and the score panel shows 8/16 items, 2 lines and a 2-tap combo." width="560"></a>
15
+ </p>
16
+
17
+ _The second line completes on a two-tap combo: the line is drawn, the BINGO! banner and +100 pop up, and confetti bursts. The default UI is Japanese: 持ちものビンゴ = "Packing Bingo", そろった = "packed", 2ライン目 = "2nd line". An English text set is included._
18
+
19
+ <p>
20
+ <a href="docs/images/phone-reach.png"><img src="docs/images/phone-reach.png" alt="Phone layout with one line completed and a dashed, pulsing square labeled リーチ (reach) on the last missing item." height="320"></a>
21
+ <a href="docs/images/phone-combo.png"><img src="docs/images/phone-combo.png" alt="Phone layout during a three-tap combo: +20 and +30 popups, 2 COMBO! and 3 COMBO! labels, a draining combo gauge and two リーチ callouts." height="320"></a>
22
+ <a href="docs/images/phone-perfect.png"><img src="docs/images/phone-perfect.png" alt="Phone layout after all 16 items are stamped: a 準備完了 (ready) stamp, the Perfect! card with score 3,410, max combo ×10 and 10 lines, with confetti and falling item emoji." height="320"></a>
23
+ </p>
24
+
25
+ _On a phone, left to right: one line done and a リーチ ("reach") badge on the square that would finish the next one; a three-tap combo; the Perfect! screen with the final score, fireworks and falling item emoji._
26
+
27
+ ## Features
28
+
29
+ Packing the night before a school trip is a chore. Packing Bingo turns the checklist into a 4×4 bingo card, so every item packed is a stamp, and every few items there's something to celebrate.
30
+
31
+ - **Packing becomes a game.** The 16 items sit on a 4×4 card. Any row, column or diagonal is a bingo, for 10 possible lines.
32
+ - **There's always a next goal.** A square that would complete a line pulses and gets a リーチ ("reach") badge, and the footer names the item that would finish it.
33
+ - **Every tap gives feedback.** Each stamp comes with a ripple and sparks. Taps less than 2.5 s apart chain into a combo, with a rising note on each tap and a draining combo gauge.
34
+ - **The score rewards finishing.** An item is worth 10 points × the current combo the first time it's stamped. Completing n lines at once adds 100 × n² points, and the first full card adds a 1000-point bonus. Unchecking and re-checking adds nothing.
35
+ - **Finishing gets a real finale.** Stamping all 16 plays a "ready" stamp slam, fireworks and falling item emoji, then counts up the score, max combo and lines.
36
+ - **It fits into your site.** It's one React component with TypeScript types. All its CSS is scoped and prefixed, it lays itself out by the width of its own container rather than the screen, it renders safely on the server (Next.js App Router included), and you can theme it with CSS variables.
37
+ - **Sound needs no audio files.** All effects are synthesized with the Web Audio API. The 🔊 toggle mutes them, and the choice is remembered in the browser.
38
+ - **It's considerate by default.** Squares are real checkboxes, so the keyboard works. `prefers-reduced-motion` turns off particles, shaking and bouncing. Android phones vibrate on taps and bingos.
39
+
40
+ ## Use it in React
41
+
42
+ You need React 18 or later.
43
+
44
+ ```sh
45
+ npm install packing-bingo # or: pnpm add packing-bingo / yarn add packing-bingo
46
+ ```
47
+
48
+ Render the component wherever the checklist should go:
49
+
50
+ ```tsx
51
+ import { PackingBingo } from "packing-bingo";
52
+
53
+ export default function PackingPage() {
54
+ return <PackingBingo storageKey="kyoto-trip-2026" />;
55
+ }
56
+ ```
57
+
58
+ With `storageKey`, each student's progress is saved in their browser, so they can close the page and come back. The component ships with `"use client"`, so in the Next.js App Router you can use it straight from a page. It renders an empty `<div>` on the server and builds the card in the browser.
59
+
60
+ ### Your own items and English text
61
+
62
+ ```tsx
63
+ import { PackingBingo, en, type BingoItem } from "packing-bingo";
64
+
65
+ const items: BingoItem[] = [
66
+ { emoji: "🛂", label: "Passport" },
67
+ { emoji: "🎫", label: "Tickets" },
68
+ // … exactly 16 items, row by row from the top left
69
+ ];
70
+
71
+ <PackingBingo items={items} messages={en} title="Kyoto Trip" tag="Class 2-B" />;
72
+ ```
73
+
74
+ `messages` takes any subset of the UI text, so `messages={{ reset: "Start over" }}` changes just that one label. Define `items` and `messages` outside the component, or memoize them, because changing them rebuilds the card.
75
+
76
+ ### Keeping the state yourself
77
+
78
+ To store progress in your own backend or app state, make it controlled:
79
+
80
+ ```tsx
81
+ const [checked, setChecked] = useState<boolean[]>(Array(16).fill(false));
82
+
83
+ <PackingBingo
84
+ checked={checked}
85
+ onChange={setChecked}
86
+ onBingo={({ newLines, totalLines }) => console.log("bingo!", newLines, totalLines)}
87
+ onPerfect={({ score }) => saveResult(score)}
88
+ />;
89
+ ```
90
+
91
+ Only a change of a single item plays like a tap. A bigger jump in `checked`, such as loading saved progress from your server, updates the card quietly, with no fanfare and no bonus points for lines completed all at once.
92
+
93
+ ### Props
94
+
95
+ | Prop | Type | Default | What it does |
96
+ | --- | --- | --- | --- |
97
+ | `items` | `BingoItem[]` (16) | Japanese school-trip list | Squares, row by row: `{ emoji, label }` |
98
+ | `messages` | `Partial<Messages>` | `ja` | UI text; `en` is included |
99
+ | `title`, `tag`, `subtitle` | `string` | from `messages` | Heading, the small tag above it, and the line below it |
100
+ | `defaultChecked` | `boolean[]` (16) | all `false` | Initial state when uncontrolled |
101
+ | `checked` | `boolean[]` (16) | – | Controlled state; update it in `onChange` |
102
+ | `onChange` | `(checked) => void` | – | Called after each tap or reset (before `onBingo`/`onPerfect`) |
103
+ | `onBingo` | `({ newLines, totalLines, score }) => void` | – | Called when a tap completes lines |
104
+ | `onPerfect` | `({ score, maxCombo }) => void` | – | Called when all 16 are stamped |
105
+ | `storageKey` | `string` | – | Save progress in localStorage (uncontrolled only) |
106
+ | `sound` | `boolean` | `true` | Start with sound on or off, unless the user has already chosen |
107
+ | `fonts` | `boolean` | `true` | Load Dela Gothic One and M PLUS Rounded 1c from Google Fonts |
108
+ | `demo` | `boolean` | `false` | Pre-fill six items and show demo buttons |
109
+ | `className`, `style` | | – | Applied to the wrapper `<div>` |
110
+
111
+ A `ref` gives you `reset()`, `setChecked(checked)` and `getState()`. `setChecked` follows the same rule as `checked`: one item changes like a tap, more change quietly. `getState()` returns the checks, completed lines, score, max combo and whether the card is complete.
112
+
113
+ ### Theming
114
+
115
+ Set any of these CSS variables on the component or an ancestor: `--pkb-sun` (board), `--pkb-ink` (lines and text), `--pkb-paper` (squares), `--pkb-red` (stamps and accents), `--pkb-mint` (completed lines), and `--pkb-font-fallback`.
116
+
117
+ ```tsx
118
+ <PackingBingo style={{ "--pkb-sun": "#9AD0F5" } as React.CSSProperties} />
119
+ ```
120
+
121
+ The card is at most 720 px wide and switches to its compact layout below 560 px of available width.
122
+
123
+ ### Without React
124
+
125
+ The engine has no framework dependency:
126
+
127
+ ```ts
128
+ import { createPackingBingo } from "packing-bingo/core";
129
+
130
+ const card = createPackingBingo(document.getElementById("bingo")!, { storageKey: "trip" });
131
+ // later: card.destroy();
132
+ ```
133
+
134
+ ## Standalone page
135
+
136
+ `index.html` is the whole app in one file, so you can open it directly or put it on any static host. It saves progress in the browser.
137
+
138
+ ```sh
139
+ git clone https://github.com/Jin-hiroo/packing-bingo.git
140
+ cd packing-bingo
141
+ open index.html # macOS; on other systems, open the file in a browser
142
+ ```
143
+
144
+ Add `?demo` to the URL to start part-way through and show the demo buttons: "▶ ビンゴを見る" plays a bingo, and "▶ コンボ → パーフェクト" plays a combo run to a full card. On GitHub Pages, use **Settings → Pages → Deploy from a branch → `main` / root**.
145
+
146
+ ## Customize
147
+
148
+ - **React:** use the `items`, `messages`, `title`, `tag` and `subtitle` props shown above.
149
+ - **Standalone page:** the last `<script>` in `index.html` calls `PackingBingo.createPackingBingo(…)`. Add options there, for example `items: [{ emoji: "🛂", label: "Passport" }, …]`. To change the defaults for every build, edit `src/items.ts` or `src/messages.ts` and run `npm run build`.
150
+
151
+ The card needs exactly 16 items, and it throws an error otherwise. On narrow screens, labels wrap after a `・`, so `常備薬・酔い止め` breaks as 常備薬・ / 酔い止め.
152
+
153
+ ## Development
154
+
155
+ ```sh
156
+ npm install # also builds dist/ and index.html
157
+ npm run build # dist/ (ESM, CJS, types, browser bundle) and the standalone index.html
158
+ npm run typecheck
159
+ ```
160
+
161
+ `index.html` is generated from `src/` by `scripts/build-standalone.mjs`, so don't edit it by hand.
162
+
163
+ ## Good to know
164
+
165
+ - **Saving is per browser.** `storageKey` and the standalone page use localStorage, so progress doesn't follow a student to another device. For that, use controlled mode and store `checked` yourself.
166
+ - **Emoji look different on each system**, because they come from the device's emoji font.
167
+ - **Vibration works only where the Vibration API exists**, which in practice means Android browsers. iPhones don't vibrate.
168
+ - **Testing so far:** the React component was tested with React 19 in StrictMode, three cards on one page, controlled and uncontrolled, and server rendering with `renderToString` (ESM and CommonJS). Resets and callbacks that land mid-celebration were checked with scripted browser tests, which aren't part of this repository yet. Taps were automated in Chromium at desktop and phone sizes. Safari, Firefox and real phones haven't been tried yet, and the sound hasn't been checked on a real device.
169
+
170
+ ## 日本語
171
+
172
+ 修学旅行の持ち物チェックリストを、4×4のビンゴにしたものです。持ち物を入れるたびにマスをタップしてスタンプを押し、タテ・ヨコ・ナナメがそろうとビンゴになります。コンボ・スコア・効果音・花火で、前の晩の荷造りを少し楽しくします。
173
+
174
+ - **Reactのサイトで使う場合:** `npm install packing-bingo` でインストールし、`<PackingBingo storageKey="kyoto-trip-2026" />` と書くだけで表示できます。持ち物は `items`、画面の文言は `messages` で変更できます。Next.jsのApp Routerでもそのまま使えます。
175
+ - **単体のページで使う場合:** `index.html` を開くだけで動き、進み具合はブラウザに保存されます。`?demo` を付けると、途中まで埋まった状態とデモ用のボタンが出ます。
176
+
177
+ ## License
178
+
179
+ [MIT](LICENSE) © 2026 Jin-hiroo.
180
+
181
+ The Dela Gothic One and M PLUS Rounded 1c fonts are loaded from Google Fonts and are licensed under the SIL Open Font License. They aren't included in this repository.