Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Practice Kit quality
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
jobs:
quality:
name: Quality gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm run check
- run: npm test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
*.tgz
qa/
*.log
Empty file added .nojekyll
Empty file.
29 changes: 29 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Utility API

Import with require('./planner.js'), or load planner.js as a normal
browser script and use window.BeappPractice.

| Function | Input | Output |
| --- | --- | --- |
| createSession(options) | minutes: 2, 5, or 8; focus: mixed, memory, attention, reaction, or thinking; optional non-negative integer offset | Session with tasks and timing note |
| createWeek(options) | A real startDate in YYYY-MM-DD format, plus session options | Seven consecutive calendar-day suggestions |
| getTask(id) | A task ID from TASKS | Name, area, official URL, unit, instructions, and result guidance |
| validateResult(result) | {date, task, value, condition, notes?} | Normalized result with its task-specific unit |
| resultsToCsv(results) | Valid manual result objects | CSV text for a journal |
| weekToCsv(week) | Output of createWeek | CSV text for a seven-day plan |

TASKS and AREAS are frozen catalog exports.
Invalid inputs throw RangeError or TypeError.

Reaction results must be positive milliseconds. Number-memory digits and
visual-memory cells must be non-negative integers. Accuracy values must be
between 0 and 100. The condition field is required and accepts up to 120
characters; optional notes accept up to 500 characters.

For accuracy exercises, copy the percentage shown by the test, or calculate
correct / total * 100 from a completed attempt. Record any other displayed
metric in notes. Never turn a memory level or reaction time into a percentage.

The utility does not call the BEAPP API, store data, schedule reminders,
diagnose conditions, or assign difficulty levels.
A higher-level app decides when and where to store journal entries.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changelog

## 1.0.0

- Short sessions and an optional seven-day CSV plan.
- Simple instructions for eight BEAPP exercises.
- Browser-local manual journal and CSV export.
- Zero-dependency planning utility with input validation.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 BEAPP Practice Kit contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
99 changes: 99 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<img src="assets/brand-logo.webp" alt="Brain Exercise App logo" width="44">

# BEAPP Practice Kit

A small companion for [Brain Exercise App](https://brainexerciseapp.com/).
Choose a short session, understand the exercise, and keep a note of your result.

**[Open the planner and journal](https://yantm.github.io/beapp-practice-kit/)**
· [Read the practical guide](guide.md)
· [Open BEAPP Daily Training](https://brainexerciseapp.com/daily-brain-training/)

<img src="assets/hero.webp" alt="The BEAPP brain character with four skill areas" width="420">

## Start in three steps

1. Choose **2, 5, or 8 minutes**, then a skill area or “A bit of everything.”
2. Open the first exercise on BEAPP. Read its rules and finish an attempt.
3. Copy the result into your manual journal. Include the difficulty, device,
and input method so that your next comparison is useful.

Times are planning estimates, including reading the instructions.
Finish at a comfortable pace and take a break when you need one.

Prefer a ready-made session? Open
[Daily Training](https://brainexerciseapp.com/daily-brain-training/).
Want an introduction to the skill areas? Start with
[Brain Check](https://brainexerciseapp.com/brain-check/).

## What the kit includes

- A short-session planner with memory, attention, reaction, and thinking choices.
- Plain-English steps for eight exercises.
- A downloadable seven-day CSV plan. Each day is optional.
- A manual browser-local journal with CSV export.
- A zero-dependency JavaScript utility for other small planning tools.

The exercises run on **brainexerciseapp.com**. This kit stores only the
results you enter yourself. It does not import or change your app history.

## Use it without installing anything

Open the live planner above. To use the kit offline, download the
**beapp-practice-kit-v1.0.0.zip** release, unzip it, and open **index.html**.
The planner, instructions, and CSV exports work locally.
Opening an exercise still requires access to BEAPP.

The kit does not include analytics or send journal entries to a server.
Entries are stored in this browser's local storage. Clearing site data,
changing browsers, or using private browsing can remove access to them.
Export CSV to keep a copy. If storage is unavailable, the page tells you
to export temporary entries before leaving.

## Read results fairly

Compare the **same exercise, difficulty, device, and input method**.
Read accuracy alongside speed when both are shown. Record interruptions
or early clicks in your notes. The kit keeps each exercise's units separate
and does not combine them into an overall score.

Results describe performance in specific tasks. This kit is a planning and
note-taking tool, not a medical assessment or a promise of changes in
everyday abilities. [How BEAPP results are calculated](https://brainexerciseapp.com/how-results-are-calculated/).

## JavaScript usage

Node.js 20 or newer is required only for development and the utility API.
No Node.js installation is needed to open the browser kit.

```js
const { createSession, createWeek, resultsToCsv } = require('./planner.js');
const session = createSession({ minutes: 5, focus: 'memory' });
console.log(session.tasks.map(task => task.name));
const week = createWeek({ startDate: '2026-10-06', minutes: 5, focus: 'mixed' });
const csv = resultsToCsv([{
date: '2026-10-06', task: 'reaction', value: 240,
condition: 'same difficulty · laptop · mouse', notes: 'no early clicks'
}]);
```

API reference: [API.md](API.md).
Dates use YYYY-MM-DD; the seven-day schedule uses UTC calendar arithmetic.
CSV export quotes text and protects against spreadsheet formula interpretation.

## Development

```sh
npm run check
npm test
```

Tests cover planning choices, date boundaries, result units, validation,
and CSV handling. Pull requests run the **Quality gate** workflow.
There is no build step and no runtime dependency.

## License

New utility code and documentation are MIT licensed.
BEAPP logos, mascot artwork, and skill icons have separate
[brand asset terms](assets/NOTICE.md).
89 changes: 89 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* Browser companion: journal entries stay in this browser only. */
(function(){
'use strict';
const api = window.BeappPractice, $ = id=>document.getElementById(id);
const KEY = 'beapp_practice_kit_journal_v1';
const today = new Date();
const date = today.getFullYear()+'-'+String(today.getMonth()+1).padStart(2,'0')+'-'+String(today.getDate()).padStart(2,'0');
const escape = value=>String(value).replaceAll('&','&amp;').replaceAll('<','&lt;').replaceAll('>','&gt;').replaceAll('"','&quot;').replaceAll("'",'&#39;');
const status = (id,text,error=false)=>{ $(id).textContent=text; $(id).classList.toggle('error',error); };
function options(){
const data = new FormData($('plan-form'));
return {minutes:Number(data.get('minutes')),focus:data.get('focus')};
}
function renderSession(){
const session = api.createSession(options());
$('session').innerHTML='<h3>Your '+session.minutes+'-minute starting route</h3><p>Read the rules, finish an attempt, and note the result.</p><ol>'+
session.tasks.map((task,i)=>'<li><span class="step-number">'+String(i+1).padStart(2,'0')+'</span><div><a target="_blank" rel="noopener" href="'+task.url+'">'+task.name+' ↗</a><small>'+escape(task.steps[0])+'</small></div></li>').join('')+
'</ol><a class="button primary" target="_blank" rel="noopener" href="'+session.tasks[0].url+'">Start with '+session.tasks[0].name+' ↗</a>';
}
function readResults(){
const raw = localStorage.getItem(KEY);
if (!raw) return [];
const list = JSON.parse(raw);
if (!Array.isArray(list)||list.length>1000) throw new Error('The saved journal could not be read. Your existing data has been left in place.');
return list.map(api.validateResult);
}
let entries=[];
function renderResults(){
$('download-results').disabled=entries.length===0;
$('results').innerHTML=entries.length?entries.slice(-20).reverse().map(row=>{
const task=api.getTask(row.task);
return '<article class="result-row"><div><strong>'+task.name+'</strong><strong>'+row.value+' '+escape(task.unit)+'</strong></div><small>'+escape(row.date)+' · '+escape(row.condition)+'</small>'+
(row.notes?'<p>'+escape(row.notes)+'</p>':'')+'</article>';
}).join(''):'<div class="empty"><strong>Your first result goes here.</strong><p>Finish one exercise on BEAPP, then copy its result into this journal.</p></div>';
if (entries.length>20) status('storage-status','Showing the latest 20 results. Export CSV includes all '+entries.length+' entries.');
}
function refreshResults(){
try {entries=readResults(); status('storage-status',''); renderResults();}
catch(error){status('storage-status',error.message+' Export any unsaved entries before leaving this page.',true);}
}
function updateValue(){
const task=api.getTask($('result-task').value), input=$('result-value');
$('value-label').textContent=task.label;
$('value-help').textContent=task.read;
input.min=task.min; input.step=task.integer?'1':'any';
if (task.max!==undefined) input.max=task.max; else input.removeAttribute('max');
input.value='';
}
function download(filename,text){
const url=URL.createObjectURL(new Blob(['\uFEFF'+text],{type:'text/csv;charset=utf-8'}));
const anchor=document.createElement('a');
anchor.href=url; anchor.download=filename; document.body.append(anchor); anchor.click(); anchor.remove();
setTimeout(()=>URL.revokeObjectURL(url),2000);
}
$('week-start').value=date; $('result-date').value=date;
$('result-task').innerHTML=api.TASKS.map(task=>'<option value="'+task.id+'">'+task.name+'</option>').join('');
$('exercise-guide').innerHTML=api.TASKS.map(task=>'<article class="card exercise"><img src="assets/'+task.area+'.svg" alt=""><h3>'+task.name+'</h3><p>'+task.read+'</p><details><summary>How to do it</summary><div class="answer"><ol>'+task.steps.map(step=>'<li>'+escape(step)+'</li>').join('')+'</ol><p class="tip">'+escape(task.tip)+'</p></div></details><a target="_blank" rel="noopener" href="'+task.url+'">Try '+task.name+' ↗</a></article>').join('');
$('plan-form').addEventListener('change',renderSession);
$('plan-form').addEventListener('submit',event=>event.preventDefault());
$('result-task').addEventListener('change',updateValue);
$('download-week').addEventListener('click',()=>{
try {download('beapp-practice-plan.csv',api.weekToCsv(api.createWeek({startDate:$('week-start').value,...options()})));status('week-status','Your 7-day CSV plan is ready. Each day is optional.');}
catch(error){status('week-status',error.message,true);}
});
$('print-plan').addEventListener('click',()=>window.print());
$('result-form').addEventListener('submit',event=>{
event.preventDefault();
let row;
try {row=api.validateResult({date:$('result-date').value,task:$('result-task').value,value:$('result-value').value,condition:$('result-condition').value,notes:$('result-notes').value});}
catch(error){status('save-status',error.message,true);return;}
try {
const current=readResults();
if(current.length>=1000){status('save-status','This journal has 1,000 entries. Export CSV to keep a copy.',true);return;}
const next=[...current,row];
localStorage.setItem(KEY,JSON.stringify(next));
entries=next;status('save-status','Saved in this browser.');status('storage-status','');renderResults();
$('result-value').value='';$('result-notes').value='';
} catch(error) {
// Preserve an exportable in-memory entry when storage is unavailable.
entries=[...entries,row];renderResults();
status('save-status','Could not save to browser storage. This entry is temporary: export CSV before leaving or reloading.',true);
}
});
$('download-results').addEventListener('click',()=>{
if(entries.length) download('beapp-practice-journal.csv',api.resultsToCsv(entries));
});
window.addEventListener('storage',event=>{if(event.key===KEY) refreshResults();});
renderSession();updateValue();refreshResults();
})();
6 changes: 6 additions & 0 deletions assets/NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# BEAPP brand assets

The logo, mascot illustration, and four skill icons belong to the Brain
Exercise App brand and are included to identify this companion.
The repository's MIT license covers the new utility code and documentation.
It does not grant rights to BEAPP trademarks or brand artwork.
14 changes: 14 additions & 0 deletions assets/attention.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/brand-logo.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions assets/memory.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions assets/reaction.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions assets/thinking.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading