児童が読んだ本を記録し、冊数・ページ数・金額を「貯金」のようにためていく読書通帳アプリです。 本のバーコード(ISBN)をカメラで読み取るだけで記録できます。
- 公開URL: https://reading-books.giga-school.com/(旧 https://gigayama.github.io/Reading-Books/ から専用ドメインへ移しました)
- 対象: 小学校(GIGA端末・タブレット・スマートフォン)
- 保存先: 端末内の
localStorageのみ。外部への送信は一切行いません。 - 先生向けの使い方は
MANUAL.md(専門用語なし・「うまくいかないとき」つき)
| 画面 | できること |
|---|---|
| ホーム | いままでの 冊数・ページ数・金額の合計、今月の目標に対する進み具合、記録の入口3つ(カメラ/ISBN/手入力)、さいきん きろくした本 3冊 |
| リスト | この月/この年/ぜんぶ の切りかえ、年月の選びなおし、本の名前と かいた人での検索、えらんだ範囲の 冊数・ページ数・金額 |
| 本の くわしく(リスト・ホームから) | ページ数・ねだん・ISBN の確認、★(0〜5)の付けかえ、かんそうの書き足し、その1件の削除 |
| スタンプ | 月ごとの目標(1〜99さつ・はじめは10さつ)と、たまっていくスタンプ帳(絵柄は月ごとに変わります) |
| きろく | ふりかえり(グラフ)、データの保存・読み込み、A4たてでの印刷、つかいかた、アプリとしてのインストール、音のオンオフ、記録のリセット、バージョンと学習ログ件数の表示 |
| やりかた | 入口 | 中で おきること |
|---|---|---|
| カメラで よむ | ホーム →「カメラで バーコードを よむ」 | 978 / 979 で始まる EAN-13 だけを受けつけ、読めたら そのまま書誌検索へ進みます。日本の本のねだんのバーコード(191 / 192 で始まるもの)を読んだときは、その場で読みなおしを うながします |
| ばんごうで さがす | ホーム →「本のばんごう(ISBN)で さがす」/カメラ画面 →「ばんごうで いれる」 | 13けたでも 10けたでも 入れられます(10けたは 978 を付けた13けたに直します)。チェックディジットが 合わないものは はじきます |
| じぶんで かく | ホーム →「じぶんで かいて きろくする」 | 検索をせずに、題名から手で入力します |
記録に かならず要るのは「本の なまえ」と「ページ」の2つだけです。 かいた人・ねだん・★・かんそうは 空のままでも保存できます(かいた人が空のときは「ふめい」になります)。
- すでに 同じ ISBN、または同じ題名の記録があるときは「おなじ本が あります」と出て、 それでも記録するか えらべます
- リスト/スタンプで えらんでいる年月が「今月」でないときは、その月の記録になります (入力画面に「この きろくは ◯年◯月に なります」と金色で出ます)。前の月の分を あとから入れられます
- 月の目標に はじめて とどいた月は、紙ふぶきとファンファーレでお祝いします (同じ月に2回は出ません。端末の「視差効果を減らす」がオンのときは 紙ふぶきを出しません)
次の3つの書誌データベースを 同時に 呼び、そろったものから使います。 いずれも鍵の要らない公開APIで、送るのは ISBN の数字だけです。
| 出どころ | 主に使う値 |
|---|---|
| openBD | 題名・著者・ページ数(ONIX の Extent)・ねだん |
| Google Books API | 題名・著者・ページ数(pageCount)・ねだん |
| 国立国会図書館サーチ(NDL) | 題名・著者・ページ数(extent)・ねだん |
- ページ数は ページ数として はっきり書かれている項目を先に使い、それが1つも無いときだけ 紹介文から「◯◯ページ」を拾います(大きい数を むやみに ひろわないため)
- ねだんは openBD → Google Books → NDL の順に えらびます
- 題名・ページ数・ねだんが そろったら すぐ次へ進み、そろわなくても 6秒で打ちきります (1つの API が おそいだけで 児童を ながく待たせないため)
- 3つとも だめだったときは「じぶんで かいて きろく できます」と出して 手入力へ ゆずります。 取れなかった らん(ページ・ねだん)には 赤い しるしが つきます
Chrome / Edge / Safari から ホーム画面に追加してアプリとして起動できます。
| ブラウザ | 手順 |
|---|---|
| Chrome / Edge(Android・PC) | 「きろく」→「アプリとして インストール」。 この行はブラウザが beforeinstallprompt を出したときだけ表示されるので、出ていないときはメニュー(⋮)→「アプリをインストール」 |
| Safari(iPhone・iPad) | 「きろく」→「アプリとして インストール」で手順の案内が出ます。 実際の操作は 共有 ⬆️ →「ホーム画面に追加」 |
Service Worker がアプリ本体を端末に保存するため、2回目以降はオフラインでも起動します。 (書誌データの検索だけはインターネットが必要です。)
manifest.json… アプリ名・アイコン・表示モード・ショートカットsw.js… オフライン用のキャッシュoffline.html… アプリ本体すら取れないときの案内ページicons/… アイコン(192 / 512 / maskable / apple-touch-icon)
アイコンの長押しで出るショートカットと、URL の ?screen= は次の画面を直接ひらきます。
| URL | ひらく画面 |
|---|---|
?screen=scan |
カメラで よみとる |
?screen=home / list / stamp / data |
ホーム/リスト/スタンプ/きろく |
id / scope / start_url は 公開の置き場所から始まる絶対パスにします。
このアプリは reading-books.giga-school.com という専用ドメインの直下で公開しているので、
3つとも / から始めます(quality.config.json の basePath が正解の値で、
品質ゲートと実機テストはこれと突きあわせます)。
gigayama.github.io/Reading-Books/ で公開していたころは /Reading-Books/ でした。
ドメインを移したのに /Reading-Books/ のままにすると、開いているページ
(https://reading-books.giga-school.com/)が scope の外になり、ブラウザは
manifest ごと丸ごと無視します。 その結果、インストールできず、すでにホーム画面に
入れてある PWA も起動しなくなります。gigayama.github.io のように1つのオリジンを
数十個のアプリで共有する置き方に戻すなら、basePath を /リポジトリ名/ にして
manifest の3つも書きかえてください(相対パスのままだと URL の書き方ひとつで
別アプリ扱いになったり、似た構成の別アプリと取りちがえられます)。
このリポジトリをコピーして新しいアプリを作るときは、CNAME・basePath・
manifest の3つを最初に書きかえてください。
サーバー(GitHub Pages を含む)は HTML や JS を gzip / brotli で縮めて返します。
fetch は中身をもどしてから渡してくれますが、「縮めてあります」という
Content-Encoding ヘッダーだけは Response に残ります。
これを そのまま Cache API に入れて、圏外のときにページとして返すと、
ブラウザはヘッダーを信じてもう一度ほどこうとして失敗し、真っ白なエラー画面になります。
sw.js の stripEncodingHeaders() で、中身はそのまま・ヘッダーだけ外して保存しています。
sw.js と js/app.js の APP_VERSION を、リリースごとに必ず上げてください
(この2つが食いちがうと npm run check の E9 が落ちます。package.json の version も
あわせておくと、あとから追いやすくなります)。
新しい版が用意できると、児童の画面に「あたらしい バージョンが あります」
「さいしんに する」「あとで」のバーが出ます。
黙って入れかえないのは、かんそうを入力している途中に再読み込みが走ると
書いたものが消えてしまうためです。
かいそう0(下のナビゲーションバー = タブ)
├── ホーム
│ ├── かいそう1 カメラで よみとる
│ │ └── かいそう2 本を きろくする
│ ├── かいそう1 本を きろくする ← ISBN検索・手入力から じかに
│ └── かいそう1 本の くわしく ← さいきん きろくした本 から
├── リスト
│ └── かいそう1 本の くわしく
├── スタンプ
└── きろく
├── かいそう1 どくしょの ふりかえり
├── かいそう1 データを のこす
├── かいそう1 つかいかた
└── かいそう1 ぜんぶ けす
「つかいかた」は、いちばん上の画面のときだけ出る**ヘッダー右上の「?」**からも ひらけます。
下の階層にいるとき、画面下部のナビゲーションバーが「◀ もどる」に変わります。 また、画面の左右どちらかの端から中央へスワイプしても1つ前の階層に戻れます。
戻る操作は History API を通して1本化してあり、次を保証しています。
- 端末やブラウザの「戻る」も、アプリの階層を1つずつさかのぼる
- いちばん上の画面で戻ってもアプリは終了しない(履歴の底に見張りの履歴を1つ置いています)
- スワイプ操作とブラウザの戻るが同時に起きて2階層戻ることがない
(端末がジェスチャーを引き取った場合は
touchcancelを受け取り、アプリ側は何もしません)
骨組みは Qalc と同じ設計(6トークン・太い輪郭・段差の影)にそろえたまま、 色みをアプリアイコン(本のちょきんばこ)に合わせた、深い藍+金の落ち着いた配色にしてあります。 色は次の6つのトークンだけで組み立てます。新しい画面を足すときも、この6つの外の色を増やさないでください。
| トークン | 値 | 役わり |
|---|---|---|
--bg |
#F3F0E9 |
画面の下じき(アイコンのまわりの紙いろ) |
--panel |
#FFFFFF |
カード・ボタンの面 |
--text |
#14283C |
文字とすべての輪郭線(すみ色) |
--primary |
#1F4C72 |
このアプリの色(アイコンの深い藍) |
--secondary |
#2E7D8C |
決定・進む・もどる(落ち着いた青みどり) |
--accent |
#D9AE58 |
ごほうび・強調(アイコンの金) |
文字のこさ(3段階)
本文は --text、ひかえめな説明は --ink-soft、
いちばんひかえめなもの(プレースホルダ・からっぽの表示)は --ink-faint を使います。
この3つは いちばん暗い地(--secondary-tint)にのせても 4.5:1 以上 でそろえてあります。
Chromebook の液晶は視野角もコントラストも弱く、うすい灰色はななめから見るとほとんど読めません。
| トークン | 値 | いちばん暗い地での比 |
|---|---|---|
--ink-soft |
#4C5A69 |
6.06:1 |
--ink-faint |
#5C6C7E |
4.60:1 |
値を変えたら npm run check が D8 で見張ります(quality.config.json の contrast)。
かたちの決まり
- 輪郭は太く(カード・ボタン 3px、小さい部品 2px)、色は
--text - 影は「段差」(カード
4px 4px 0/ ボタン0 4px 0)。ぼかし影は使わない - ボタンは押すと影が消えて
translateY(4px)沈む - 角丸は 20px(カード・ボタン)/16px(本の行・目標の入力)/12px(入力らん)/999px(チップ・セグメント・丸い部品)
- グラデーション・文字の影は使わない
- 書体は Zen Maru Gothic。
fonts/から自分で配ります(CDN は使いません)。 太さは実際に使っている 700 と 900 だけを配布します(500 は未使用)
アイコン(絵文字は使わない)
画面の中のアイコンはすべて自前の SVG です。絵文字は端末ごとに絵柄も色も変わるため使いません。
index.html の先頭にある <svg class="icon-sprite"> に <symbol id="i-…"> を並べ、
使う場所からは次の形で呼び出します。
<svg class="ic"><use href="#i-camera"></use></svg>ic('i-camera') // JavaScript から組み立てるときのヘルパー
ic('i-star', 'ic solid') // solid を付けると塗りつぶし(★など)- 大きさは親の
font-size(1em)、色はcurrentColorにそろいます - 線は 24×24 のビューボックスで太さ 2・角丸の端。新しいアイコンもこの形に合わせてください
- 月ごとのスタンプの絵柄は
i-m1〜i-m12(MONTH_STAMPS)です
端の「戻る」スワイプは Qalc と同じ寸法・同じ見た目です (はしの幅 32px/戻る距離 72px/たてのぶれ 48px まで/56px の半円チップ)。
本アプリは **学習ログ共通スキーマ仕様書 study.v1(1.9)**に準拠しています。
仕様書 §3.8 が本アプリの定義です(採点を伴わない活動を本スキーマに載せる事例)。
| 項目 | 値 |
|---|---|
| 出力スキーマ版 | study.v1 |
appId |
reading-books |
studyLog.js ロジック版 |
1.1(グローバル/IIFE 形態) |
| 保存先キー | study.records.v1 |
⚠️ study.records.v1は複数アプリ共通の学習ログです。 このアプリ専用のキーではないため、リセット処理やクリーンアップの対象に含めないでください。
アプリ内の「きろくを ぜんぶ けす」で削除するのは、次の3つのキーだけです。
reading_record_main_v1_logs よんだ本の記録
reading_record_main_v1_goals 月ごとの目標
reading_record_main_v1_meta お祝い済みの月・音の設定
localStorage.clear() は使用しません。Service Worker の activate でも、
reading-books- で始まる自アプリのキャッシュ以外は削除しません。
記録内容とスキーマとの対応は docs/study-log.md を参照してください。
このアプリは保存だけを行い、外部への送信は一切しません。送信するのは、
gamification.giga-school.com に置かれた学習ポータル(Gamification/manabi-portal/)です。
学習ログ(study.records.v1)は localStorage に入るため、オリジン(ドメイン)ごとに
別々です。このアプリが reading-books.giga-school.com へ移ったことで、
ポータルが自分の localStorage を読むだけでは、この記録は見えなくなりました。
そこで、読み取り専用の受け渡し口を置いています。
| ファイル | 役割 |
|---|---|
records-export.html |
受け渡し口のページ(児童が開く画面ではない) |
js/records-export.js |
study.records.v1 を読んで postMessage で返す |
ポータルがこのページを同一サイトの iframe で開き、postMessage で問い合わせます。
サブドメイン同士は同一サイト(eTLD+1 が giga-school.com)なので、ブラウザの
third-party ストレージ分割の対象にならず、iframe の中でも第一者と同じ
localStorage が見えます。
- 読むだけ。書き込みも削除もしません。 集計側の不具合でこのアプリの記録が 壊れることが、原理的に起きない形にしてあります
- 渡す相手は
giga-school.comとそのサブドメインだけです ポータルの「きろくを おくる」を押すと、端末にたまった学習ログが まなびクエスト(学習記録・ゲーミフィケーションのアプリ)へ届きます。
まなびクエスト側の読書記録の手入力フォームは廃止され、読書の記録はこのアプリだけで行います。 届いたレコードは冊数・ページ数として、ランキング(どくしょ王)・バッジ・ミッション・ 学習ポートフォリオPDFに反映されます。
送るのは次の項目だけです。児童を見分けられる情報(氏名・出席番号・端末情報)は含みません (出席番号はポータル側で付きます)。
| 送る値 | 使われ方 |
|---|---|
本の題名(unit.title) |
読書記録・みんなの本だな |
ページ数・値段・★(ext.pages / priceYen / rating) |
読書量・手ごたえの把握 |
かんそう(ext.memo) |
★の高いものが「みんなの本だな」のおすすめになります |
ISBN(ext.isbn) |
同じ本をまとめるための鍵 |
記録した月・月の冊数・目標・達成(ext.monthKey / monthlyBooks / monthlyGoal / goalAchieved) |
目標に対する進み具合 |
通算の冊数・ページ数(ext.totalBooks / totalPages) |
その時点までの読書量 |
記録のしかた(ext.lookup … auto / manual / none) |
自動で引けない本(古い蔵書など)の割合 |
記録の開始・終了時刻と かかった時間(startedAt / endedAt / elapsedMs / activeMs) |
読書時間ではありません。「記録する操作」にかかった時間で、学習時間には加算されません |
かんそうは「本を きろくする」画面で書いたものが送られます。 あとから「本の くわしく」で書き足したかんそうは、このアプリの中には残りますが、 送信ずみの学習ログには反映されません(学習ログは書きかえられない追記専用の記録のためです)。
index.html 画面の HTML(マークアップのみ。スクリプトとスタイルは持ちません)
css/style.css スタイル一式(@font-face・画面・印刷・ハイコントラスト)
css/offline.css offline.html だけで使うスタイル
js/pwa-early.js <head> 最上部で読む。インストールの合図を取りこぼさないため
js/app.js アプリ本体(画面・操作・書誌検索・学習ログの組み立て/読み出し)
js/offline.js offline.html の「もういちど ためす」
offline.html 圏外のときの案内(アプリと同じ配色・同じフォント)
studyLog.js 学習ログ共通モジュール(全アプリ共通・不変。ロジック版 1.1)
manifest.json PWA マニフェスト
sw.js Service Worker(オフライン対応)
fonts/zen-maru-gothic/ Zen Maru Gothic woff2(700 / 900・unicode-range 分割 244本)
icons/ アプリアイコン一式(192 / 512 / maskable / apple-touch / favicon / icon.svg)
vendor/quagga.min.js バーコード読取ライブラリ QuaggaJS 0.12.1(MIT)
vendor/quagga.LICENSE.txt QuaggaJS のライセンス本文
docs/study-log.md 学習ログの設計メモ
AUDIT.md GIGA Standard v4 による現状監査
MANUAL.md 先生向けの手引き
ROLLOUT.md 他のリポジトリへ持っていく知見
scripts/check-project.mjs 品質ゲート(静的・依存なし)
quality.config.json 品質ゲートの設定(コントラストの組み合わせ・例外の理由)
tests/browser.test.mjs 実機(Chromium)での検査
tests/server.mjs 検査用の静的サーバー(/Reading-Books/ の下で配信する)
package.json npm スクリプト(check / test / serve)と playwright の指定
.github/workflows/deploy.yml GitHub Actions(検査だけを行い、公開には手を出しません)
.github/dependabot.yml GitHub Actions の更新通知(月1回)
外部 CDN には一切依存していません。 Web フォントも fonts/ から自分で配ります
(学校のネットワークで外部ドメインが遮断されても、オフラインでも、同じ字体で表示されます)。
バーコードの読み取りは、対応端末では標準の BarcodeDetector を使い、
非対応の端末(iOS Safari など)では同梱の QuaggaJS に自動で切り替わります。
サーバーを持たない静的アプリ(A型)です。認証も、児童を見分ける情報もありません。
| 項目 | 設計 |
|---|---|
| 個人情報 | 持ちません。 氏名・出席番号・メールアドレスを入力させる箇所がありません |
| 保存場所 | 児童の端末の localStorage のみ。サーバーへ送りません |
| API キー | 使いません(openBD / Google Books / NDL はいずれも鍵なしの公開API) |
| 外へ出る通信 | 書誌検索の3件のみ。CSP の connect-src でそれ以外を遮断しています |
| CSP | index.html の <meta http-equiv> で宣言。script-src 'self' / style-src 'self'(インラインの script も style も無し) |
| クリックジャッキング | frame-ancestors は <meta> では効かず、GitHub Pages はヘッダーを足せないため、js/pwa-early.js で window.top !== window.self を見張ります |
localStorage.clear() |
使いません。 自アプリの3キーだけを消します |
| Service Worker | localStorage に一切触れません。reading-books- で始まる自分のキャッシュだけを掃除します |
'unsafe-inline' は script 側にも style 側にもありません。
style="..." の直書きはすべて css/style.css の補助クラス(.mt-4 .txt-danger など)に
置きかえてあります。新しい画面を足すときも style="..." を書かないでください
(CSP に弾かれて、その指定だけが無視されます)。
大きさがそのつど変わるところ(グラフの棒の高さ・進み具合のバー)は
JavaScript から element.style.height = … で動かしています。
これは CSSOM の操作なので CSP の対象外です。
| 制限 | 内容 | 対処 |
|---|---|---|
localStorage の容量 |
オリジンあたり 5MB 前後。専用ドメインなのでこのアプリだけで使えます(旧 gigayama.github.io に保存したぶんは別オリジンのため引きつげません) |
記録1件は数百バイト。数千冊でも問題ありませんが、書き出し機能を用意しています |
| 学習ログの上限 | study.records.v1 は 500件(studyLog.js)。超えると古いものから消えます |
ポータルから定期的に送ってください |
| iOS Safari の ITP | 7日間使わないと保存データが消されます | ホーム画面に追加してもらう(MANUAL.md 2章) |
| Chromebook のタブ破棄 | メモリ不足でタブが捨てられ、入力中のデータが消えることがあります | pagehide で確定保存しています |
| 書誌API | いずれも公開API。学校のフィルタで遮断されることがあります | 3系統フォールバック。すべて失敗したら手入力へ誘導します |
| フォント | fonts/ は 244本・合計 約3.9MB ありますが、unicode-range で分割されており初回に落ちるのは数十KBだけです |
先読み(precache)の対象には入れていません。 一度読まれたぶんは Service Worker が持つので、2回目からはオフラインでも同じ字体で出ます |
ビルドは不要です。ローカルで確認する場合は任意の静的サーバーで配信してください。
npx http-server -p 8099 -c-1 .Service Worker とカメラは https:// または http://localhost でのみ動作します。
manifest.json の scope が /Reading-Books/ のため、
リポジトリ名のディレクトリの下で配信してください(例:site/Reading-Books/)。
npm run check # 静的な検査(依存パッケージ不要)
npm run test:browser # 実機(Chromium)での検査。playwright が要る
npm test # 両方npm run test:browser は Chromium を立ちあげて、次を実際に確かめます。
| 見るもの | 中身 |
|---|---|
| 横スクロール | 320 / 375 / 810 / 1366 / 1920px |
| console・CSP | 全画面を回ってエラー0件・Refused to 0件 |
| 空振り検知 | 検査用の記録がリストに出ているか(出ていないと以下が素通りする) |
| タップ領域 | 44px 未満の押せる要素が無いか(::after で広げた分も数える) |
| コントラスト | 描画された文字色と、重なりを解決した地の色から計算。プレースホルダ(疑似要素)と「からっぽの表示」も含む |
| 印刷 | 印刷シートが組み立てられ、画面用の要素が出ないか |
| maskable | 絵が中央80%のまるに収まっているか(四角で見ると甘くなる) |
| オフライン | サーバーを本当に止めてアプリが起動するか |
| manifest | id / scope / start_url がリポジトリ名の絶対パスか |
npm run check のほうは、LICENSE や手引きの有無・CSP・秘密情報の直書き・localStorage.clear()・
safe-area-inset・印刷CSS・トークンのコントラスト・manifest とアイコン・sw.js の作法・
APP_VERSION の一致・1ファイルの大きさ・初回に読む JS の量を見ます。
.github/workflows/deploy.yml が、main への push と すべての Pull Request で
npm run check(静的)と npm run test:browser(Chromium)を回します。
公開そのものには手を出しません。 GitHub Pages は「ブランチからデプロイ」の設定で
main に入った時点で公開されます(ワークフローが壊れても公開は止まりません)。
- 320px 幅で横スクロールが出ない(DevTools のレスポンシブモード)
- コンソールにエラー0件、
Refused to(CSP違反)0件 - Application タブで manifest が読め、インストール可能と表示される
- サーバーを止めてから再読み込みしても起動する
- 「きろく」→「データを のこす」→「いんさつ」で A4たての記録が出る
-
APP_VERSIONを上げた(sw.jsとjs/app.jsの両方。npm run checkが食いちがいを見ます) -
npm testが通る
©2026 どくしょ ちょきんばこ/ICT支援の杜