Releases: lionrayonnant/FPVThePlanet
Release list
v1.2.0
Ajouté
- La nomenclature devient vérifiable. Chaque famille nomme désormais son
moteur, son hélice et son pack par leur identifiant de catalogue
(motor.part,propPart,battery.part), etprofile-schema-selftest
refuse une référence qui ne résout pas, un KV qui contredit son entrée, une
diagonale d'hélice ou un pas qui ne sont pas ceux du catalogue. Le 2207 à
2450 KV de la référence — la dernière référence du fichier qui n'était pas un
fait — est déclaré dansOFF_CATALOGUE_MOTORSavec sa provenance, pas
dansSPEC_MOTORS: ce catalogue est une transcription dont le nombre
d'entrées est épinglé, et y ajouter une ligne serait exactement ce que cette
vérification existe pour attraper. Rien ne bouge en vol :freestyle5reste
la référence au bit près. - BENCH : la machine exacte (#159). L'aéronef du banc n'est plus un menu
déroulant sur six familles, c'est un montage. Une BASE —NOMINAL, un
exemplaire tiré (INDIVIDUAL), ouCUSTOM, assemblé depuis le catalogue de
la spec (21 moteurs, 20 hélices, 13 châssis, 17 packs, 3 caméras) — et,
par-dessus, 45 paramètres réglables au chiffre près : masse, inerties, bras,
hélice, moteur, pack, traînée, PID, rates, courbe de gaz, bruit gyro, latence
de boucle. La dérivation CUSTOM n'invente rien : elle applique les quatre
règles déjà écrites en tête dedrone-profiles.js.NOMINALsans réglage
reste exactement le profil de référence — la fonctionnalité est inerte
tant qu'on n'y touche pas. - La radio se règle en vol, au banc (#159).
ON AIR, le pool, le morceau et
le transport dans le panneau de vol du banc : le jukebox continuait de jouer
après qu'on en sortait, mais plus rien n'y donnait accès une fois en l'air.
Au banc seulement — en FIELD la musique est l'arc de la Bible §34.
Modifié
- Le nombre de vérifications n'est plus annoncé à trois endroits
différents.README.mddisait « 2 700+ »,docs/manual.md« ~1 430 »,
CONTRIBUTING.md« environ 1 200 » : trois chiffres pour une seule chaîne.
Le manuel le porte seul, mesuré (~3 200), avec la commande qui le recompte.
Le manuel gagne au passage la liste complète des scripts de
sim/package.json—electron,sync-scenes,resume,replay,
validate:propset les autres n'y figuraient nulle part. package-lock.jsonest réindenté en tabulations, celles que npm réécrit
en lisantpackage.json: chaquenpm installlaissait sinon un diff de
5 983 lignes dans l'arbre de travail. Aucune dépendance ne change.CLAUDE.md,HANDOFF.mdetdocs/PICKUP.mdcessent de décrire un dépôt
privé et une branche non fusionnée. Le passage au public est fait des deux
côtés qu'il annonçait (provider: github, jeton de déploiement facultatif),
et le lot « gravité » est surmain.propInertiaest dérivé au lieu d'être choisi. Normalisé en
k = I / (m * R^2), le fichier impliquait un k de 0,115 à 0,620 sur sept
pièces qui sont le même objet moulé à des tailles différentes. Une hélice est
géométriquement auto-similaire : pales effilées portant leur masse en dedans,
sur un moyeu à rayon quasi nul. La tige uniforme donne 1/3, l'effilement et
le moyeu ramènent dans 0,2–0,3, et la référence mesure 0,248 — c'est la
constante, et la masse vient du catalogue. Le nombre de pales n'entre pas, et
c'est un résultat : 4 g pour un 5", 7 g pour un 6" et 2 g pour un 3" sont des
masses de tripale et ces familles volent en tripale ; 8 g pour un 7" et 1 g
pour un 2,5" sont des masses de bipale (un 7" tripale pèse 11-12 g) et ces
familles volent en bipale. Chaque masse du catalogue est déjà celle de
l'hélice embarquée. Corrections : cinewhoop −60 %, toothpick −17 %, race5
+11 %, swarmNode +46 %, longrange +115 % — cette dernière parce que son
commentaire comptait le nombre de pales deux fois, en partant d'un 1,1e-5
deviné pour un 7" tripale puis en le multipliant par 2/3, alors que les 8 g du
catalogue sont déjà la bipale.freestyle5etheavy5ne bougent pas d'un
bit, les six séquences denpm run replayle confirment.- L'inertie de
swarmNodeest reconstruite à partir de ses pièces. Elle
était « heavy5 mise à l'échelle, interpolée vers longrange », et longrange a
bougé sous elle (0,92 → 1,05 kg, tripale → bipale de catalogue, inertie
refaite). Une interpolation ne vaut que ses extrémités : elle est remplacée
par le modèle que longrange documente — quatre masses ponctuelles aux coins
plus une boîte équivalente calibrée sur freestyle5 —, qui reproduit ses deux
points de calibration à 0,3 %. Résultat 11 à 13 % plus bas, et un rapport
I_lacet/(I_tangage+I_roulis)de 0,942 qui la remet dans la bande où sont les
six autres au lieu de 0,920 toute seule. Le départ connu est écrit : ~170 g de
radio maillée sont au mât, au-dessus du centre de masse, et la boîte les
répartit. - Les six réglages PID sont rebalayés, plus celui de swarmNode, contre les
nouvelles inerties.freestyle5etheavy5en ressortent identiques.
Corrigé
-
Les réglages audio ne prenaient effet qu'au hack suivant. Les trois
curseurs (Volume, Tone, Music) n'étaient branchés sur le son qu'au démarrage
d'une scène (finishBoot) : ouverts depuis le terminal, ils écrivaient le
localStorageet leur libellé, et rien d'autre. Le branchement se fait
désormais une seule fois, au chargement du module. Et il ne suffisait pas :
audio-bus.jsignorait un volume demandé avant l'existence du contexte audio
— il le mémorise maintenant et construit son graphe à cette valeur. -
Trois indications du HUD pointaient à l'envers. Après
prep, les
coordonnées sont en mètres ENU locaux avec Z = sud : le nord est-Z, et
chaque relèvement porte un signe moins facile à perdre. Trois lectures
l'avaient perdu, chacune à sa façon. La flèche HOME calculait
atan2(dx, dz): le point de départ droit devant était dessiné droit
derrière — gauche et droite sortant justes, personne ne l'avait vu. Le ruban
de cap publiait le lacet du quaternion, qui est l'opposé du cap : nez à
l'est, il affichait 270 ; leheadingDegde la piste, donc le cap stocké avec
chaque photo, portait la même inversion. La flèche de vent du HUD, elle,
inversait gauche et droite : un vent de travers venant de gauche était dessiné
comme poussant vers la gauche. Les trois sites faisaient chacun leur propre
trigonométrie ;src/bearing.jsla tient désormais seul, et
tools/bearing-selftest.mjsépingle les cas tels que le pilote les voit. -
Le compteur DECODING de l'écran de chargement pouvait passer sous zéro.
Incrémenté sur le seul messagestage: 'decoding', il était décrémenté sur
tout message terminal — y compris l'échec qu'un worker renvoie quand son
téléchargement a échoué avant tout décodage. Une planche en 404 et l'écran
affichait « DECODING -1 SHEET(S) ». -
Un chunk en échec abandonnait ses voisins. Le chargement entier était
rejeté, mais les deux autres workers continuaient de décoder (~135 Mo chacun)
vers une scène que personne ne monterait, et les matières déjà poussées dans
tileMaterialsn'étaient jamais rendues :dispose()libère le GPU, pas le
tampon de pixels JS. Un chargement qui échoue arrête maintenant ses voisins et
rend ce qu'il a construit. -
Quitter une acquisition laissait fuir son minuteur de silence.
LEAVE
arrêtait l'horloge, la RTC et le flux SSE, mais pas le minuteur quefinish()
nettoie — et celui-ci écrit dans.sc-job-note, résolu contre le panneau
monté au moment où il se déclenche. Partir dans les dix secondes puis lancer
une autre acquisition faisait écrire « LINK INTERRUPTED » par-dessus le
nouveau travail, en bonne santé. -
Le pied d'une colonne nulle passait sous l'axe dans l'onglet DATA
(Math.max(..., v > 0 ? 1 : 1)contre un sommet planché à 0), et la grille de
repli d'entry-state.jsannonçait uncellSizelu sur les cellules de la
grille au lieu de son propre pavé. -
La convention de
battery.maxCurrentest tranchée et épinglée. Le champ
est documenté « A aux quatre moteurs plein gaz », donc le tirage du build ;
la note du pack, elle, vautcapacité * C— pour le4s-1300de la
référence, 195 A contre les 100 A du tirage. Les deux nombres sont vrais et ne
sont pas la même grandeur, et c'est cette ambiguïté qui faisait passer le
champ pour incohérent. La règle 3 du fichier donne le tirage, les sept
familles la respectent à mieux que 1 %, et un test le vérifie — avec un second
qui compare au plafond du pack. À savoir en le lisant : aucune physique ne
litmaxCurrent, le pack s'affaisse sur le vrai courant de bobinage issu de
la balance de couple demotor.js. C'est un chiffre de fiche technique, ce
qui est précisément pourquoi il lui faut un test et pas un lecteur.
Ajouté
?aero=bem: l'hélice en théorie de l'élément de pale, éteinte par
défaut.src/blade-element.jsexistait, validé sur 187 hélices de
soufflerie, et n'était branché nulle part : le câbler remplace le modèle de
poussée et invalide six réglages sur la foi d'un terme edgewise qu'aucun banc
d'ici ne peut vérifier — la soufflerie UIUC souffle dans l'axe. Il est donc
câblé derrière un drapeau, plombé comme?loop=, et le chemin par défaut est
identique au bit près :cmpne trouve pas un octet d'écart sur les 36
traces denpm run replay, et un selftest compare 400 pas élément par élément
entre le défaut,aero:'classic'explicite et un drapeau inconnu. Ce que le
drapeau achète, c'est que le terme edgewise devienne mesurable à défaut
d'être vérifiable :tools/aero-model-compare.mjsmet les deux modèles côte à
côte — poussée, couple et force en plan, du stationnaire à la croisière, plus
la garde de #103 jouée contre les deux. Ce qu'il dit : la lame rend 14 à 30 %
de poussée en moins au stationnaire, et tout cet écart est `pr...
v1.1.0
Ce que la première mise en ligne réelle a trouvé. La 1.0.0 a été taguée avant
qu'une instance publique existe : tout ce qui suit a été découvert en la
déployant pour de bon, et rien de tout cela ne pouvait l'être autrement.
Corrigé
-
Le curseur disparaissait dès qu'un clic tombait à côté d'un bouton. Le
curseur EST le focus natif du navigateur : cliquer sur le fond d'un écran, un
titre ou une ligne de texte le fait perdre, plus rien ne porte le marqueur ▌
et Entrée n'active plus rien. Il fallait une flèche — qui repartait du haut de
la liste — ou Échap pour ressortir et revenir. Le focus est désormais reposé
là où il était, surfocusoutplutôt qu'en bloquant lemousedown: la
sélection à la souris reste possible, et on sélectionne à la main dans ces
écrans (une adresse de paiement, une ligne de journal). Sortir d'un champ de
saisie reste une intention : le curseur repart alors du premier contrôle sur
lequel on peut appuyer, sans y être renvoyé.Deux déclencheurs, parce qu'un seul navigateur ne suffit pas à prouver un
correctif de focus : Chrome ne déplace le focus qu'une fois, aumousedown,
etfocusouty suffisait ; Firefox défocalise aumousedownPUIS
réattribue le focus à la fin du clic — le rétablissement, différé d'un tour,
tombait entre les deux et le clic le défaisait. L'écouteurclick, qui passe
après toute la séquence souris, est celui qui tient dans cet ordre-là. Les
deux sont sans effet quand le focus est déjà quelque part dans l'écran. -
JUKEBOX, onglet ALL : les lignes étaient écrasées à 6,5 px. Les 143
morceaux étaient bien là, dans l'ordre, avec le bon texte, et aucun n'était
lisible. Unflex-direction: columnavec unmax-heightne déborde pas dans
sa barre de défilement : par défaut il rétrécit ses enfants jusqu'à ce que
tout rentre. En dessous d'une vingtaine d'éléments rien ne bouge — d'où un
filtre par pool parfait et un seul onglet cassé. La même forme existait quatre
fois (les deux listes, le panneau des réglages, la page DATA) ;
tools/list-layout-selftest.mjsrefuse désormais une cinquième qui
l'oublierait. -
La carte de l'onglet LIVE ne s'affichait plus : toutes les tuiles
OpenStreetMap revenaient en 403 « Access blocked ». L'en-tête
Referrer-Policy: no-referrer, ajouté par la passe de sécurité de la 1.0.0,
retirait leRefererdes requêtes de tuiles — or la politique d'usage d'OSM
exige unRefererou un User-Agent qui identifie l'application, et un
navigateur n'envoie qu'un User-Agent générique. Remplacé par
strict-origin-when-cross-origin, qui garde l'intention : le même-origine
conserve l'URL complète, donc le slug de scène et la graine de build ne
sortent toujours pas, et OSM reçoit l'origine nue dont il a besoin.Invisible en développement, parce que Vite ne sert aucun de ces en-têtes :
seule une vraie mise en production pouvait le montrer. Concerne aussi les
applications de bureau 1.0.0, qui embarquent le même serveur. -
deploy.shtéléchargeait les métadonnées JSON de l'asset au lieu de
l'archive, ettaréchouait sur « not in gzip format ».gh_apipose
Accept: application/vnd.github+jsonet la fonction de téléchargement en
ajoutait un second enapplication/octet-stream: curl envoie les deux,
GitHub honore le premier. Le script passe maintenant par
browser_download_url, qui sert les octets sans négociation de contenu —
possible parce que le dépôt est public. Il vérifie en plus que le fichier
reçu est bien une archive, et affiche ses premiers octets sinon. -
Caddy journalise vers journald au lieu d'un fichier.
output fileimposait
de créer/var/log/caddyà la main, entre deux étapes précises, et refusait
quand même de démarrer le service alors que le répertoire appartenait bien à
caddyet y était inscriptible. Une ligne de configuration pour un mode de
panne spécifique à la plateforme :journalctl -u caddy -fdonne les mêmes
accès et laisse la rotation au système.
Modifié
deploy/README.md: la checklist supposait un shell root sans jamais dire
comment en obtenir un, alors qu'aucun hébergeur ne donne root — la première
commande échouait après avoir eu l'air de fonctionner. Le piège du tube est
signalé avec (sudodoit élevergpgettee, pascurl).- La consigne de durcissement SSH nommait le fichier
sshd_config.d/99-hardening.conf.sshdapplique la première définition
qu'il lit et parcourt les extraits dans l'ordre lexical — l'inverse de la
convention systemd. Les images cloud Ubuntu livrent un50-cloud-init.conf
avecPasswordAuthentication yes, qui gagnait : le fichier de durcissement
existait, disait la bonne chose, et ne faisait rien. Renommé en01-, et la
vérification lit désormaissshd -Tplutôt que le fichier. README.md: la construction de l'app de bureau réclamenpm run build
d'abord.electron-builderempaquettedist/tel quel sans jamais le
reconstruire, etdist/est gitignoré, donc changer de branche puis
empaqueter livrait la nouvelle coquille Electron autour de l'ancien jeu.- Le crédit d'imagerie Google descend au bas de la colonne FIELD, avec les
autres mentions légales — licence, sources — au lieu d'être coincé entre le
rail LIVE et ce qui décolle, où il se lisait comme une étape du parcours.
Toujours sur LIVE seulement : le terrain déjà sur le disque a emporté son
crédit avec lui.
Ajouté
-
Un pourboire, en trois marques. Le pied de page de FIELD porte les logos
Cake Wallet, Bitcoin et Monero, dessinés dans la grille 12×12 du jeu, sous une
ligne qui dit à quoi ça sert. Chacun ouvre une petite fenêtre par-dessus FIELD
— la carte, l'épingle et la zone choisie restent exactement où elles étaient.
Un logo se reconnaît avant de se lire, ce qu'un bouton « SUPPORT » ne faisait
pas, et un pot à pourboires n'a pas besoin de tout le cadre pour dire une seule
chose.Trois adresses — Monero, Bitcoin en paiement silencieux (BIP352), Bitcoin
classique, les deux dernières dans la même fenêtre puisque c'est une seule
décision pour qui donne — plus une poignée Cake lisible,fpvtp@cake.cash,
la seule ligne qu'un humain peut retenir ou dicter : quatre-vingt-quinze
caractères de base58 ne sont pas une interface. Chaque adresse est affichée
en entier, jamais tronquée, et copiable d'un bouton qui dit s'il a réussi.Crypto uniquement : tous les rails fiat vérifient l'identité du bénéficiaire,
ce que ce projet ne propose pas, et une page de paiement à l'état civil
déferait le pseudonyme que le dépôt tient partout ailleurs. La fenêtre ne le
dit pas — expliquer l'absence de bouton carte transforme une petite offre en
plaidoirie ; c'est le README qui porte le raisonnement.Les adresses vivent dans un module pur,
tools/support-model.mjs, pour une
raison précise :tools/support-selftest.mjsles revérifie par checksum à
chaque passage de CI — bech32 et bech32m pour Bitcoin, Keccak-256 pour
Monero, l'implémentation étant elle-même contrôlée sur le vecteur de test
officiel avant qu'on lui fasse confiance. Une coquille dans une légende est
embarrassante ; une coquille dans une adresse envoie l'argent d'un inconnu là
où personne ne pourra jamais le dépenser, et le dépôt comme les binaires la
porteraient pour la durée de la version. -
Le jeu dit où sont ses sources. Sous le pied de page de FIELD, une
catégorie à part — « SOURCE · LEAVE A STAR ON GITHUB », le logo GitHub et
AGPL-3.0—, cliquable, et la même marque discrète dans l'OSD en vol.
Ce n'est pas de la promotion : l'article 13 de l'AGPL exige qu'un joueur qui
interagit avec le programme à travers un réseau se voie offrir les sources
correspondantes — or sur l'instance de quelqu'un d'autre, il ne voit jamais le
dépôt, ni le fichierLICENSE, ni le README. L'offre doit être dans le
programme.Les icônes viennent du jeu lui-même :
src/pixel-icons.js(PHASE 20, Bible
§41) existait depuis longtemps et n'était branché à rien ; c'est son premier
usage. La bibliothèque gagne quatre marques — GitHub, Bitcoin, Monero, un
gâteau pour Cake Wallet — dessinées pour survivre à douze pixels : la
silhouette pour GitHub, le ₿ sans sa pièce, l'anneau et le M de Monero. Le
mot est ce qu'on décode, la marque est ce qu'on reconnaît. En vol elle n'est
pas
cliquable : le vol capture le pointeur, une cible dans l'image serait un
piège ; c'est le pied de page du terminal qui porte le lien. -
deploy/README.mdgagne une section « Hardening the machine » : SSH par
clés, restriction du port 22,fail2ban, mises à jour automatiques, et le
mode SSL à vérifier derrière un CDN. Le service était déjà bien confiné par
son unité systemd ; la machine, elle, n'était couverte nulle part.
Which file do I download?
| File | For whom |
|---|---|
FPVTP-*-win-x64.exe |
Play on Windows. Installer: Start Menu entry, uninstaller, automatic updates. It is not code-signed, so SmartScreen warns on first launch. |
FPVTP-*-linux-x86_64.AppImage |
Play on Linux. Make it executable, double-click. Automatic updates. |
fpvtp-server-*-linux-x64.tar.gz |
Host an instance. The server, the built game, a Node runtime and deploy/ (systemd unit, Caddyfile, delivery script, checklist). No npm install to run. |
latest.yml, latest-linux.yml, *.blockmap |
Update plumbing, read by the installed app. Not meant to be downloaded by hand. |
There is no macOS build.
To play: take the one file for your system, that is the whole install.
To host: unpack, then follow deploy/README.md. The server listens on
127.0.0.1 and refuses to listen wider without --mode shared, which
then demands an operator key on every API request.
The game is under AGPL-3.0: if you host a modified version
for other people, you must publish its sources to them.
v1.0.0
Première version publique. Le jeu existait déjà en 0.3.0 ; ce qui change ici,
c'est qu'il est fait pour être rencontré par quelqu'un d'autre que son auteur.
- On vole au-dessus d'une vraie ville, dans le navigateur, en photogrammétrie
Google Earth diffusée pendant le vol. Aucun terrain à télécharger d'abord :
on clique un point sur la carte, on vole quinze secondes plus tard, et les
tuiles vont directement de Google au navigateur du joueur sans passer par un
serveur. - Le clavier est jouable. Sans manette, le vol démarre en angle et les axes
montent progressivement ; une manette reçoit toujours de l'acro inchangé. - Un navigateur sans WebGL2, un serveur de tuiles bloqué, un délai dépassé :
les trois disent maintenant ce qui se passe au lieu d'une page noire, d'une
impasse ou d'un vide infini. - Une passe de sécurité complète, avec exploits reproduits : évasion par lien
symbolique, injection HTML stockée, limite d'inscription contournable,
routes non bornées, allocation pilotée par le réseau, et deux portes
Electron. - L'imagerie Google est créditée sur le chemin que tout le monde emprunte.
Elle ne l'était pas. - Les surfaces publiques — README, workflows, notes de version, manuel,
serveur, outils — sont en anglais. - 2 700 vérifications automatiques et une passe de fuzzing à graine fixe dans
la même chaîne, exécutée avant chaque publication.
Le détail, rubrique par rubrique.
Ajouté
-
Un navigateur sans WebGL2 dit pourquoi, au lieu d'une page noire sans un
mot. three r170 demande un contextewebgl2et rien d'autre, et
WebGLRendererlève au niveau module :main.jsétait interrompu avant même
que le Hud qui aurait pu le signaler existe. La sonde vit maintenant dans
index.html, en script classique, avant le module — sans bundle, sans
feuille de style, sans police, styles en ligne : quoi qu'il ait échoué plus
bas, ces mots arrivent à l'écran. Elle nomme les quatre choses qui règlent
vraiment le problème. -
L'écran d'échec a une sortie :
[ RELOAD ], Échap et Entrée. Il n'en avait
aucune, ce qui faisait de tout blocage dekh.google.com— un bloqueur de
publicité, un VPN, un proxy d'entreprise — la fin de la visite. Le message
nomme désormais cette cause au lieu de se taire. -
Les fichiers qu'un dépôt public doit avoir :
CONTRIBUTING.md,
SECURITY.md,CODE_OF_CONDUCT.md, un gabarit de pull request, une
configuration de gabarits d'issue qui ferme l'issue vide et route les
questions vers Discussions et les vulnérabilités vers le formulaire privé,
etdependabot.yml. -
Nouveaux selftests :
first-run-selftest.mjs(18 vérifications, dont
l'exécution de la vraie sonde d'index.html),rocktree-unpack-selftest.mjs
et le modèle purboot-failure-model.mjs. -
Une passe de fuzzing,
npm run fuzz(sim/tools/fuzz.mjspour les
modules purs,sim/tools/fuzz-api.mjspour les routes HTTP contre un vrai
serveur, harnais partagé danssim/tools/lib/fuzz.mjs). Seize cibles, chacune
avec l'invariant qu'elle vérifie et le modèle de menace de son entrée ; graine
fixe, donc rejouable et intégrée àselftest:ci. Ce qu'elle a trouvé est dans
sim/docs/handoff-archive/fuzzing.md. -
Bibliothèque musicale : 143 pistes au lieu de 73. Chaque pool double à peu
près, et le drone d'essaim reçoit enfin le sien,swarmNode, 10 pistes. Aucune
piste retirée. -
Dialogue : un nouveau lot d'environ 100 répliques par shard sur les onze
événements, soit 1 100 entrées de plus. -
JUKEBOX (#120), cinquième voie à la racine : la bibliothèque musicale entière,
enfin écoutable. Jusqu'ici un morceau ne s'entendait que si le tirage le
donnait — déterministe sur la famille et la graine du drone — et tout le reste
restait invisible. C'est une radio et pas un lecteur : elle enchaîne toute
seule, et elle continue de jouer quand on la quitte, dans les menus comme
en vol. On choisit sa bande-son, puis on décolle avec.Elle n'est pas la musique du vol pour autant. L'arc du hack — la musique
sourde, le duck du rituel, l'explosion au drop, l'intensité qui suit le
pilote, la mort au choc — appartient à FIELD et ne bouge pas d'un pouce
lorsque la radio est éteinte. Quand elle joue, elle joue à plat et le vol ne
la touche plus : ni filtre aux gaz, ni coupure au crash. -
Un pool musical pour SWARM NODE (#116). La 7ᵉ famille — le nœud de
commandement d'un essaim — était absente deMUSIC_POOLS: le vol le plus
rare du jeu était aussi le seul à se jouer en silence. Son noyau est une
techno dure menée par le kick, hoover gras en lead, sèche et proche ; à
Carpenter elle emprunte l'ossature — ostinato mineur figé sur une pédale de
basse immobile — et non le timbre. 132-142 BPM. -
Mode turtle (#105). Une machine sur le dos n'avait qu'une issue depuis D9 :
couper le lien et la perdre. Une touche —Tpar défaut, remappable comme les
autres — la remet à l'endroit, et la ligne[T] TURTLEs'affiche à l'écran
dès que la machine est immobile ET sur le dos, au-dessus du rappel
[HOLD K] CUT LINK: des deux issues, celle qui rend la machine se lit avant
celle qui la perd. Le retournement est assisté plutôt que piloté aux moteurs
inversés (pas demotors[4]signé, pas de modèle de pale inversée), mais son
couple est plafonné à ce que deux moteurs de l'appareil peuvent réellement
produire, et il s'arrête seul — assiette rétablie, ou délai dépassé. -
La culmination du hack est de retour (#101). Le retrait du CONTROL VECTOR
(#33) avait supprimésrc/ritual.jsen entier, alors que le problème tenait
à la moitié haute du fichier : la saisie d'un vecteur mémorisé hors du jeu,
qui bloquait un joueur l'ayant oublié. La culmination qui suivait est partie
avec elle, et[ JACK IN ]coupait droit au résultat.
Elle revient seule, sur son propre écran entre l'invite etCONTROL ACQUIRED:src/culmination.js, une à quatre secondes plein écran
(variante V1–V4 tirée sur la graine de la cible,
tools/culmination-model.mjs), les primitives demo scene pondérées par
famille (FAMILY_PRIMITIVES, revenu danssrc/hack-grammars.js), les quatre
couleurs d'événement, un coup à chaque battement, et la signature sonore de
la famille (CULMINATION_SCORES/scoreFordans
tools/ui-audio-model.mjs,uiAudio.playCulmination()) pendant que la
musique se retire. Rien à presser : elle démarre seule, rend la main seule,
Échap saute le battement.prefers-reduced-motionla réduit à un seul
battement sans flash.
Ce qui ne revient pas : la saisie du vecteur, son riser (ritualTension) et
le blocage qu'ils portaient. La Bible §19 compte donc à nouveau deux porteurs
de la palette demo scene, l'intro et la culmination, ce que vérifient
tools/palette-selftest.mjsettools/intro-primitives-selftest.mjs. -
Le modèle de vol connaît maintenant le vol en translation (#91). Trois
mécanismes qui manquaient, et que tout pilote ressent :- Portance de translation : en avançant, le rotor s'échappe de son propre
flux induit et gagne en rendement — +21 % de poussée à 20 m/s sur le 5"
de référence. Ce n'est pas un terme de plus :kInflowEST déjà la pente
d'inflow de la théorie du disque, et le nouveau calcul la GÉNÉRALISE, en
forme fermée (Glauert), sans itération à 250 Hz. L'air calme et le vol
purement vertical restent identiques au bit près, et la branche de descente
est laissée telle quelle : entre −2·vh et 0 la théorie n'a pas de solution
du tout, et ce régime est déjà modélisé empiriquement comme propwash. Flapback: ajouté puis retiré avant publication (#103, voir
Corrigé plus haut) — les deux moments qu'il apportait rendaient l'appareil
impilotable en vitesse.- Précession des rotors : un lacet pendant un roulis déplace le nez.
Complémentaire du terme d'inertie d'hélice déjà présent en lacet, pas
redondant : l'un a besoin que le régime CHANGE, l'autre seulement qu'il ne
soit pas nul.
Aucun nouveau réglage par famille : tout se dérive de la géométrie et des
coefficients existants.
- Portance de translation : en avançant, le rotor s'échappe de son propre
-
sim/tools/aero-selftest.mjs: banc sans Rapier, sans scène et sans
navigateur, dans la chaîne CI, qui affirme des identités et jamais des
nombres relevés — le résidu de Glauert, la limite de saturation contre la
constante d'inflow elle-même, le câblage exact de la précession avec l'inflow
coupé pour l'isoler. Il porte aussi une version headless de la porte
anti-divergence sous roulis tenu, qui exigeait Rapier et une scène installée. -
node tools/tune-pid.mjs --cruisefait voler le banc en avant, à la vitesse
d'équilibre propre à chaque famille, et juge un candidat sur le PIRE des deux
régimes. Les PID livrés ne changent pas : au point de fonctionnement du banc
le plant n'a pas bougé —npm run tuneest identique au bit près — donc le
tune reste exactement aussi mesuré qu'avant. -
La marque entre dans le jeu (#73).
docs/brand.mdréservait depuis toujours
le verrouillage empilé — le symbole, puisF P V T P !dessous — au « splash,
boot » ; il n'avait jamais été posé, et la marque ne sortait que du favicon et
de la carte Open Graph. Elle tient maintenant le cracktro de lancement, et
elle s'y trace module par module : le cadre d'abord, parce que le cadre
EST le panneau, puis les quatorze cellules en ordre de lecture, puis le nom
s'inscrit dessous. La marque est un randomart figé (brand.md) et un
randomart, dans ce jeu, ça se trace (#57). -
Tout tient dans la phase
revealde l'intro : aucune durée nouvelle,
tools/intro-model.mjsne bouge pas, et le selftest refuse un tracé qui
déborderait sur la plasma. Le sinus-scroll ne possède plus que la phase
plasma— pendantrevealet à la résolution le verrouillage est immobile et
exact, c'est-à-dire juste aux deux moments où l'œil le lit. -
La marque ne prend jamais une couleur demo, pas même sous la plasma : le
cyan et le magen...
v0.3.0
Ajouté
- Le menu a quatre voies au lieu de deux :
FIELD,BENCH,ARCHIVE,
SETTINGS, à la racine et dans cet ordre. ARCHIVE n'est plus un lien enterré
dans un onglet de FIELD, SETTINGS n'est plus répété à trois endroits, et
fpvtp.moderetient les quatre (#6, #7). - Un briefing de quatre écrans (
INPUT,THE TERMINAL,A SESSION,
BRIEFING COMPLETE) accueille un opérateur qui vient d'être créé, juste
après le CONTROL VECTOR. Il énonce, il n'ordonne pas ; Échap le saute ;
[ CALIBRATE ]et[ MAP KEYS ]ouvrent le bon onglet deSETTINGSet
reviennent, et l'écranINPUTlit le mappage en direct. Il se rejoue par
SETTINGS›SYSTEM›[ REPLAY BRIEFING ]. Le premier vol hors banc
affiche trois lignes brèves —THROTTLE UP,[TAB] SETTINGS,
[HOLD K] CUT LINK, cette dernière nommant la touche réellement liée et
comptée depuis le décollage — puis plus jamais (#16). - Le panneau
SETTINGS(Tab) passe à la direction artistique du terminal :
en-têteFPVTP! // SETTINGS, quatre ongletsCONTROLLER · KEYBOARD · AUDIO · SYSTEM, un corps à la fois, et l'onglet ouvert est retenu pour la session.
KEYBOARDliste chaque action avec ses touches et un[ REBIND ]: la
touche suivante est prise, Échap annule, une touche déjà prise déclenche un
échange annoncé sur la ligne,[ RESET KEYS ]remet les valeurs d'usine.
SYSTEMporte la portée d'affichage (mode?live=),[ RESET SETTINGS ]
et le numéro de version (#15). - Les commandes clavier passent par une table remappable (
src/key-map.js) :
une action porte un nom (throttleUp,pause,cutLink…), ses touches se
changent, et les valeurs par défaut couvrent QWERTY et AZERTY (W/Z, A/Q).
Réglages rangés dansfpvtp.keyMap; Tab, Échap et Entrée restent fixes. - La caméra libre (
C, une orbite qui gelait le monde) devient une bascule de
vueV: FPV / CHASE. La vue CHASE est la caméra de vol reposée 1,1 m
derrière le nez et 0,45 m au-dessus, champ plafonné à 75° et OSD de la cible
débranché (c'est une caméra extérieure, pas le flux vidéo), la simulation
continue de tourner derrière elle, et elle marche sur tous les chemins
(LOCAL, LIVE, BANC). Un
bouton[V] FPV/[V] CHASEen haut à droite de l'OSD fait le même geste
à la souris. Chaque vol commence en FPV (#12). - L'écran de fin de vol montre la machine perdue en 3D, celle qui volait —
livrée, numéro et châssis compris — et on peut la tourner à la souris. Elle
tourne seule d'un tour toutes les 24 s. Sans contexte WebGL, le portrait fil
de fer d'avant prend le relais ; l'archive, elle, garde le SVG (#13). - Tests couvrant qu'un vol EN DIRECT remplit bien le Session Log, le Target
Log et le compteur OPERATOR, et n'est jamais proposé en REVISIT/RESUME (#8).
Modifié
-
FIELD ouvre sur l'onglet
LIVE, désormais placé avantLOCAL: c'est la voie
qui marche sans rien avoir téléchargé. Sur un serveur qui n'acquiert pas,
l'onglet LOCAL est éteint et dit en trois lignes pourquoi, au lieu de laisser
une liste vide (#6). -
La tête de FIELD ne salue plus l'opérateur (la racine le fait, une fois) et
son pied ne compte plus rien : il ditLOCAL INSTALLATION · BUILD nou
SHARED SERVER · BUILD n. Les compteurs vivent dans ARCHIVE › OPERATOR (#6). -
Échap est écrit sur les écrans qui l'écoutent :
[ESC] OPERATION MODEsous
FIELD, BENCH et ARCHIVE,[ESC] BACKsur les écrans en dessous (#7). -
Le panneau
SETTINGSprend le noir du terminal, ses filets et ses trois
niveaux typographiques, et remplace son boutonClose (Tab)par la ligne de
touches[ESC] CLOSE · [TAB] CLOSE. Le rappel clavier figé qui vivait sous
Controlsa disparu : l'ongletKEYBOARDle remplace, et il dit la vérité. -
L'écran affiche la vraie version du paquet (
v0.0.0, oudevhors build
Vite) au lieu de la constante de lore0.97b(#9). -
Le chargement des cartes LIVE ne refait plus la marche rocktree à chaque
recalcul (#21).kh.google.cominterdit au cache HTTP de garder ses
réponses : tous les 50 m de vol, la fenêtre de streaming redemandait les
344 bulks d'une fenêtre de 300 m depuis la racine. La traversée est
désormais pipelinée (16 bulks en vol, plus de lots séquentiels de 8) et
garde ses bulks dans le worker pour toute la session ; la fenêtre ne
désire que les nœuds dont la boîte recoupe le disque de chargement (15,7 %
de nœuds en moins, tous dans le brouillard de bord) ;bootLive()lance
la première traversée avant d'attendre Rapier et crée ses workers
d'emblée. Mesuré, service réel, 60 ms de latence émulée par requête :
traversée de boot 4,3 s → 2,0 s, recalcul en vol 3,5 s → 80 ms. -
Build de production découpé et précompressé (#21). Rapier (2 Mo de
WASM en base64) est chargé parimport()danssrc/physics.js— chunk
séparé, préchauffé pendant le terminal, le menu ne l'attend plus ;three
a son propre chunk, en cache d'une version à l'autre.npm run build
enchaînetools/precompress.mjs(.br/.gzà côté des fichiers texte,
4,8 Mo → 1,0 Mo) etserver/static.mjsles sert avecContent-Encoding,
Vary, une ETag par représentation, jamais sur unRange, jamais si la
variante est plus vieille que sa source. Onze vérifications de plus dans
server-selftest.mjs. -
Niveau de détail par anneaux en LIVE (#22) : niveau 21 jusqu'à 150 m
du drone, 20 jusqu'à 300 m, 19 au-delà (tools/lib/rocktree/lod.mjs). Une
traversée par anneau (les suivantes servies par le cache de bulks), puis un
assemblage qui fait exclure aux nœuds grossiers les octants qu'un nœud plus
fin dessine — chaque point du disque couvert exactement une fois, vérifié
sur un octree synthétique jusqu'aux coutures. Mesuré, service réel : 1259 →
740 nœuds à 300 m, 4176 → 1003 à 600 m. -
Cache disque des réponses rocktree (#22,
src/rocktree-cache.js,
Cache API) : NodeData et BulkMetadata persistent entre sessions dans les
Workers — REDEPLOY et un second vol au même endroit ne repassent plus par
le réseau. Jamais PlanetoidMetadata (l'epoch), jamais une réponse non-ok,
5000 entrées au plus, fetch nu sans Cache API.
Corrigé
- Une installation locale ne se présente plus comme un serveur partagé. Le pied
de FIELD et l'avis de l'ongletLOCALse lisaient sur le droit d'acquérir,
fermé par défaut sur toute build distribuée : le client de bureau affichait
donc « SHARED SERVER » et se conseillait à lui-même d'installer le client de
bureau.GET /__map-api/scenesrend désormais lemodedu serveur
(local|shared), et c'est lui qui décide de ces deux formulations ;
DRAW BOX/DRAW SHAPEcontinuent de se lire sur le droit d'acquérir. - Le portrait de la machine manquait sur deux fins de vol sur trois — sortie de
zone et lien coupé — et sur tout vol NOMINAL (?family=,?scene=,?live=,
NOMINAL au banc), faute d'exemplaire tiré. Chaque fin porte désormais son
portrait, et une famille sans tirage en a un déduit de son nom (#13). - Face au soleil, l'exposition ferme moins fort : entre 55 et 75 % de son
niveau au repos au lieu de tomber à 35 %, l'image reste pilotable (#11).
Retiré
- Le lien
MODEdu pied de FIELD (Échap faisait déjà exactement la même chose),
les liensSETTINGSdu pied de FIELD, de la rangée ARCHIVE et du pied du
banc, l'entréeARCHIVEde la rangée LOCAL, la ligneDESKTOP CLIENT AVAILABLEet la mentionSTREAMED NOW · NOTHING KEPT · NEEDS THE LINKde
l'onglet LIVE, qui était fausse : un vol en direct est archivé comme les
autres (#6, #7). - L'atterrissage. Un vol se termine par un crash, une sortie de zone ou le
pilote qui coupe le lien (K maintenue) : plus de désarmement (touche J, geste
manette), plus de verdictLANDED, plus d'écranPOST-FLIGHT ANALYSISni de
reprise de session. Les vieux journaux qui portentLANDEDse relisent et
s'affichent tels quels (#10).
Quel fichier télécharger
| Fichier | Pour qui |
|---|---|
FPVTP-*-win-x64.exe |
Jouer sous Windows. Installeur : entrée Menu Démarrer, désinstalleur, mise à jour automatique. |
FPVTP-*-linux-x86_64.AppImage |
Jouer sous Linux. Rendre exécutable, double-cliquer. |
fpvtp-server-*-linux-x64.tar.gz |
Héberger une instance. Le serveur, le jeu construit, un runtime Node, et deploy/ (unité systemd, Caddyfile, script de livraison, checklist). Aucun npm install à faire. |
latest.yml / latest-linux.yml |
Les flux de mise à jour automatique. Ne pas télécharger à la main. |
Héberger : décompresser, puis suivre deploy/README.md. Le serveur
écoute sur 127.0.0.1 et refuse d'aller plus loin sans --mode shared,
qui réclame alors une clé d'opérateur à chaque requête.
Le jeu est sous AGPL-3.0 : si vous en hébergez une version
modifiée pour d'autres personnes, vous devez leur en publier les sources.
v0.1.0-beta
Ajouté
sim/server/— le jeu démarre sans Vite (#259, tranche T1 du design de
déploiement).node server/index.mjs [--data <dir>] [--port 8080] [--host 127.0.0.1] [--mode local|shared] [--dist <dir>] [--open], avec les
variables d'environnementFPVTP_DATA_DIR/FPVTP_PORT/FPVTP_HOST/
FPVTP_MODE.api.mjsporte/__operatoret/__map-api— les deux tables
de routes déplacées telles quelles, aucun chemin, aucune méthode, aucun code
de statut ni aucune forme de réponse ne changent ;static.mjssert le
dist/de Vite, avecRange(reprendre le téléchargement d'un chunk de
scène), ETag faible,Cache-Control: immutablesur/scenes/<slug>/*, et
aucun repli SPA : un fichier absent rend un 404 JSON, jamaisindex.html
(le pendant serveur de #275). Aucune dépendance npm : dunode:httpnu.sim/tools/lib/paths.mjs— un seul module résout le répertoire de données
(scenes/,scenes.json,operator-state/,cache/google-earth/). Sans
FPVTP_DATA_DIR, il rend exactement les chemins d'aujourd'hui :npm run dev
ne bouge pas d'un octet, etFPV_OPERATOR_DIRreste honoré.sim/tools/server-selftest.mjs(26 vérifications) et
sim/tools/vite-adapter-selftest.mjs, chaînés dansselftest:ci.LICENSE(GNU AGPL-3.0-only) et unREADME.mdà la racine : le dépôt se
prépare à devenir public.docs/manuel.mdreste le README technique..githooks/pre-commit— refuse un commit signé par une adresse hors liste
blanche.git config core.hooksPath .githooksl'active dans un clone.- Le jeu s'installe comme un jeu (#291, tranche T2) : un installeur
.exe
sous Windows — entrée Menu Démarrer, désinstalleur — et uneAppImagesous
Linux. L'app est un seul process Electron qui démarre le serveur du jeu sur
la boucle locale, sur un port éphémère, et ouvre une fenêtre dessus : ni
terminal, ni navigateur à part. Les données (scènes, sessions, état
opérateur) vivent hors du dossier du programme —app.getPath('userData'),
forcé sur%LOCALAPPDATA%plutôt que le%APPDATA%itinérant par défaut —
donc une mise à jour n'écrase rien.electron-updaterest câblé sur un flux
HTTP générique (le dépôt est privé : GitHub Releases demanderait un jeton à
chaque téléchargement) dont l'adresse reste un point d'ancrage explicite tant
que le serveur n'existe pas. Pas de macOS, pas de signature de code :
décisions actées. - Une clé d'opérateur pour les serveurs partagés (#60, tranche T3). Créer
un opérateur produit un secret de 128 bits — base32 sans caractères ambigus,
groupé par 4 — stocké haché en SHA-256 et rendu une seule fois. Un serveur en
--mode sharedle réclame enAuthorization: Bearersur/__operator/:id/*
et/__map-api/*(401 sans, 403 avec une mauvaise) et ne publie plus
d'annuaire (404 sur la liste). L'inscription reste en libre service —
c'est le cas nominal sur un serveur partagé — mais plafonnée par adresse, et
les captures d'un opérateur ont un plafond cumulé.GET /__operator/whoami
retrouve un profil par sa clé depuis un autre navigateur, et
node server/index.mjs key <id>en délivre une neuve : c'est la migration
des fichiers existants et la seule voie de récupération. Un serveurlocal
ne lit jamais l'en-tête : sa frontière reste le socket,npm run devne
change pas. - Côté joueur, la clé se tait : le navigateur la garde, l'inscription ne
fait rien noter à personne, et[ SHOW KEY ]dans ARCHIVE > OPERATOR la rend
le jour où l'on veut emporter son profil ailleurs — sur le modèle de
[ SHOW VECTOR ], sans jamais se confondre avec le Control Vector. Un
serveur qui ne reconnaît pas le navigateur ouvre un écran où
[ NEW OPERATOR ]est l'action principale et la saisie d'une clé la porte de
secours. deploy/(#292, tranche T4) : l'unité systemd du serveur en mode partagé
(écoute sur la boucle locale seulement, données hors du dossier du programme,
acquisition délibérément fermée,ProtectSystem=strict), la configuration
Caddy de ses deux entrées publiques — le jeu derrière TLS, et un sous-domaine
statique et sans authentification qui distribue les installeurs et leurs
fichiers de mise à jour — un script de livraison qui télécharge une release
privée, bascule un lien symbolique, redémarre et vérifie que le service
répond avant de rendre la main, en laissant la version précédente intacte
pour un retour arrière en deux commandes, et la checklist qu'un humain suit
une fois pour préparer une machine neuve. Rien n'est déployé : la première
livraison reste manuelle.
Modifié
- Dépendances remontées (PR #5, groupe
npm_and_yarn) : sharp 0.33 → 0.35,
Vite 5 → 6, electron-builder 25 → 26, et Electron 33 → 44 — pas 39 comme
proposé initialement : 39 est hors de la fenêtre de support d'Electron (les
trois derniers majeurs) et laissait ouverte l'alerte de traversée de chemin
d'extract-zip.npm auditne rapporte plus rien. Aucune des ruptures d'API
de sharp 0.35 (failOnError,paletteBitDepth,jp2k) n'était utilisée. sim/electron/main.jssuit la nouvelle signature du relais
console-message: Electron ≥ 36 passe un seul objet d'événement et un
leveltextuel, pas quatre arguments avec un niveau numérique. L'ancienne
forme ne journalisait plus rien.sim/tools/map-api-plugin.mjsn'est plus qu'un adaptateur Vite de vingt
lignes : il montecreateApi()sur les middlewares du serveur de dev, avec
son logger. Toute la logique a migré danssim/server/api.mjs.sim/tools/session-api-selftest.mjsteste désormais le serveur autonome
plutôt que Vite — il teste ce qui est livré, et il passe de 208 ms à 85 ms.- L'acquisition de terrain est fermée par défaut (#60) : elle n'est active
que siFPVTP_ACQUIREvaut1outrue, et jamais en--mode shared,
quoi qu'il arrive — deux gardes indépendantes. Fermée, elle retire
[ DRAW BOX ]et[ DRAW SHAPE ]de l'écran et laisse l'onglet LIVE, qui
porte déjà la boucle complète ; une ligne au pied signale alors le client de
bureau, sans rien promettre de plus que jouer chez soi. Conséquence pour le
développement :npm run devveut désormaisFPVTP_ACQUIRE=1dans
l'environnement pour retrouverACQUIRE AREA. - La CI vérifie le dépôt sous Windows autant que sous Linux (#291) : la
matrice{ubuntu, windows}deci.ymla déjà fait tomber une comparaison de
chemin (provider-selftest.mjs) et deux dépendances à la locale du système.
Un.gitattributesracine imposeeol=lf: une soixantaine de selftests
découpent sur\n, etcore.autocrlfest vrai par défaut sur les runners
Windows. sim/public/scenes.jsonest committé vide : c'est un fichier généré, propre
à chaque installation, et il portait trois entrées fantômes qui faisaient
échouernpm run selftest:sceneset affichaient trois scènes inexistantes sur
un clone neuf.node tools/sync-scenes.mjs --adoptle reconstruit depuis le
disque.tools/imagery-selftest.mjs(16 vérifications) est enfin chaîné dans
selftest:operator: il existait sans jamais tourner.- La release publie de quoi démarrer un serveur :
release.ymlattache
désormais unfpvtp-server-<tag>-linux-x64.tar.gz(app/avecserver/,
tools/,src/,dist/, plus le runtime Node de la version qui vient de
passer les selftests) à côté de l'archivedistseule. C'est ce que
deploy/deploy.shinstalle. Aucunnpm installsur le VPS : le serveur
démarre sansnode_modules, mesuré.
Modifié
- Le nom
fpvmapsdisparaît du dépôt, jusqu'au préfixe des clés
localStorage(fpvmaps.→fpvtp.), au nom du paquet npm (fpvtp-sim),
à celui du plugin Vite (fpvtp-map-api) et à la métadonnéegeneratordes
.glbexportés. Aucune migration : un joueur qui met à jour repart avec
des réglages neufs — calibrage manette, volumes, réglages d'objectif. Son
opérateur, lui, n'est pas perdu : il vit côté serveur, etOPERATOR SELECT
le repropose. - Le README de la racine est réécrit autour de ce qu'un nouveau venu vit
vraiment : une capture d'écran, ce qu'on peut faire tout de suite sur un
clone neuf (voler en LIVE, puisqu'il n'y a aucun terrain sur disque), les
contrôles, et les trois façons de faire tourner le jeu. - Le dépôt est désormais
lionrayonnant/FPVThePlanet: toutes les références
internes,deploy/deploy.shet l'unité systemd comprises, pointent dessus.
Modifié
- La release publie ce qu'il faut pour héberger sa propre instance.
L'archivefpvtp-server-<tag>-linux-x64.tar.gzemporte désormaisdeploy/
(unité systemd, Caddyfile, script de livraison, checklist) et laLICENSE—
que l'AGPL exige de faire accompagner le programme distribué — en plus du
serveur, du jeu construit et d'un runtime Node. Toujours aucunnpm install
à faire sur la machine d'accueil. La licence voyage aussi dans l'application
Electron (extraResources). - Le corps de la GitHub Release liste maintenant les fichiers et dit lequel
télécharger selon qu'on veut jouer ou héberger. - Le workflow refuse de publier une archive qui ne démarre pas : le runtime
embarqué doit résoudreserver/index.mjsavant que l'archive soit scellée. - L'archive
fpvtp-sim-<tag>.zip(ledist/seul) disparaît : elle ne pouvait
pas démarrer — c'est précisément ce que #259 reprochait aux « livraisons »
d'avant.
Modifié
- Un seul README, à la racine. Le dépôt en avait deux, et rien ne disait
lequel lire :sim/README.mddevientdocs/manuel.md— il reste entier,
mais ce n'est plus un README. La racine est la porte d'entrée, le manuel est
le manuel. Les références de la documentation vivante suivent ; les plans et
specs d'archive gardent les leurs, ils racontent ce qui a été édité ce
jour-là.
Corrigé
- Le scanner disait
NO LOCAL TERRAIN — DRAW AN AREA ON THE MAPalors que
[ DRAW BOX ]et[ DRAW SHAPE ]s...