試験勉強用のマークシート入力・採点アプリです。白いシート上で解答をマークし、CSV/JSONへ保存して再利用できます。入力・ファイル変換・採点・保存はブラウザー内で行います。
- 数字「1〜4」、カタカナ「ア〜エ」、自作テンプレート、任意の選択肢の直接入力からシートを作成。
- 問題番号・選択肢の個別編集、問題の追加・削除・並べ替え。
- 解答と正答を別タブで入力。正答には問題ごとの配点を設定。
- 解答・正答それぞれをCSV/JSONで読込・出力。正答から空の解答ファイルも作成。
- 読込時に問題番号(label)を照合して採点し、得点・正答率・問題別判定を表示。
- 現在の作業と自作テンプレートを自動保存。PC・スマートフォン幅とキーボード操作に対応。
初版は単一選択・1人分の採点に対応します。問題文は手元の教材を参照してください。複数選択、部分点、複数人の一括採点、画像認識、ログイン、答案収集、端末間同期は含みません。
Node.js 24系とnpmを使用します。依存関係は package-lock.json で固定しています。
npm ci
npm run dev通常は http://127.0.0.1:5173/MarkSheet/ で開けます。起動ログに表示されたポートを確認してください。
Windows PowerShellでスクリプト実行ポリシーのエラーが出る場合は、ポリシーを変更せず npm.cmd / npx.cmd を使えます。
npm.cmd ci
npm.cmd run dev本番ビルドは次のコマンドで確認します。
npm run build
npm run preview -- --port 4173 --strictPorthttp://127.0.0.1:4173/MarkSheet/ を開いてください。出力先は dist/ です。HTMLの直接起動ではなくHTTPサーバー経由で使用します。
- シート作成:シート名・問題数・選択肢を指定します。初期値は20問・数字の4択です。「自由に入力(任意の選択肢)」では文字・数字・記号を直接入力し、追加・削除・並べ替えできます。2択・3択・5択以上にも対応し、4択固定ではありません。
- シート設定:番号・選択肢・並び順を編集し、「変更を保存」で確定します。解答や正答が消える場合は、対象の問題を確認してから反映します。未保存の設定から移動する際も確認します。
- 解答:丸いマークまたはラベルを選びます。各問の「解答を消す」で未回答に戻せます。
- 正答:正答と配点を設定します。初期配点は1点。未設定の正答は採点対象外です。
- 採点:「採点する」で結果を確認します。入力・構成・配点を変更すると結果は未採点に戻ります。
- 保存・持ち出し:各タブのCSV/JSON出力でファイルを保存します。未回答を残した出力も可能です。
Tabで操作対象を移動し、ラジオ入力では矢印キーで選択を切り替えられます。解除ボタンはEnter/Space、タブ切替は左右矢印とHome/Endにも対応します。ダイアログはEscapeで閉じられます。
新規作成と新規ファイル読込では「選択肢テンプレート」、シート設定では「共通の選択肢」から 自由に入力(任意の選択肢) を選びます。1行に1つ入力し、「選択肢を追加」や各行の削除ボタンで個数を変更してください。例えば「はい/いいえ」の2択、「正しい/誤り/保留」の3択、「A〜F」の6択を設定できます。
選択肢は2つ以上で、空欄・前後空白を除いた重複は使えません。ファイル読込時は、ファイル中の選択値をすべて含む選択肢を指定します。シート設定の「全問に適用」は既存問題へ、問題追加時は新しい問題へ反映されます。問題ごとに異なる選択肢や個数を使う場合は、問題の「編集」で変更できます。よく使う組み合わせは「テンプレート」タブで保存できます。
解答タブで読み込むと解答、正答タブで読み込むと正答になります。初期画面から読み込む場合は、確認画面で「読込先」を選んでください。ファイル自体に種別は含めません。
既存シートへ読み込む場合、全問の問題番号(label)を現在のシートと完全に一致させます。行の並び順は自由です。対応する問題の選択肢にない値、欠落・余分・重複した番号は拒否します。01 と 1 は別の番号です。番号と選択値が同じ別の試験かどうかはファイルから判別できないため、確認画面のシート名と読込先を確認してください。
ファイル全体の検証と確認後、選んだ側の解答または正答を全問置き換えます。反対側の入力、配点、選択肢、シート名、問題の表示順は保持します。失敗・キャンセル時は作業を変更しません。
新しく始める場合は、ファイルの番号から問題を作り、確認画面でシート名と選択肢を設定します。選択値が収まるテンプレートを初期候補として表示し、確定前に変更できます。既存のテンプレートにない値は「自由に入力」で選択肢を直接指定できます。全問同じ選択肢・1問1点で開始し、必要に応じて後から個別に編集します。現在の作業がある場合は「新しいシートとして開く」を選ぶと、確認後に置き換えます。自作テンプレートは保持します。
正答ファイルから始めた場合は、空の解答も作成します。正答タブの「空の解答をCSVで出力」「空の解答をJSONで出力」で、番号を維持した全問未回答のファイルを配布できます。解答・正答は手入力/CSV/JSONを自由に組み合わせられます。
| 状態 | 判定 | 得点 | 正答率の分母 |
|---|---|---|---|
| 正答と解答が一致 | 正解 | その問題の配点 | 含む |
| 正答と解答が不一致 | 不正解 | 0点 | 含む |
| 正答あり・解答なし | 未回答 | 0点 | 含む |
| 正答なし | 採点対象外 | 集計しない | 含まない |
- 満点は、正答が設定された問題の配点合計です。
- 正答率は「正解数 ÷ 採点対象の問題数 × 100」。小数第1位まで表示し、配点で重み付けしません。
- 全問正答未設定なら「採点対象がありません」、得点0/0点、正答率「—」を表示します。
- ファイル読込時はlabelと画面の選択肢で照合し、採点には画面で設定した配点を使用します。
サンプルは正答「ア・イ・ウ・未設定」、解答「ア・ウ・未回答・ア」です。読み込んだ後、正答タブで配点を2・1・3・1点に設定すると、2/6点、33.3%、正解・不正解・未回答・対象外が各1問 になります。新規読込の初期配点(各1点)では1/3点・33.3%です。
解答ファイルの出力は labelとanswerの2項目、正答ファイルの出力は label・answer・pointsの3項目 です。シートID・問題ID・シート名・種別・バージョン・選択肢は公開ファイルに含めません。正答の読込では、従来の2項目形式と配点を含む3項目形式の両方を受け付けます。
| 項目 | 内容 |
|---|---|
label |
問題番号の文字列。空・重複不可。01、問2なども使用可能 |
answer |
選択値の文字列。未回答・正答未設定はJSONではnull、CSVでは空欄 |
points |
正答ファイルだけで使う正の整数の配点。全問題に指定する。解答ファイルには含めない |
[
{ "label": "01", "answer": "ア" },
{ "label": "02", "answer": null }
]最上位は配列です。解答ファイルでは各要素にlabelとanswerを指定し、正答ファイルの出力ではpointsも指定します。正答の読込だけはpointsなしの旧形式も使用でき、その場合は既存シートの配点を保持し、新規シートでは1点で開始します。pointsを含める場合は全問題に正の整数を指定してください。読込時はanswer: ""も未設定として扱い、出力時はnullに統一します。番号や選択値が数字でも、"01"のように文字列で指定してください。
正答ファイルの配点付きJSON例:
[
{ "label": "01", "answer": "ア", "points": 2 },
{ "label": "02", "answer": null, "points": 1 }
]ヘッダーの列名と順序を固定します。1レコードが1問です。
label,answer
01,ア
02,- 解答ファイルのヘッダーは
label,answerの順、全レコードは2列です。answerの空欄は未設定です。 - 正答ファイルの出力は次の3列です。正答の読込では、この形式と上記の2列形式の両方を使用できます。
label,answer,points
01,ア,2
02,,1pointsは正答ファイルでだけ使う正の整数です。解答ファイルに含めると拒否されます。- UTF-8で入出力し、CSV出力にはBOMを付けます。読込時はBOM有無、CRLF/LFを許容します。JSONのBOM付き読込も可能です。
- カンマ・引用符・途中の改行を含むセルに対応します。選択肢・番号・解答を自動で数値化しません。
01と1は別の値です。 - エラーの「CSVレコード番号」はヘッダーを1として数えます。引用セル内の改行がある場合、テキストエディターの物理的な行番号とは異なります。
ファイルでは、空の一覧、重複・空の番号、必須項目の欠落、余分な項目、文字列以外の番号・選択値を拒否します。読込先のシートとの照合では、問題の欠落・追加、選択肢に存在しない値を拒否します。拡張子だけでなく内容も検証します。任意の列名のCSVを推測して変換する機能はありません。
旧形式のschemaVersion・questionsを持つJSONや9列CSVは、公開ファイルの読込対象外です。変換する場合は、各問題からlabelとanswerだけを取り出してください。以前のブラウザー内の保存データは引き続き復元できます。
画面で編集した選択肢の前後空白は取り除きます。読み込んだ文字列は保持し、選択肢の重複検査では前後空白を除いて比較します。大文字小文字・全角半角などの正規化は行いません。
作成・編集で指定できる問題数は1〜10,000問です。性能とレイアウトの検証対象は200問×10選択肢です。配点と全問題の配点合計は Number.MAX_SAFE_INTEGER(9,007,199,254,740,991)以下の整数に制限し、丸めによる誤採点を防ぎます。
| 種類 | JSON | CSV(UTF-8 BOM付き) |
|---|---|---|
| 解答 | responses.json | responses.csv |
| 正答 | answerKey.json | answerKey.csv |
- localStorageの専用キー
marksheet:workspace:v1に、シート・解答・正答・自作テンプレートを保存します。公開ファイルとは別の内部形式で、選択肢・配点・IDも保持します。採点結果は保存せず、復元後は未採点になります。 - 入力確定後200msで保存し、ページを離れる際にも保存します。シート設定は「変更を保存」、テンプレートは「テンプレートを保存」で確定した内容が対象です。
- 保存失敗を画面に通知し、入力とCSV/JSON出力を継続できます。破損データは初回読込だけでは上書きしません。新しい作業を保存すると置き換わります。
- 「保存データを削除」は確認後にこのアプリのキーだけを削除します。削除に失敗した場合は現在の作業を保持します。
- 保存は同じブラウザー・同じオリジンの範囲です。プライベートブラウズの終了やブラウザーデータ削除で失われることがあります。端末間同期・複数タブ間の同時編集調停はありません。
- 解答・正答をサーバーへ送信する処理、外部フォント、CDN、分析SDKは使用しません。表示内容はテキストとして扱います。アプリ本体とサンプルの配信には通常のHTTP通信を使用します。
npm run check
npx playwright install chromium webkit
npm run test:e2ePowerShellでは npm.cmd / npx.cmd に置き換えられます。LinuxのCIでは npx playwright install --with-deps chromium webkit を使います。
| コマンド | 対象 |
|---|---|
npm run lint |
ESLint・React Hooksの静的検査 |
npm run typecheck |
TypeScriptの型検査 |
npm test |
採点境界、形式往復、不一致、編集状態、保存失敗 |
npm run test:e2e |
本番ビルド+Playwright。ChromiumのPC/スマホ幅、WebKitのスマホ幅 |
ブラウザーテストでは全9通りの入力形式、正答先行、空シート配布、キャンセル、設定変更の影響、テンプレート、キーボード、保存失敗、200問×10選択肢、reduced motion、横幅、axeによる主要画面の検査を確認します。失敗時のスクリーンショット・トレースは test-results/、HTMLレポートは playwright-report/ に出力します。
samiosu/MarkSheet のプロジェクトサイトを想定し、Viteの base は /MarkSheet/ です。同一ページ内のタブで画面を切り替えるため、サーバー側のURLルーティングは不要です。
- リポジトリの Settings → Pages → Build and deployment → Source を GitHub Actions にします。
.github/workflows/pages.ymlを含むコードをmainにpushするか、Actionsから手動実行します。- 検証・テスト・ビルドが成功すると
dist/がPagesへ配置されます。PRでは検証のみ実行します。 - ワークフローに表示される公開URLを開き、アセット、入力、再読み込みを確認します。想定URLは
https://samiosu.github.io/MarkSheet/です。
別のリポジトリ名なら vite.config.ts の base とブラウザーテストのURLを合わせて変更してください。ユーザーサイトや独自ドメイン直下なら base: '/' を使用します。Vite公式のPagesガイド
GitHub Actionsは公式タグのコミットSHAで固定しています。更新時は配布元のリリースと差分を確認してください。
この実装で実際のGitHub Pagesへの公開は行っていません。 ローカルの /MarkSheet/ 配下での本番ビルド検証と、公開後の確認は区別してください。実機のスマートフォンでの検証も未実施です。
UIには emil-design-eng を適用しています。スキル本体とMITのLICENSEを .agents/skills/emil-design-eng/ に、取得元情報を skills-lock.json に含めています。スキルは開発用の指示書であり、Webアプリの実行時には読み込みません。
| 配置 | 役割 |
|---|---|
src/domain/ |
データ型、テンプレート設定、形式検証、採点、状態更新、保存、テスト |
src/components/ |
解答入力、設定、テンプレート、結果、ダイアログ |
src/App.tsx |
画面切替、確認フロー、ファイル操作、自動保存 |
src/styles.css |
共通の配色・余白・状態表示・レスポンシブ対応 |
public/samples/ |
公開形式の架空サンプル |
tests/ |
本番ビルドに対するブラウザーテスト |
mark-sheet-requirements.md |
添付の要件書 |
標準テンプレートは src/domain/templates.ts で変更できます。UIレビューと検証記録は docs/UI-REVIEW.md を参照してください。
GPT-6 AstraとGPT-5.6 Lunaを使用しました。
Codexに入力するための仕様書はWorkで作成し、それ以降はCodexを使用しています。
Codexにおいては、Planモードを使用して仕様書から設計を行っています。
設計及び初期の実装においてはAstra『MAX』を、修正にはAstra『Medium』とLuna『Max』を使用しました。