Add project skeleton: Godot setup, tooling, and smoke test

Pins Godot 4.6.3-stable and GUT 9.6.0 (9.6.1+ reference
AccessibilityServer, unavailable in 4.6.3) via tools/setup.sh. Wires
make check (gdlint + gdformat config for 4-space indent, headless
GUT run, and a JSON well-formedness check ahead of real schema
validation). Seven autoload stubs match the architecture in the
cahier des charges; real logic lands with the following steps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Denis Defolie
2026-10-11 16:15:19 +02:00
parent 50198a49a2
commit a1f749de40
48 changed files with 475 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[*.{gd,py,json,md,cfg,yml,yaml,sh}]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
+30
View File
@@ -0,0 +1,30 @@
# Texte : fins de ligne normalisees en LF
* text=auto eol=lf
*.gd text eol=lf
*.gdshader text eol=lf
*.tscn text eol=lf
*.tres text eol=lf
*.cfg text eol=lf
*.json text eol=lf
*.md text eol=lf
*.cs text eol=lf
*.py text eol=lf
*.sh text eol=lf
Makefile text eol=lf
# Assets : binaires, jamais de conversion de fin de ligne
*.png binary
*.jpg binary
*.jpeg binary
*.webp binary
*.ogg binary
*.wav binary
*.mp3 binary
*.ttf binary
*.otf binary
*.woff binary
*.woff2 binary
*.zip binary
*.ico binary
*.svg binary
+26
View File
@@ -0,0 +1,26 @@
# Runtime et artefacts Godot
.godot/
build/
# Outillage telecharge par `make setup` (Godot, GUT), non versionne
.godot-bin/
addons/gut/
.venv/
# Python
__pycache__/
*.pyc
# Secrets et identifiants (export, env, mots de passe, cles)
.env
*.env
*.keystore
*.jks
*.p12
*.mobileprovision
secrets.*
export_credentials.cfg
# Fichiers d'edition courants
*.swp
.DS_Store
+1
View File
@@ -0,0 +1 @@
4.6.3-stable
+35
View File
@@ -0,0 +1,35 @@
GODOT_BIN := .godot-bin/godot
VENV := .venv
GDLINT := $(VENV)/bin/gdlint
GDFORMAT := $(VENV)/bin/gdformat
GD_SOURCES := autoload scripts tests
.PHONY: setup run lint format validate-data test check export-linux export-windows
setup:
tools/setup.sh
run:
$(GODOT_BIN) --path .
lint:
$(GDLINT) $(GD_SOURCES)
format:
$(GDFORMAT) $(GD_SOURCES)
validate-data:
$(GODOT_BIN) --headless --path . -s res://scripts/data/validate_data_cli.gd
test:
$(GODOT_BIN) --headless --path . -s res://addons/gut/gut_cmdln.gd -gdir=res://tests -gexit
check: lint validate-data test
export-linux:
@echo "Export Linux : pas encore configure (voir Ordre de construction, etape 6)."
@exit 1
export-windows:
@echo "Export Windows : pas encore configure (voir Ordre de construction, etape 6)."
@exit 1
+44
View File
@@ -0,0 +1,44 @@
# Les Aventuriers des mots (The Word Adventurers)
An educational French-language game for 7-9 year olds (French grades CE1-CE2): an offline 2D adventure with an explorable map, a guide character, and grammar, spelling, and dictation exercises.
Open source project, in development. Current status: technical skeleton (see `docs/specs/decisions.md` for scoping decisions and `docs/specs/cahier-des-charges.md` for the full specification, both in French — this is a French-curriculum product).
## Tech stack
- Godot 4.6 (typed GDScript)
- Exercises and pedagogical content as JSON data, validated on load
- Headless tests (GUT), GDScript lint/format (gdtoolkit)
## Getting started
```sh
make setup # installs Godot (pinned), GUT and gdtoolkit locally, nothing is committed
make run # runs the game
```
## Commands
| Command | Effect |
|---|---|
| `make setup` | installs tooling (lint, tests, export templates) |
| `make run` | runs the game |
| `make lint` / `make format` | GDScript static analysis and formatting |
| `make validate-data` | validates the JSON files in `data/` |
| `make test` | headless tests |
| `make check` | lint + validate-data + test, must pass before every commit |
| `make export-linux` / `make export-windows` | exports into `build/` (from the export step onward) |
## Structure
- `autoload/`: global modules (game lifecycle, profiles, progress, exercises, saves, audio, settings)
- `scenes/`: self-contained Godot scenes communicating via signals
- `scripts/`: pure logic (correction, pedagogy) and data loading
- `data/`: pedagogical content as JSON, validated against schemas
- `assets/`: graphics and audio (placeholder at this stage, see `assets/CREDITS.md`)
- `tests/`: headless tests (GUT)
- `docs/specs/`: specification and scoping decisions (French)
## License
Code and content under the [GNU Affero General Public License v3](LICENSE).
+44
View File
@@ -0,0 +1,44 @@
# Les Aventuriers des mots
Jeu éducatif de français pour les CE1-CE2 (7-9 ans) : une aventure 2D hors ligne, avec une carte à explorer, un personnage guide, et des exercices de grammaire, d'orthographe et de dictées.
Projet open source, en développement. Statut actuel : squelette technique (voir `docs/specs/decisions.md` pour les décisions de cadrage et `docs/specs/cahier-des-charges.md` pour la spécification complète).
## Pile technique
- Godot 4.6 (GDScript typé)
- Exercices et contenu pédagogique en données JSON, validées au chargement
- Tests headless (GUT), lint/format GDScript (gdtoolkit)
## Démarrer
```sh
make setup # installe Godot (pinné), GUT et gdtoolkit en local, rien n'est commité
make run # lance le jeu
```
## Commandes
| Commande | Effet |
|---|---|
| `make setup` | installe l'outillage (lint, tests, modèles d'export) |
| `make run` | lance le jeu |
| `make lint` / `make format` | analyse statique et formatage GDScript |
| `make validate-data` | valide les JSON de `data/` |
| `make test` | tests headless |
| `make check` | lint + validate-data + test, à passer avant chaque commit |
| `make export-linux` / `make export-windows` | exports dans `build/` (à partir de l'étape export) |
## Structure
- `autoload/` : modules globaux (gestion du jeu, profils, progression, exercices, sauvegardes, audio, réglages)
- `scenes/` : scènes Godot, autonomes et communiquant par signaux
- `scripts/` : logique pure (correction, pédagogie) et chargement des données
- `data/` : contenu pédagogique en JSON, validé contre des schémas
- `assets/` : graphismes et audio (provisoires à ce stade, voir `assets/CREDITS.md`)
- `tests/` : tests headless (GUT)
- `docs/specs/` : cahier des charges et décisions de cadrage
## Licence
Code et contenu sous [GNU Affero General Public License v3](LICENSE).
+9
View File
@@ -0,0 +1,9 @@
# Sources des assets provisoires
Tous les graphismes et sons actuels sont provisoires, crees pour ce projet, sans asset tiers.
| Fichier | Origine | Licence |
|---|---|---|
| `icon.svg` | Forme geometrique simple, creee pour ce projet | AGPL-3.0 (code et assets du depot) |
Les voix de dictee provisoires (a venir) seront generees par synthese vocale hors ligne et listees ici au fur et a mesure, avec la mention `review_status: draft` correspondante dans les donnees.
View File
View File
View File
View File
View File
View File
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Lecture des voix, dictees, musiques et effets sonores, y compris l'audio provisoire des dictees.
## Logique detaillee a partir de l'etape "Scenes" (voir Ordre de construction).
+1
View File
@@ -0,0 +1 @@
uid://542icpqhkik3
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Chargement et deroulement des exercices a partir des donnees JSON validees.
## Logique detaillee a partir de l'etape "Donnees" (voir Ordre de construction).
+1
View File
@@ -0,0 +1 @@
uid://dvni3nligy7lx
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Cycle de vie de l'application, navigation entre scenes et etat general du jeu.
## Logique detaillee a partir de l'etape "Scenes" (voir Ordre de construction).
+1
View File
@@ -0,0 +1 @@
uid://cw6hsqn7d08bu
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Creation, selection et suppression des profils enfants.
## Logique detaillee a partir de l'etape "Profils et sauvegardes".
+1
View File
@@ -0,0 +1 @@
uid://dl471qrur3sxh
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Competences, missions debloquees et planification des revisions par profil.
## Logique detaillee a partir de l'etape "Logique pure" (voir docs/specs/decisions.md, point 5).
+1
View File
@@ -0,0 +1 @@
uid://ei0m2liq1j86
+4
View File
@@ -0,0 +1,4 @@
extends Node
## Serialisation des sauvegardes par profil dans user:// (ecriture atomique,
## copie de secours, migration).
## Logique detaillee a partir de l'etape "Profils et sauvegardes".
+1
View File
@@ -0,0 +1 @@
uid://ce07tiyi8ad46
+3
View File
@@ -0,0 +1,3 @@
extends Node
## Volume, taille du texte et autres preferences de l'enfant ou de l'adulte.
## Logique detaillee a partir de l'etape "Scenes" (voir Ordre de construction).
+1
View File
@@ -0,0 +1 @@
uid://cdsn8dm6pbh6w
View File
View File
View File
View File
View File
View File
View File
View File
View File
+5
View File
@@ -0,0 +1,5 @@
excluded_directories: !!set
.git: null
line_length: 100
safety_checks: null
use_spaces: 4
+47
View File
@@ -0,0 +1,47 @@
class-definitions-order:
- tools
- classnames
- extends
- docstrings
- signals
- enums
- consts
- staticvars
- exports
- pubvars
- prvvars
- onreadypubvars
- onreadyprvvars
- others
class-load-variable-name: (([A-Z][a-z0-9]*)+|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
class-name: ([A-Z][a-z0-9]*)+
class-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
comparison-with-itself: null
constant-name: _?[A-Z][A-Z0-9]*(_[A-Z0-9]+)*
disable: []
duplicated-load: null
enum-element-name: '[A-Z][A-Z0-9]*(_[A-Z0-9]+)*'
enum-name: ([A-Z][a-z0-9]*)+
excluded_directories: !!set
.git: null
expression-not-assigned: null
function-argument-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
function-arguments-number: 10
function-name: (_on_([A-Z][a-z0-9]*)+(_[a-z0-9]+)*|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
function-preload-variable-name: ([A-Z][a-z0-9]*)+
function-variable-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
load-constant-name: (([A-Z][a-z0-9]*)+|_?[A-Z][A-Z0-9]*(_[A-Z0-9]+)*)
loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
max-file-lines: 1000
max-line-length: 100
max-public-methods: 20
max-returns: 6
mixed-tabs-and-spaces: null
no-elif-return: null
no-else-return: null
signal-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
sub-class-name: _?([A-Z][a-z0-9]*)+
tab-characters: 1
trailing-whitespace: null
unnecessary-pass: null
unused-argument: null
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<rect width="128" height="128" rx="24" fill="#4a7c59"/>
<text x="64" y="86" font-family="sans-serif" font-size="64" fill="#ffffff" text-anchor="middle">M</text>
</svg>

After

Width:  |  Height:  |  Size: 260 B

+43
View File
@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://blboaodg2nrl7"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
+26
View File
@@ -0,0 +1,26 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Les Aventuriers des mots"
run/main_scene="res://scenes/boot/boot.tscn"
config/features=PackedStringArray("4.6", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
GameManager="*res://autoload/game_manager.gd"
ProfileManager="*res://autoload/profile_manager.gd"
ProgressManager="*res://autoload/progress_manager.gd"
ExerciseEngine="*res://autoload/exercise_engine.gd"
SaveManager="*res://autoload/save_manager.gd"
AudioManager="*res://autoload/audio_manager.gd"
SettingsManager="*res://autoload/settings_manager.gd"
+3
View File
@@ -0,0 +1,3 @@
[gd_scene load_steps=1 format=3]
[node name="Boot" type="Node"]
+46
View File
@@ -0,0 +1,46 @@
extends SceneTree
## Outil headless invoque par `make validate-data`.
## A ce stade, verifie seulement que les fichiers data/**/*.json sont du JSON bien forme.
## La validation contre les schemas (rule, exercise, dictation, curriculum, save) sera
## ajoutee a l'etape "Donnees" (voir Ordre de construction, docs/specs/decisions.md point 2).
func _init() -> void:
var json_paths: Array[String] = _find_json_files("res://data")
var failures: Array[String] = []
for path in json_paths:
var file := FileAccess.open(path, FileAccess.READ)
if file == null:
failures.append("%s : lecture impossible" % path)
continue
var text := file.get_as_text()
if text.strip_edges().is_empty():
continue
if JSON.parse_string(text) == null:
failures.append("%s : JSON invalide" % path)
if failures.is_empty():
print("validate-data : %d fichier(s) JSON valide(s)" % json_paths.size())
quit(0)
else:
for failure in failures:
printerr(failure)
quit(1)
func _find_json_files(root_path: String) -> Array[String]:
var result: Array[String] = []
var dir := DirAccess.open(root_path)
if dir == null:
return result
dir.list_dir_begin()
var entry := dir.get_next()
while entry != "":
if entry != "." and entry != "..":
var full_path := root_path.path_join(entry)
if dir.current_is_dir():
result.append_array(_find_json_files(full_path))
elif entry.ends_with(".json"):
result.append(full_path)
entry = dir.get_next()
return result
+1
View File
@@ -0,0 +1 @@
uid://01g5hgfcb5tq
+14
View File
@@ -0,0 +1,14 @@
extends GutTest
## Verifie que le squelette du projet charge correctement les sept autoloads.
## Les tests de logique pedagogique (correction, progression, sauvegardes)
## arrivent avec les etapes correspondantes.
func test_autoloads_are_registered() -> void:
assert_not_null(GameManager, "GameManager doit etre charge")
assert_not_null(ProfileManager, "ProfileManager doit etre charge")
assert_not_null(ProgressManager, "ProgressManager doit etre charge")
assert_not_null(ExerciseEngine, "ExerciseEngine doit etre charge")
assert_not_null(SaveManager, "SaveManager doit etre charge")
assert_not_null(AudioManager, "AudioManager doit etre charge")
assert_not_null(SettingsManager, "SettingsManager doit etre charge")
+1
View File
@@ -0,0 +1 @@
uid://bgko12vcwsipr
Executable
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Installe l'outillage de developpement : binaire Godot pinne, addon GUT,
# environnement Python pour gdtoolkit. Rien de ceci n'est commite (voir .gitignore) :
# ce script est la seule source de verite pour reconstruire l'outillage.
set -euo pipefail
cd "$(dirname "$0")/.."
GODOT_VERSION="$(cat .godot-version)"
GODOT_BIN_DIR=".godot-bin"
GODOT_BIN="${GODOT_BIN_DIR}/godot"
GUT_VERSION="v9.6.0" # v9.6.1+ reference AccessibilityServer, absent de Godot 4.6.3
GDTOOLKIT_VERSION="4.5.0"
mkdir -p "${GODOT_BIN_DIR}"
if [ ! -x "${GODOT_BIN}" ]; then
echo "Telechargement de Godot ${GODOT_VERSION}..."
TMP_ZIP="$(mktemp)"
curl -sL -o "${TMP_ZIP}" \
"https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}/Godot_v${GODOT_VERSION}_linux.x86_64.zip"
unzip -o -j "${TMP_ZIP}" -d "${GODOT_BIN_DIR}"
mv "${GODOT_BIN_DIR}/Godot_v${GODOT_VERSION}_linux.x86_64" "${GODOT_BIN}"
chmod +x "${GODOT_BIN}"
rm -f "${TMP_ZIP}"
else
echo "Godot deja present dans ${GODOT_BIN}."
fi
if [ ! -d "addons/gut" ]; then
echo "Telechargement de GUT ${GUT_VERSION}..."
TMP_TAR="$(mktemp)"
TMP_DIR="$(mktemp -d)"
curl -sL -o "${TMP_TAR}" \
"https://github.com/bitwes/Gut/archive/refs/tags/${GUT_VERSION}.tar.gz"
tar xzf "${TMP_TAR}" -C "${TMP_DIR}"
mkdir -p addons
cp -r "${TMP_DIR}"/Gut-*/addons/gut addons/gut
rm -rf "${TMP_TAR}" "${TMP_DIR}"
else
echo "GUT deja present dans addons/gut."
fi
if [ ! -d ".venv" ]; then
echo "Creation de l'environnement Python pour gdtoolkit..."
python3 -m venv .venv
fi
./.venv/bin/pip install --quiet --upgrade pip
./.venv/bin/pip install --quiet "gdtoolkit==${GDTOOLKIT_VERSION}"
echo "Setup termine : Godot ${GODOT_VERSION}, GUT ${GUT_VERSION}, gdtoolkit ${GDTOOLKIT_VERSION}."