No description
  • JavaScript 77.6%
  • CSS 13.3%
  • HTML 4%
  • Shell 1.9%
  • Swift 1.8%
  • Other 1.4%
Find a file
Hermes 73d7043a8f
Some checks failed
Tests / test (push) Successful in 12s
Build & Release Android / build (push) Successful in 4m0s
Build & Release iOS / build (push) Has been cancelled
minimale iOS naar 15.0 en uploaden naar App Store Connect vanuit CI
Apple stuurde ITMS-90068 op build 69: MinimumOSVersion 13.0 is te laag, vanaf
voorjaar 2027 moet dat 15.0 zijn. De build zelf is gewoon geaccepteerd, dit was
een vooraankondiging - maar het is een regel wijzigen, dus dat doen we nu.

15.0 dekt de iPhone 6s en nieuwer. De app is een eigen WKWebView-wrapper zonder
externe pods, dus niets dwingt een lagere versie af.

Verder kan de pipeline nu zelf naar App Store Connect uploaden. Bewust achter
een schakelaar: start met workflow_dispatch en naar_appstore = true. Elke upload
is zichtbaar bij Apple en verbruikt een buildnummer dat je nooit meer kunt
hergebruiken, dus dat mag geen bijeffect van een push naar main zijn.
2026-09-01 21:15:42 +02:00
.forgejo/workflows minimale iOS naar 15.0 en uploaden naar App Store Connect vanuit CI 2026-09-01 21:15:42 +02:00
app Release notes — StarTrails 2026-08-16 14:29:06 +02:00
appstore appstore: vijf schermen per apparaat, en de juiste schermmaat 2026-08-31 14:48:35 +02:00
assets/verkeersborden Release notes — StarTrails 2026-08-16 14:29:06 +02:00
css screens 2026-08-16 14:40:26 +02:00
gradle/wrapper Fixes, uitbreidingen en policy fixes 2026-07-30 10:27:20 +02:00
ios minimale iOS naar 15.0 en uploaden naar App Store Connect vanuit CI 2026-09-01 21:15:42 +02:00
js Tests toegevoegd + opslagcontrole voor alle platforms 2026-08-29 13:19:41 +02:00
media screens 2026-08-16 14:40:26 +02:00
tests Tests toegevoegd + opslagcontrole voor alle platforms 2026-08-29 13:19:41 +02:00
.gitattributes Upload files to "/" 2026-07-16 20:35:30 +00:00
.gitignore iOS: dezelfde game, een eigen wrapper en een eigen pipeline 2026-08-05 15:53:59 +02:00
build.gradle Fixes, uitbreidingen en policy fixes 2026-07-30 10:27:20 +02:00
gradle.properties Android WebView-wrapper + Forgejo APK/AAB-pipeline 2026-07-17 08:39:57 +02:00
gradlew Android WebView-wrapper + Forgejo APK/AAB-pipeline 2026-07-17 08:39:57 +02:00
gradlew.bat Android WebView-wrapper + Forgejo APK/AAB-pipeline 2026-07-17 08:39:57 +02:00
index.html Release notes — StarTrails 2026-08-16 14:29:06 +02:00
privacy.html a 2026-07-23 10:22:31 +02:00
README.md Fixes, uitbreidingen en policy fixes 2026-07-30 10:27:20 +02:00
settings.gradle rename 2026-07-23 09:17:21 +02:00

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)

  1. Object toevoegen aan VAKKEN
  2. Doelen per groep toevoegen in LEERLIJN
  3. Generatorfunctie schrijven die {tekst, spraak, picto, opties, antwoord} teruggeeft
  4. 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 speechSynthesis in de webversie, native Android TextToSpeech in 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 he­lemaal 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-tag v1.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 is versionName gelijk aan de tag.
  • Rookproef zonder release: workflow_dispatch op 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.html haalt 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.