- JavaScript 78.3%
- CSS 14%
- HTML 4.2%
- Swift 1.9%
- Java 1.5%
- Other 0.1%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| app | ||
| assets/verkeersborden | ||
| css | ||
| gradle/wrapper | ||
| ios | ||
| js | ||
| media | ||
| .gitattributes | ||
| .gitignore | ||
| build.gradle | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| index.html | ||
| privacy.html | ||
| README.md | ||
| settings.gradle | ||
StarTrails ✦
Educatief leerspel voor kinderen uit groep 2 t/m 6, met 19 leerpaden (rekenen,
taal, spelling, topografie, geschiedenis, verkeer, vreemde talen, ...).
Geen build, geen dependencies: index.html + css/ + js/, direct te
openen in een browser. Werkt ook volledig offline (geen netwerkverzoeken).
Ook verpakt als Android-app: een dunne WebView-wrapper (zie Android-app hieronder).
Concept
De speler kiest eerst de app-taal (nl/en/es — de systeemtaal staat al voorgeselecteerd), maakt daarna een eigen diertjes-karakter, kiest een leerpad (vak) en bewandelt per wereld een slingerpad met 12 levels. Per level 5 vragen, 1–3 sterren. Na X gehaalde levels win je een nieuw kledingstuk voor je karakter — er zijn tientallen stuks te winnen, verspreid over een lange progressie, zodat er ook op de lange termijn iets te halen blijft.
- Leerpaden gescheiden — elk vak heeft zijn eigen vragenbank, ze lopen nooit door elkaar
- Groep 2 en 3 lezen nog niet — de vraag staat altijd wél uitgeschreven op het scherm (voor de ouder/leraar die meekijkt), maar wordt voor deze groepen ook automatisch en duidelijk voorgelezen; het antwoord bestaat nooit uit alleen leestekst
- Cito-leerlijn — de werelden zijn de leerroute door het schooljaar
- Profiel per kind — eigen taal, groep, avatar en voortgang; meerdere profielen per apparaat, elk met eigen profielbeheer (resetten/wissen)
Structuur
| Blok | Waar | Wat |
|---|---|---|
| CSS | css/style.css |
merkkleuren als CSS-variabelen, thema per wereld |
| Markup | index.html |
schermen (.screen), er is er steeds één .active |
| Logica | js/*.js + js/vakken/*.js |
configuratie, avatar, schermen, per-vak vraaggeneratoren |
Schermen
taalkeuze → profielen → maker → vak → werelden → kaart → spel → resultaat
Navigatie loopt via toon(id). De 🏠-knop (naarHuis()) staat op elk speelscherm.
De taalkeuze wordt maar één keer getoond — daarna herkent de app dat de
apparaattaal al gekozen is (opgeslagen in localStorage) en start hij
direct bij het profielenscherm.
Uitbreiden
Alle content staat als configuratie bovenin het script. Je hoeft zelden logica aan te raken.
Nieuwe wereld
Voeg een object toe aan WERELDEN:
{ id:"jungle", icoon:"🌴", levels:12, bonus:4,
naam:{nl:"De Wilde Jungle", en:"The Wild Jungle"},
stijl:{ bg1:"…", bg2:"…", bg3:"…", pad:"…", padStip:"…", titel:"…", band:"…" },
dieren:["🐒","🦜", … 12 stuks],
deco:["🌺","🍌", …],
critters:["🦋","🐝", …] }
Het pad wordt automatisch getekend voor elk aantal levels. Voor een eigen
getekende achtergrond: voeg een if (s === 'jungle')-tak toe aan sceneSVG().
Zonder die tak valt hij terug op de ruimte-scène — dus wél toevoegen.
Nieuw leerpad (vak)
- Object toevoegen aan
VAKKEN - Doelen per groep toevoegen in
LEERLIJN - Generatorfunctie schrijven die
{tekst, spraak, picto, opties, antwoord}teruggeeft - Regel toevoegen in
vraagVoorVak()
Opties maak je met O(html, waarde). Voor groep 2–3: gebruik plaatjes als
opties, nooit geschreven woorden, en zet altijd een picto en spraak.
Nieuwe kleding / milestone
Regel toevoegen aan ITEMS in js/avatar.js (slot hoofd/gezicht/nek/rug)
en aan MILESTONES (op de juiste plek qua n, de lijst moet oplopend
gesorteerd blijven — checkMilestones() pakt anders niet de eerstvolgende
onvervulde beloning). Een item zonder eigen tekenwerk in avatarSVG() wordt
automatisch als emoji op de juiste plek getekend (zie de generieke fallback
onderin avatarSVG()) — voor een net iets mooiere avatar kan je er later
alsnog een eigen vector-tekening aan toevoegen, net als bij de originele 8
items (pet, strik, zonnebril, ...).
Nieuwe taal
Sleutel toevoegen aan UI in js/data.js (kopieer UI.nl en vertaal) en,
per vak, aan de eigen woordenbank in dat vak-bestand. Niet elk vak heeft al
een volledige es-bank (sommige, zoals de Nederlandse d/t-spelling in
spelling.js, hebben een taalkundig eigen — geen letterlijk vertaald —
Engels alternatief en vallen voor overige talen terug op Nederlands; dat
is een bewuste, gedocumenteerde keuze, geen bug). Vergeet de vlagknop in
tekenMaker() niet als je een vierde taal toevoegt. Spraak: lees() in
js/audio.js kiest de stem op basis van taalNu() (of een expliciete
spraakTaal op de vraag, zoals het vak vreemde talen gebruikt om een
woord in de andere taal met de juiste stem te laten uitspreken).
Leerlijn (Cito)
De werelden vormen de route door het schooljaar: Bos ≈ start · Strand ≈ richting M-toets · Stad ≈ richting E-toets · Ruimte ≈ verdieping
| Groep | Rekenen | Taal |
|---|---|---|
| 2 | resultatief tellen 5→12, meer/minder | luisterwoordenschat, rijmen, klankbewustzijn |
| 3 | M3 erbij/eraf t/m 10 · E3 t/m 20 + splitsen | letters, hakken en plakken |
| 4 | t/m 100, tafels 1/2/5/10 | klankzuivere woorden, ei/ij, au/ou |
| 5 | alle tafels, delen, t/m 1000 | open/gesloten lettergrepen |
| 6 | tafels t/m 12, deelsommen, grote getallen | werkwoordspelling d/dt/t |
Aanpassen doe je in het LEERLIJN-object; de generatoren lezen daaruit.
Profielbeheer
Bij het bewerken van een bestaand profiel (⚙️ aankleden) staat onderin een profielbeheer-sectie:
- Voortgang resetten — alle sterren, gewonnen items en gedragen kleding van dat profiel worden gewist (met bevestiging), de rest (naam/avatar/taal) blijft staan.
- Alles ontgrendelen — zet in één keer alle werelden/levels op 3 sterren en ontgrendelt alle kledingstukken. Vooral bedoeld om snel te testen hoe laatste werelden/beloningen eruitzien, niet voor gewoon speelgebruik.
- Profiel wissen — verwijdert het profiel volledig.
Elk van deze acties vraagt eerst bevestiging (native confirm()-dialoog) en
is niet ongedaan te maken.
Profielen die zijn opgeslagen vóórdat een vak of wereld werd toegevoegd,
worden bij het laden automatisch aangevuld (migreerProfiel() in js/app.js)
zodat een oud profiel niet crasht op een nieuw vak.
Beloningssysteem
ITEMS (in js/avatar.js) bevat tientallen kledingstukken/accessoires over
vier slots (hoofd, gezicht, nek, rug), die één voor één ontgrendelen
via MILESTONES naarmate een profiel meer levels haalt (gehaaldeLevels(),
geteld over alle vakken samen). De thresholds lopen bewust op tot ver in de
honderden levels, zodat er ook voor een fanatieke speler nog lang iets te
winnen is.
De originele 8 items hebben een eigen handgetekende SVG in avatarSVG().
Nieuwere items hebben dat niet — ze worden generiek als emoji op de juiste
plek getekend (zie de fallback onderin avatarSVG()). Functioneel werkt dit
identiek; het is alleen minder verzorgd dan de handgetekende items.
Openstaand voor een latere sessie: per item een eigen vector-illustratie
tekenen (zoals bij de originele 8), en evt. nog een 5e kledingslot.
Nog te doen richting productie
- Spraak voor groep 2/3 — nu synthetische stemmen (browser
speechSynthesisin de webversie, native AndroidTextToSpeechin de app — zie hieronder). Voor een echt kindvriendelijke ervaring: ingesproken audio van een stemacteur. - Geluid — nu synthetische tonen via Web Audio. Vervangen door echte samples.
- Illustraties — emoji zijn placeholders; per platform zien ze er anders uit. Vervangen door eigen tekeningen in dezelfde huisstijl (zie ook Beloningssysteem hierboven).
- Ouderscherm — voortgang per vak, tijdslimiet, ouderslot.
- AVG — geen dataverzameling van kinderen, geen advertenties, offline werkend.
Android-app (build & release)
De game is een zelfstandige webapp; de Android-app is een dunne WebView-wrapper
die index.html + css/ + js/ mee in de APK bundelt en volledig offline
draait (geen netwerk-permissie, geen dataverzameling — AVG-vriendelijk).
Structuur
| Pad | Wat |
|---|---|
app/ |
Android-module: één MainActivity met een full-screen WebView |
app/build.gradle |
bundelt de webbestanden via de copyWebAssets-task naar assets/www/ |
settings.gradle |
voegt de app-module alleen toe als er een Android-SDK is (ANDROID_HOME), zodat index.html openen zónder toolchain blijft werken |
.forgejo/workflows/android.yaml |
CI: bouwt en publiceert een getekende APK + AAB |
App-id com.startrails.app · minSdk 24 (Android 7.0+) · compile/target 36.
Voorlezen (native TTS-bridge)
De Android WebView implementeert de Web Speech API (speechSynthesis)
niet — die bestaat alleen in echte browsers. Zonder bridge deed de
voorleesknop in de app dus helemaal niets. MainActivity.java initialiseert
daarom Android's eigen TextToSpeech en injecteert die als
window.AndroidTTS (speak(tekst, taal) / stop()) in de WebView.
js/audio.js (lees()) doet feature-detectie: is window.AndroidTTS
aanwezig (in de app), dan gaat het voorlezen daarlangs; anders (in een
gewone browser) via speechSynthesis, precies zoals voorheen. Dezelfde
vragen-code werkt dus ongewijzigd op beide platformen.
Releasen
Elke commit naar main levert automatisch een getekende release op (continuous
delivery). De pipeline bouwt app:assembleRelease + app:bundleRelease, ondertekent
met de upload-key en hangt StarTrails-vX.Y.Z.apk (sideload) + .aab (Play Store)
aan een nieuwe release. Je hoeft dus niets extra's te doen: gewoon pushen naar main.
- Versie:
versionName = 1.0.<CI-runnummer>, auto-tagv1.0.<runnummer>.versionCode = runnummer(uniek + oplopend, zodat Play elke upload accepteert). - Expliciete versie (optioneel): push een tag, bijv.
git tag v2.0.0 && git push origin v2.0.0→ dan isversionNamegelijk aan de tag. - Rookproef zonder release:
workflow_dispatchop een feature-branch bouwt wél APK + AAB maar publiceert géén release.
De release-secrets staan al in Forgejo (repo → Settings → Actions → Secrets):
ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS,
ANDROID_KEY_PASSWORD. Zonder deze zou CI wél bouwen, maar debug-getekend.
Lokaal bouwen kan ook met een Android-SDK: ./gradlew app:assembleDebug
(APK in app/build/outputs/apk/debug/).
Nog te doen richting productie (Android)
- Lettertypes —
index.htmlhaalt Fredoka/Nunito van Google Fonts; offline valt dit terug op systeemfonts. Voor de app: fonts lokaal meebundelen. - Play App Signing gebruiken; upload-key veilig bewaren.
Licentie
Intern prototype.