Manuel de vectra-sdk
Version 0.12.0 · moteur VECTRA 7.9.15 (contrat 1, mode provisoire) · TRUvector
vectra-sdk sert à créer des scènes, des applications et des jeux avec le moteur VECTRA, dans le navigateur. Ce manuel explique tout ce que le kit sait faire aujourd'hui, comment s'en servir, et ce qui n'est pas encore fait. La liste exhaustive des nœuds, matières, comportements et noms anglais est dans la Référence, produite à partir du code.
1. Prendre en main
1.1 Ce qu'il faut
- Node.js 20 ou plus (pour les outils et les tests ; le kit lui-même tourne dans le navigateur).
- Le moteur VECTRA, à côté : le dépôt
truvector/vectra(7.9.15 ou plus récent). vectra-sdk ne contient aucune ligne du moteur ; il le lit dans le dossiermoteur/. - Un navigateur avec WebGPU (Chrome, Edge, Safari récent) ; à défaut, WebGL2 (voir 10.2).
1.2 Installer
git clone git@github.com:truvector/vectra-sdk.git
cd vectra-sdk
npm install
npm run lier-moteur -- ../vectra # moteur/ devient un lien vers ton dépôt du moteur
npm run dev # http://127.0.0.1:8080/
Ouvre ensuite http://127.0.0.1:8080/exemples/01-premier-monde.html, ou la Forge en ligne : http://127.0.0.1:8080/packages/forge-web/.
1.3 Un premier monde
import { Vectra, sdf, mat } from "./vectra/vectra.js";
const monde = await Vectra.creer("#ecran", { ciel: "heure-bleue" });
monde.ajouter(sdf.terrain({ relief: 4 }), mat.pierre());
const phare = sdf.boite([4, 18, 4]).arrondir(0.3)
.moins(sdf.cylindre(1.2, 20))
.fondre(sdf.sphere(3).en([0, 10, 0]), 0.8);
monde.ajouter(phare, mat.metal({ teinte: "#00D4FF" })).en([0, 9, -30]);
monde.repeter(sdf.sphere(0.5), { case: 6, hasard: 0.8, sur: "sol" }, mat.verre());
monde.joueur({ marche: true });
Ces quelques lignes donnent un terrain de pierre, un phare de métal creusé d'un puits, mille galets de verre posés sur le sol (calculés, pas stockés) et un joueur qui marche (ZQSD ou WASD, souris, manette, tactile). C'est l'exemple exemples/01-premier-monde.html.
1.4 Les trois portes d'entrée
| Porte | Pour qui | Où |
|---|---|---|
| Le code | qui écrit du JavaScript | vectra.js (français) ou vectra.en.js (anglais) |
| La Forge en ligne | qui préfère la souris | packages/forge-web/ |
| Les gabarits | qui veut partir d'un projet complet | npx vectra nouveau mon-jeu --gabarit plateforme |
Et pour essayer sans rien installer : le terrain de jeu (docs/terrain.html, en ligne sur /docs/terrain.html) — du code à gauche, le monde à droite, des exemples, et un lien « Partager » qui contient le code.
Ce qu'on fait par une porte s'ouvre par les deux autres : la Forge enregistre des fichiers .vectra que le code charge avec monde.charger(), et un projet en code s'exporte avec monde.exporter().
2. Comprendre
2.1 Une scène décrite, pas écrite
Dans le moteur, chaque monde est un shader WGSL écrit à la main. Avec le SDK, tu décris ton monde : des formes, des opérations entre elles, des matières, des répétitions. Le SDK en tire, à chaque changement de structure :
- le WGSL de la scène (le champ de distance, autour d'une « scène gabarit » qui respecte le contrat du moteur) ;
- le GLSL ES 3.0 pour les appareils sans WebGPU (traduction par naga, embarqué dans
vendor/naga-wasm/) ; - le même champ en JavaScript, pour le sol, les collisions et la visée.
Une seule description : le sol sur lequel on marche est exactement celui qu'on voit.
2.2 Structure et réglages
C'est la règle la plus utile à connaître :
- Un réglage (bouger, tourner, mettre à l'échelle, changer une taille, une teinte, une rugosité) passe par le bloc auteur, un tableau de paramètres envoyé au GPU à chaque image. Effet immédiat, rien à compiler.
- Un changement de structure (ajouter ou retirer une forme, changer d'opération, changer de matière, ajouter une rotation à un objet qui n'en avait pas) recompile la scène, en tâche de fond. L'image d'avant reste affichée jusqu'à ce que la nouvelle soit prête.
Conseil : si un objet va tourner plus tard, crée-le avec une rotation (.tourner(0) ou l'option { tourne: true } de ajouter). Les entités en ont toujours une.
2.3 Le bloc auteur et sa limite
Avec le moteur 7.9.15, le bloc auteur loge dans la fin du tampon de jeu du moteur, inutilisée : 132 vec4. Chaque matière en prend 2, chaque objet placé 1 (2 s'il tourne), chaque paramètre un quart ou un entier, et chaque groupe « lourd » 1 de plus pour sa sphère englobante. Les exemples en utilisent entre 9 et 112.
Quand le bloc est plein, le SDK ne casse rien : les derniers paramètres sont écrits en dur dans le shader, et les changer recompile. L'événement avertissement le signale. Le moteur 8.4 donnera une liaison à part de 256 vec4.
2.4 Le moteur, une dépendance
Le SDK ne parle au moteur que par un seul fichier, packages/sdk/src/moteur.js (l'adaptateur). Avec le moteur 7.9.15, qui n'a pas encore de porte publique, l'adaptateur fait lui-même ce que la V8 du moteur apportera : assembler les // #import (portage exact de la Forge, vérifié à l'octet sur 33 sorties), loger le bloc auteur, porter la scène gabarit. Ces contournements sont dans packages/sdk/src/provisoire/ et marqués PROVISOIRE : ils disparaîtront lot après lot. monde.infos.provisoire vaut true tant qu'ils servent.
3. L'API
L'API existe en français (vectra.js) et en anglais (vectra.en.js), à égalité : mêmes objets, mêmes méthodes. La correspondance complète est dans la Référence.
3.1 Vectra
| Membre | Rôle |
|---|---|
await Vectra.creer(cible, options) | Crée un monde dans un élément ("#ecran", un div ou un canvas). Renvoie un Monde. |
Vectra.configurer({ moteur: { racine }, langue }) | Où est le moteur (si ce n'est pas moteur/ à côté du SDK), langue des messages ("fr", "en"). |
Vectra.capacites() | { webgpu, webgl2, tactile, recommande }. |
await Vectra.moteur() | Version du moteur chargé, contrat, mode provisoire, capacité du bloc auteur. |
Vectra.scenes, Vectra.ciels, Vectra.noeuds | Les listes disponibles. |
Vectra.version | Version du SDK. |
Options de creer :
| Option | Valeurs | Défaut |
|---|---|---|
scene | une scène livrée : "plaine", "cathedrale", "organismes"… (voir 3.12) | aucune : scène décrite |
ciel | "jour", "heure-bleue", "aube", "studio", "nuit" | "jour" |
style | un style du moteur ("manga", "vitrail"…) | aucun |
qualite | 0 à 3, ou "auto" | "auto" |
mode | "auto", "complet", "allege", "fixe" (image fixe : le monde se rend jusqu'à être net puis s'arrête ; un geste, un changement ou capture() le relance) | "auto" |
graine | 8 signes (alphabet des graines VECTRA) | "A7K2M9QX" |
loin | distance de vue (m) | 400 |
rendu | "webgl2" pour forcer le repli | WebGPU d'abord |
cinema | post-traitement, styles, anti-crénelage | true |
langue | "fr", "en" | "fr" |
moteur | { racine: "https://…/moteur/" } | moteur/ à côté du SDK |
pixelsMax | plafond du rapport de pixels | 2 |
3.2 Construire : ajouter, repeter, entite
const tour = monde.ajouter(sdf.cylindre(1, 8), mat.pierre()).en([0, 4, 0]);
monde.repeter(sdf.cone(0.4, 1.2), { case: 4, densite: 0.6, sur: "sol", graine: "sapins" }, mat.bois());
const orbe = monde.entite({ forme: sdf.sphere(0.5), matiere: mat.lueur("#FF4FD8"), position: [2, 1, 0], avec: [comportements.flotter()] });
ajouter(forme, matiere?, { tourne? })→Objet. La matière est propre à l'objet : la régler ne touche pas les autres.repeter(forme, { case, densite, hasard, varier, graine, sur }, matiere?): une forme par case, sans rien stocker.sur: "sol"pose chaque copie sur le premier terrain ou plan ajouté (ou sur unObjetde sol donné).entite({ forme, matiere, position, rotation, echelle, rayon, surLeSol, donnees, avec })→Entite.entites(n, i => définition)en crée plusieurs.
3.3 Les formes : sdf et l'API chaînée
Formes : sdf.sphere, boite, cylindre, tore, capsule, cone, octaedre, plan, terrain, objet, wgsl, union. Pour une capture en gaussiennes 3D, voir monde.splats() (3.13).
Chaque forme se chaîne :
| Méthode | Effet |
|---|---|
.en([x, y, z]), .tourner([rx, ry, rz]) ou .tourner(degrés), .echelle(s) | placement |
.union(...), .moins(...), .inter(...), .fondre(autre, k), .morphose(autre, t) | opérations (morphose : 0 = cette forme, 1 = l'autre, réglable sans recompiler) |
.arrondir(r), .creuser(e), .tordre(f), .plier(f), .onduler(a, f), .miroir("x"), .bruit(amplitude, frequence, graine), .fractale({ iterations, echelle, decalage }) | modificateurs (bruit : surface rugueuse ; fractale : repliements successifs, façon Menger) |
.grille(pas, nombre), .parCase({ … }), .anneau(n, rayon) | répétitions |
.matiere(mat.x()), .nommer("Porte") | matière, nom |
Une opération prend la forme sur laquelle elle est appelée comme premier enfant : a.moins(b) creuse b dans a.
3.4 Les matières : mat
mat.pierre(), bois(), platre(), metal(), verre(), gelee(), lueur(), tissu(), terre(), eau(), mat(), objet(). Options : teinte ("#rrggbb", ou mat.lueur("#F5C542") directement), rugosite, metal, emission, texture. La pierre, le bois, le plâtre, le métal, le tissu et la terre prennent les textures photographiées du moteur (CC0), teintées par la couleur choisie. Le verre, la gelée et l'eau ont leur propre éclairage.
3.5 Objet et Entite
| Membre | Effet |
|---|---|
.en(p), .tourner(r), .echelle(s) | placement, sans recompiler |
.position, .rotation, .centre, .rayon, .visible, .echelleActuelle | lecture |
.regler({ rayon: 2 }) | paramètres de la forme racine |
.matiere.regler({ teinte: "#f00" }) | matière, sans recompiler |
.cacher(), .montrer(), .retirer() | visibilité ; retirer ôte la forme du graphe peu après |
entite.avec(comportement…), .sans(nom) | comportements |
entite.retirer({ effet: "eclat", son: "cloche" }) | retrait animé |
entite.donnees | tes propres données |
3.6 Le joueur et la caméra
const joueur = monde.joueur({ marche: true, saut: 7.5, vitesse: 4.5, position: [0, 2, 10] });
joueur.position = monde.surLeSol([5, 1.7, 5]);
Le corps a deux sphères (pieds et tête), la gravité, le saut, la course (Maj). Dans une scène décrite, il est repoussé hors du champ de distance ; dans une scène livrée, il suit le sol et les collisions de la scène, comme dans le lecteur. marche: false : vol libre (R et F pour monter, descendre).
Caméra (monde.camera) :
| Méthode | Mode |
|---|---|
libre() | vol libre, glisser pour regarder (mode par défaut sans joueur) |
orbite(cible, { distance, hauteur, auto, vitesse }) | tourner autour d'un objet ou d'un point |
suivre(entite, { distance, hauteur }) | à la troisième personne |
poser(position, regard) | pose fixe |
joueur() | première personne : les yeux du joueur (mode par défaut dès qu'il y a un joueur) |
await allerVers(cible, { duree, distance }) | vol animé (raccourci : await monde.allerVers(cible)) |
rail(points, { vitesse, duree, boucle, regard, avance }) | sur rail : parcourt les points à vitesse constante, en regardant devant (ou regard) |
sequence({ cles, legendes, duree, boucle }) | mise en scène, format des séquences du moteur : [instant, x, y, z, visé x, y, z] |
monde.joueur({ lacet }) oriente le joueur au départ (radians ; Math.PI / 2 regarde vers +x).
3.7 Les actions
Les entrées sont ramenées à des actions nommées : avancer, reculer, gauche, droite, sauter, courir, interagir, lanterne, monter, descendre, pause. Les touches sont données par position : la touche W d'un clavier QWERTY est la touche Z d'un AZERTY, sans rien régler.
monde.actions.sur("interagir", () => porte.retirer());
monde.actions.lier("style", ["KeyV"]); // une action à toi
monde.actions.etat("courir"); // maintenue ?
monde.actions.capturerSouris(); // pointeur verrouillé (jeux à la première personne)
Tactile : la moitié gauche de l'écran est un joystick, la droite le regard ; une tape est un clic. Manette : disposition standard.
3.8 Les règles et les événements
monde.quand(joueur).touche(cristaux, (cristal) => cristal.retirer({ effet: "eclat" }));
monde.quand(joueur).entre({ centre: [0, 1, -20], rayon: 3 }, () => monde.ui.message("Le seuil"));
monde.quand(porte).clic(() => porte.cacher());
monde.chaque(1, () => …); monde.apres(10, () => …);
monde.on("image", (dt) => …);
Contacts : touche, quitte ; zones : entre, sort ; clic ; regard : vise(objets, fn, { distance }) — le centre de la vue se pose sur l'un d'eux (une fois par regard) ; chaque(s, fn), apres(s, fn). Chaque règle renvoie de quoi la retirer ; monde.off(nom, fn) retire un écouteur posé par monde.on. Événements de on : pret, premiere-image, image, avant-image, clic (avec { point, distance, objet }), compile, qualite, lanterne, fin, erreur, avertissement, sequence-finie, porte, interrupteur, collecte, collecte-finie.
Une erreur dans ton code n'arrête jamais le monde : elle est attrapée, signalée par l'événement erreur (une ErreurVectra qui donne la ligne), et le reste continue. Une règle ou un comportement fautif trois fois est coupé (avec un avertissement).
3.9 Les comportements
comportements.tourner, flotter, patrouiller, orbiter, suivre, fuir, troupeau, pulser, minuterie, et pour les jeux :
| Comportement | Ce qu'il fait |
|---|---|
porte({ deplacement, vitesse, ouverte }) | l'entité glisse de sa place (fermée) de deplacement (ouverte) ; elle reçoit ouvrir(), fermer(), basculer(), ouverte |
interrupteur({ cible, mode, distance, action, sur, poids }) | mode: "basculer" : près de lui, l'action « interagir » (E, bouton X) le bascule ; mode: "plaque" : actif tant que le joueur (ou une entité de poids) se tient dessus ; il ouvre ou ferme cible et appelle sur(actif) |
collecte({ compteur, total, effet, son, valeur }) | ramassé au contact du joueur ; le compteur avance (affiché si total) ; événements collecte et collecte-finie |
compteARebours(secondes, fin, { libelle }) | une minuterie affichée ; fin() à zéro |
const porte = monde.entite({ forme: sdf.boite([3, 3, 0.4]), matiere: mat.bois(), position: [0, 1.5, -10], avec: [comportements.porte()] });
monde.entite({ forme: sdf.cylindre(0.4, 0.3), matiere: mat.metal(), position: [3, 0.15, -6], avec: [comportements.interrupteur({ cible: porte })] });
monde.entites(5, (i) => ({ forme: sdf.octaedre(0.5), matiere: mat.lueur("#F5C542"), position: [i * 2 - 4, 1, -3], avec: [comportements.collecte({ compteur: "Cristaux", total: 5 })] }));
monde.on("collecte-finie", () => monde.fin("Bravo !"));
Signatures complètes dans la Référence. Un comportement est un objet { nom, attacher?(entite, monde), maj(entite, dt, monde, t) } : tu peux écrire les tiens. Trois jeux complets n'utilisent que cette API : exemples/02-jeu-collecte.html, 09-course.html (anneaux dans l'ordre, compte à rebours), 10-enigme.html (trois leviers, une porte, une clé).
3.10 L'interface de jeu
monde.ui.compteur(nom, valeur, max?), monde.ui.minuterie(nom, secondes, fin), monde.ui.message(texte, secondes), monde.fin(titre, { texte, rejouer }), monde.ui.effacer(). Du HTML par-dessus l'image, aux couleurs TRUvector, lisible par les lecteurs d'écran.
3.11 Styles, lumière, son, ancres
await monde.style("manga", { transition: "onde", intensite, reglages });"aucun"retire le style ;await monde.styles()liste les 22 styles du moteur.monde.heure(0.75, meteo)oumonde.heure(18): le monde vivant du moteur (heure du jour en fraction ou en heures, météo) ;monde.heure(null): figé.monde.lanterne()(touche L),monde.son(true, { musique }): musique générée du moteur (après un geste de l'utilisateur).monde.ancrer(element, cible, { decalage }): un élément HTML suit un objet ou un point.await monde.capture(): une image PNG (même en pause).monde.pause(),monde.reprendre(),monde.detruire(): arrêter le rendu, le relancer, tout libérer.
3.12 Les scènes livrées
Vectra.creer("#ecran", { scene: "plaine" }) monte une scène du moteur : organismes, cathedrale, abysse, aurore, atelier, genese, maison, plaine, ville. On y marche (monde.joueur()), on y change de style, on y pose des règles de zones et une interface. On ne peut pas y ajouter de formes avec le moteur 7.9.15 (leur shader est fermé) : pour un monde à toi, pars d'une scène décrite (un sdf.terrain, par exemple).
3.13 Les objets importés
const avocat = await monde.objet("avocat.vobj"); // livré avec le moteur
monde.ajouter(avocat, mat.objet()).echelle(1.6).en([0, 0.8, 0]);
const mien = await monde.objet(fichierGlb); // un .glb à toi, converti dans le navigateur
monde.objet() accepte un nom de web/objets/ du moteur (avocat.vobj, bouteille.vobj), un .vobj, ou un .glb (glTF 2.0 binaire) qu'il convertit en champ de distance dans un Worker (la page ne gèle pas). mat.objet() reprend les couleurs du modèle (texture comprise). Avec le moteur 7.9.15, un seul objet importé par scène.
Splats (gaussiennes 3D, lot 0.7) : const n = await monde.splats("flacon-splats.vspl", { en: [0, 1, -3], echelle: 1.5, rotation: 30, opacite: 1 }) pose un nuage de splats — un .vspl livré par le moteur, ou un .ply / .spz / .vspl à toi (File, ArrayBuffer) — dessiné par le rendu de splats du moteur après la scène, caché par ce qui est devant lui. Le résultat se déplace (n.en(p), n.tourner(deg), n.echelle(s), n.opacite(v)) et se retire (await n.retirer()). Un nuage par monde ; visuel seulement (pour des collisions, pose une forme simple à sa place).
Un objet importé voyage avec le projet : monde.exporter() range ses octets .vobj (en base64) dans projet.objets, et monde.charger() les relit ; un objet livré par le moteur se recharge simplement par son nom.
3.14 Les projets .vectra
monde.exporter({ nom, script, sequence }) renvoie un projet (format: "vectra-projet", version: 1) : graphe, ciel, style, caméra, joueur, script, langage ("js" ou "ts") et objets (les objets importés). await monde.charger(projet) le recharge, et exécute son script. Qui modifie monde.graphe à la main (comme la Forge) prévient le monde par monde.majGraphe({ structure }). await monde.executer(code) exécute un script d'auteur : il reçoit monde, sdf, mat, comportements, Vectra (et world, behaviours).
Scripts en TypeScript. monde.executer(code, nom, { typescript: true }) — ou un script dont la première ligne est // @ts, ou un nom en .ts — retire d'abord les types, comme le fait Node 22 : le JavaScript restant s'exécute tel quel, aux mêmes lignes (les erreurs pointent la bonne ligne). Sont retirés : annotations de variables, de paramètres (x?: T compris) et de retours, as T, satisfies T, x!, interface, type X = …, declare, génériques des fonctions déclarées, import type, modificateurs de classe (private, readonly…). Comme Node, enum, namespace, paramètres promus et décorateurs sont refusés avec un message clair. Il n'y a pas de vérification des types : pour cela, ton éditeur et les déclarations de npm run types.
// @ts
interface Score { points: number }
const s: Score = { points: 0 };
monde.quand(joueur).touche(cristal, (c: Entite) => { s.points++; c.retirer(); });
3.15 Le multijoueur
const salon = await monde.reseau.salon({ api: "https://vectra.truvector.net", salon: "PRJ-K7M2QX9A", nom: "Ana" });
salon.sur("arrivee", (j) => monde.ui.message(`${j.nom} arrive`));
salon.partager("porte", "ouverte"); salon.score(42); salon.evenement("tir", { x: 1 });
Chaque joueur envoie sa position dix fois par seconde ; les autres apparaissent comme des silhouettes lumineuses, lissées. Le salon (un Durable Object par nom) relaie aussi un état partagé, des événements et un classement. joueurs: 8 fixe la taille du salon (seize au plus) ; le suivant est refusé.
Entités partagées (lot 0.10) : salon.partagerEntite(entite, { cle }) — sa position et sa rotation partent vingt fois par seconde de chez son propriétaire, et les autres la suivent, lissée. Le salon fait autorité : le premier qui l'annonce la possède, les mises à jour des autres sont refusées ; salon.prendre(entite) la reprend (on la pousse), salon.lacher(entite) la libère, salon.possede(entite) le dit ; un joueur qui part libère les siennes. Une entité retirée (ramassée) l'est pour tous. Voir la balle de exemples/07-multijoueur.html.
3.16 Interroger le monde
monde.distance(p), monde.solSous(x, z), monde.surLeSol([x, y, z]), monde.viser(u, v) (rayon depuis la caméra), monde.hasard(graine) (.suivant(), .entre(a, b), .disque(r), .choisir(liste)), monde.infos.
monde.infos dit aussi où la traduction WebGL2 s'est faite (glsl: "worker" : dans un Worker, la page ne gèle pas). await monde.sonder([[x, y, z], …]) (anglais : probe) demande à la carte graphique la distance et la normale en 8 points au plus : [{ distance, normale }], une à deux images plus tard. Elle voit exactement ce que le rayon voit, nœud WGSL libre compris. Elle passe par la sonde cs_probe du moteur : WebGPU seulement (en WebGL2, ou dans une scène livrée, elle renvoie null).
4. Le graphe de scène
Le format graphe.v1 est ce que la Forge enregistre et ce que l'API chaînée écrit :
{
"format": "vectra-graphe", "version": 1,
"noeuds": {
"n1": { "type": "terrain", "p": { "relief": 4 }, "matiere": "m1" },
"n2": { "type": "sphere", "p": { "rayon": 3 }, "en": [0, 10, 0] },
"n3": { "type": "fondre", "p": { "k": 0.8 }, "enfants": ["n4", "n2"] }
},
"racine": ["n1", "n3"],
"matieres": { "m1": { "base": "pierre" } }
}
Règles : chaque nœud a au plus un parent ; les racines forment une union ; une matière s'hérite du parent ; un seul objet importé par graphe (moteur 7.9.15). npx vectra verifier fichier.vectra valide un fichier ; les erreurs nomment le nœud, en français et en anglais.
Le compilateur (packages/graphe/src/compiler.js) : valide, sépare la structure des paramètres (l'empreinte de la structure décide s'il faut recompiler), calcule les boîtes englobantes et les facteurs de sûreté des déformations, range les paramètres dans le bloc auteur (placements d'abord, puis sphères englobantes, puis paramètres de forme), puis émet le WGSL et l'évaluation JavaScript. Les enfants « lourds » d'une union sont élagués par leur sphère englobante : le rayon ne les calcule que s'il passe près. L'évaluation JavaScript élague exactement de la même façon : la sonde GPU et le JavaScript s'accordent à mieux que 1 mm (contrôlé sur 1 000 points près des surfaces, toutes sortes de nœuds).
Le nœud WGSL libre (sdf.wgsl(code, borne)) prend du code d'expert (il reçoit p et renvoie une distance). Une erreur dans ce code est ramenée au nœud et à la ligne de l'auteur (erreur wgsl-libre : « WGSL libre « Mon champ », ligne 2 : unresolved call target 'lenght' »), et l'image d'avant reste affichée. Il n'a pas d'équivalent JavaScript : pour les collisions du joueur, le SDK interroge alors la sonde GPU du moteur à chaque image (pieds, tête, sol juste dessous, un pas en avant) et corrige le champ JavaScript avec ce qu'elle voit. Le joueur attend que la sonde ait vu la scène compilée avant de tomber. WebGPU seulement : en WebGL2 le joueur traverse encore ces formes. Voir exemples/08-wgsl-libre.html.
5. La Forge en ligne
packages/forge-web/index.html. Elle est écrite avec le SDK et n'utilise que son API publique.
- Scène (à gauche) : l'arbre des nœuds. « Ajouter… » : une forme s'ajoute devant la caméra, posée sur le sol ; une opération, un modificateur ou une répétition enveloppe la sélection. La croix supprime. La jauge de coût estime ce que le rayon doit calculer (vert, orange, rouge, avec un conseil au survol).
- Vue (au centre) : glisser pour regarder, ZQSD/WASD pour bouger, R/F pour monter/descendre. Un clic sur un objet le choisit ; Maj+clic pose la sélection là où l'on clique. Le cadre pointillé montre la sélection.
- Poignées 3D : sur la sélection, trois flèches (X rose, Y or, Z cyan) et un disque. Glisser une flèche déplace l'objet le long de son axe ; glisser le disque le déplace sur le plan horizontal. Maj pendant le geste : pas de 50 cm. Rien n'est recompilé pendant le geste (bloc auteur), et le geste entier s'annule d'un seul Ctrl+Z.
- Inspecteur (à droite) : nom, placement, paramètres de la forme, matière (sorte, teinte, rugosité, métal, émission). Les réglages sont immédiats ; ce qui change la structure recompile.
- Code (en bas) : le script du projet dans CodeMirror 6 (coloration, complétion tirée de l'API :
monde.,sdf.,mat.,comportements.…), exécuté par Jouer ; la case TypeScript retire les types avant l'exécution. + Bibliothèque… insère des morceaux prêts : comportements (porte et interrupteur, plaque de pression, objets à ramasser, troupeau…), règles (touche, entre, vise), interface, caméra, ambiance. - Piste : la piste de temps de la caméra. « + Clé » garde la vue actuelle à un instant ; on glisse les clés sur la frise, on leur donne une légende, « ▶ Lire » joue la mise en scène. « Au démarrage » : le projet exporté ou publié commence par elle, puis rend la main au joueur.
- Coût par nœud : une pastille verte, or ou rouge sur chaque nœud de l'arbre, et des conseils sous la jauge (« 6 sphères identiques : répète-les par case », WGSL libre sans borne, fondus à trop d'enfants, arbre trop profond…). Jouer met un joueur dans le monde ; Arrêter remet la scène telle qu'elle était. Journal : compilations, erreurs avec leur ligne.
- Fichier : Nouveau, Ouvrir, Enregistrer (
.vectra). Sauvegarde automatique dans IndexedDB toutes les 10 secondes (et en quittant la page), objets importés compris ; repli sur localStorage. Annuler / Refaire : 100 niveaux (Ctrl+Z, Ctrl+Maj+Z). - + Objet .glb (importer un objet) : un
.glb(ou.vobj), converti dans le navigateur (un Worker, la page ne gèle pas ; progression affichée), posé devant la caméra avecmat.objet(). Un seul objet importé par scène (moteur 7.9.15) : un deuxième remplace le premier. L'objet est enregistré dans le.vectra. - Exporter .zip : un dossier de projet complet, prêt à devenir un dépôt GitHub privé —
index.html,jeu.js(qui ouvreprojet.vectra),projet.vectra,vectra.json,README.md,.gitignore, le SDK dansvectra/, et.github/workflows/deployer.yml(Cloudflare Pages). Le moteur n'y est pas : le déploiement le récupère à la version testée. C'est exactement ce que donnevectra nouveau mon-jeu --depuis monde.vectra. Le README du dossier donne les trois commandes (git init,gh repo create --private, secrets). - GitHub ▸ : crée un dépôt sur ton compte GitHub (privé par défaut) et y pousse le projet complet en un commit — le même dossier que l'export .zip, déploiement Cloudflare compris. Connexion par « Se connecter avec GitHub » (le Worker, droits
repoetworkflow) ou par un jeton personnel collé dans la boîte ; le jeton ne quitte le navigateur que versapi.github.com, et n'est gardé que pour l'onglet. - Publier : crée un compte anonyme (jeton gardé sur l'appareil), envoie le projet au service, et donne un lien public et une balise
<vectra-monde>.
6. La balise <vectra-monde>
<script type="module" src="https://vectra.truvector.net/sdk/0/element.js"></script>
<vectra-monde scene="plaine" data-style="manga" joueur></vectra-monde>
<vectra-monde projet="https://p.truvector.net/p/PRJ-K7M2QX9A.vectra" joueur></vectra-monde>
Attributs : scene, projet, ciel, data-style (style est déjà un attribut HTML), graine, qualite, joueur, orbite, rendu, langue, moteur. Événements DOM : vectra-pret (avec le monde), vectra-erreur.
7. L'outil en ligne de commande
| Commande | Effet |
|---|---|
vectra nouveau <dossier> --gabarit <nom> | un projet depuis un gabarit, avec sa copie du SDK et son vectra.json |
vectra nouveau <dossier> --depuis monde.vectra | un projet qui joue un fichier de la Forge (gabarit projet) |
vectra dev [dossier] --port 8080 | sert le projet et le moteur en local |
vectra verifier <fichier> | valide un .vectra ou un graphe (--en : messages anglais) |
vectra construire [dossier] --sortie dist | un site statique autonome (SDK + moteur, ≈ 14 Mo), vérifié pour Cloudflare Pages (aucun fichier > 25 Mo) |
vectra publier <fichier.vectra> --api <url> --jeton <jeton> | envoie et publie ; affiche le lien et la balise |
vectra moteur | quel moteur est lié, et où |
Noms anglais : new, check, build, publish, engine, help.
Les gabarits
| Gabarit | Ce qu'il montre |
|---|---|
plateforme | sauter de pilier en pilier jusqu'au phare ; chutes comptées, retour au départ |
visite | une place et des pavillons ; un clic vole jusqu'à un pavillon et ouvre sa fiche |
vitrine | un objet en orbite, une teinte réglée depuis la page |
exposition | une galerie à parcourir ; les cartels s'affichent à l'approche des œuvres |
bac-a-sable | voler et poser des formes d'un clic |
clip | une mise en scène : clés de caméra, légendes, styles qui changent, musique |
projet | joue un fichier projet.vectra (celui de la Forge), avec sa mise en scène de départ s'il en a une ; c'est le gabarit de l'export .zip et de l'export GitHub |
Chaque gabarit porte .github/workflows/deployer.yml : à chaque poussée sur main, il récupère le moteur (dépôt privé, jeton MOTEUR_LECTURE) à la version de vectra.json, et déploie sur Cloudflare Pages.
8. Le nuage : Cloudflare
Le Worker vectra-projets (api/) est séparé de vectra-api du moteur, qui ne change pas. Tout tient dans l'offre gratuite.
| Route | Rôle |
|---|---|
GET /api/sante | état |
POST /api/comptes | compte anonyme → { id, jeton } |
GET /api/auth/github → /api/auth/github/retour | connexion GitHub (facultative ; droits read:user repo workflow, pour « Exporter vers GitHub ») ; retour vers /forge (ADRESSE_FORGE) |
POST/GET /api/projets, GET/PUT/DELETE /api/projets/:id | projets privés, versionnés (R2 + index D1) |
POST /api/projets/:id/publier | copie figée, code PRJ-XXXXXXXX |
GET /p/:code.vectra, GET /p/:code | le projet publié et sa page publique |
GET /api/galerie, POST /api/signaler | galerie ; trois signalements masquent une publication |
GET /api/salons/:nom (WebSocket) | salon multijoueur (Durable Object SalonProjet) |
Garde-fous : projets de 8 Mo au plus (objets importés compris ; TAILLE_MAX), noms et contenu des objets embarqués vérifiés, 60 envois par heure et par compte, état des salons assaini (nombres, textes courts), ménage quotidien. Les projets publiés vivent sur une adresse à part (p.truvector.net) : le code d'un auteur ne tourne jamais là où les gens se connectent à la Forge. Le site et l'API partagent vectra.truvector.net (le Worker y prend /api/*).
Mettre en route :
cd api
npx wrangler d1 create vectra-projets # recopier l'identifiant dans wrangler.toml
npx wrangler d1 execute vectra-projets --file=schema.sql
npx wrangler r2 bucket create vectra-projets
npx wrangler deploy
En local : npx wrangler d1 execute vectra-projets --local --file=schema.sql puis npx wrangler dev --local.
Le CDN (vectra.truvector.net) reçoit npm run construire : dist/sdk/<version>/ (figé, avec le moteur exact testé) et dist/sdk/<majeure>/ (la dernière). Une page publiée ne change jamais d'elle-même.
8.1 Mettre en production : le dossier web/
npm run web produit web/, un dossier autonome à pousser tel quel dans un dépôt GitHub privé (par exemple truvector/vectra-web). Rien n'y est compilé : tout est déjà construit et contrôlé ici.
Dans web/ | Rôle | En ligne |
|---|---|---|
site/ | Cloudflare Pages : accueil, /forge, /docs/ (ce manuel), /exemples/, /sdk/<version>/ (figé), /sdk/<majeure>/ (la dernière), le moteur testé, version.json | https://vectra.truvector.net/ |
api/ | le Worker vectra-projets, routes de production actives | vectra.truvector.net/api/* et p.truvector.net |
.github/workflows/deployer.yml | à chaque poussée sur main : déploie site/ puis, si la variable D1_ID est remplie, crée R2, pose les tables (sans rien effacer) et déploie le Worker | — |
README.md | le pas-à-pas : dépôt, jeton Cloudflare, secrets, domaine, API, mise à jour | — |
Un seul domaine pour le site et l'API (vectra.…), donc la Forge publie sur /api sans réglage ; les projets publiés restent sur leur adresse séparée (p.…). Ce dépôt n'a pas besoin du jeton du moteur (MOTEUR_LECTURE) : le moteur testé est déjà dans site/. C'est aussi pourquoi il doit rester privé.
Autres adresses : npm run web -- --domaine mondomaine.fr --sous-domaine vectra --publication p --projet-pages vectra-web. Mettre à jour : npm run web, puis recopier web/ dans le dépôt de production (en gardant son .git/) et pousser. npm run test:navigateur contrôle aussi web/site (accueil et ses liens, manuel, exemple, Forge, /sdk/<majeure>/element.js dans une page tierce).
9. GitHub et la mise à jour du moteur
Les deux dépôts sont privés, et rien ne passe par npm (décision TRUvector).
| Fichier | Quand | Quoi |
|---|---|---|
.github/workflows/ci.yml | chaque poussée | tests unitaires (dont la parité avec la Forge Python et la validité WGSL par naga), puis contrôles navigateur (Chromium sans carte graphique) contre le Worker lancé en local |
.github/workflows/moteur-maj.yml | le moteur publie | met à jour vectra.moteurVersion, ouvre une demande de fusion ; mineure ou correctif : fusion automatique si la CI est verte, majeure : relecture |
.github/workflows/publier.yml | étiquette vX.Y.Z | construit dist/, l'attache à la Release, le dépose sur Cloudflare Pages |
.github/workflows/deployer.yml | poussée dans api/ | déploie le Worker |
Secrets : MOTEUR_LECTURE (lecture seule de truvector/vectra), CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID. Le dépôt du moteur doit porter une étiquette par version (v7.9.15) et, quand il publiera (lot 8.8), envoyer un repository_dispatch « moteur-publie » à vectra-sdk.
Ce qui se passe quand le moteur change : un correctif ou un ajout (style, scène, lumière) arrive sans rien toucher ; un nouvel export s'utilise quand on veut ; un changement de contrat (majeure) est refusé par la plage ^8 jusqu'à adaptation. Au démarrage, l'adaptateur vérifie le numéro de contrat du moteur et refuse, avec un message clair, un moteur incompatible.
10. Dans le détail
10.1 Performances
Dans un moteur à champs de distance, chaque forme coûte à chaque pas de chaque rayon. Ce qui aide : répéter (repeter, grille, anneau : une copie coûte comme une forme) plutôt que dupliquer ; regrouper des formes proches sous une union (elle est élaguée par sa sphère englobante) ; éviter les grandes fondre à beaucoup d'enfants. La jauge de la Forge guide ; la qualité automatique et la résolution dynamique du moteur font le reste.
10.2 Sans WebGPU
Le SDK assemble la scène en variante WebGL2 du moteur et la traduit en GLSL ES 3.0 avec naga-wasm 30.2.0 (copie embarquée dans vendor/naga-wasm/ ; à défaut, le CDN jsDelivr, version épinglée). La sortie est identique, à l'octet, à celle de naga-cli avec les mêmes options (--keep-coordinate-space --profile es300) ; la Forge du moteur ajoute --compact, que naga-wasm ne sait pas faire : son GLSL est 5 à 10 % plus court, le nôtre garde quelques fonctions inutilisées, sans effet sur l'image. La traduction se fait dans un Worker (la page ne gèle pas pendant une recompilation), avec repli sur la page si le Worker ne démarre pas. Le moteur 8.3 apportera son propre naga en WebAssembly ; l'adaptateur s'en servira à la place.
10.3 Les erreurs
Toutes les erreurs du SDK sont des ErreurVectra : code, message (dans la langue choisie), fr, en, details. Codes : contrat, bibliotheque, shader, wgsl-libre (avec details.noeud, nom, ligne), glsl, webgl2-graphe, rendu, scene, cible, style, capacite, script, detruit, rv.
10.4 Les tests
npm test # contrôles unitaires (graphe, WGSL, assembleur, lexique, contrat, API, actifs, TypeScript, export, GitHub)
npm run construire # dist/, nécessaire au contrôle du CDN
npm run test:navigateur # exemples, gabarits, Forge, CDN, web/, API du monde, documentation, nuage, salon à 8 (≈ 45 min en logiciel)
Les contrôles de la chaîne (tests/unites/contrat.test.js) refusent tout import du moteur hors de l'adaptateur, toute méthode publique sans alias anglais ou sans place dans ce manuel, et un cœur du SDK de plus de 150 Ko compressés. tests/navigateur/docs.mjs exécute chaque exemple du terrain de jeu et chaque bloc de code JavaScript / TypeScript de ce manuel.
Les contrôles navigateur utilisent Chromium sans carte graphique (SwiftShader) : lent mais fidèle. CHROMIUM=<chemin> choisit l'exécutable ; CAPTURES=<dossier> garde des images. Le contrôle du nuage demande le Worker en local (VECTRA_API, par défaut http://127.0.0.1:8787) et s'ignore sinon.
11. La feuille de route, lot par lot
Dit franchement. « Fait » veut dire écrit et contrôlé dans la chaîne ; « moteur 8 » : attend un lot du moteur (le contournement provisoire est en place quand il existe) ; « à mesurer » : demande du vrai matériel ou de vraies personnes.
| Lot | Fait | Reste |
|---|---|---|
| 0.1 dépôt et chaîne | dépôt séparé, adaptateur unique (contrôlé), 4 workflows, contrôles de taille | npm au lieu de pnpm, JSDoc au lieu de TypeScript strict, node:test au lieu de Vitest (choix assumés) ; workflows jamais lancés sur GitHub |
| 0.2 paquet et balise | Vectra.creer, 9 scènes livrées, styles, modes (dont image fixe), <vectra-monde>, FR + EN contrôlés, CDN, cœur ≈ 75 Ko compressés | Arches et photo en relief (données du moteur) ; régions du site (moteur.site(), 8.1) — moteur 8 |
| 0.3 graphe → WGSL | 27 types de nœuds (dont morphose, bruit, fractale), élagage, empreinte, débordement, erreur WGSL libre à sa ligne | « briques en flux » et « en cubes » (FluxMonde, champ_cubes : moteur 8) ; Maison du jour en graphe à 30 dB, 300 ms sur portable — à mesurer |
| 0.4 le même graphe partout | GLSL par naga dans un Worker, JS identique au GPU à < 1 mm sur 1 000 points, sonde GPU (WGSL libre) | variante casque, style par objet — moteur 8.6 ; sonde en WebGL2 — moteur |
| 0.5 entités, actions, caméras | entités, actions, tactile, manette, caméras libre, première personne, orbite, suivre, rail, séquence, vol ; vise, touche, entre, clic, minuteries | 112 entités à 60 i/s (bloc de 132 vec4 en 7.9.15 : ≈ 60 entités animées avant écriture en dur) ; jeu des Organismes refait (scène livrée fermée en 7.9.15) — moteur 8.4 / 8.6 |
| 0.6 scripts, comportements, interface | TypeScript (types retirés), 13 comportements dont porte, interrupteur, collecte, compte à rebours ; trois jeux (collecte, course, énigme) ; règle fautive coupée après 3 erreurs | vérification des types |
| 0.7 actifs | glTF → .vobj dans un Worker, objets embarqués dans le projet, splats (.vspl, .ply, .spz) | ciels .venv, photo → objet (file de vectra-api), bibliothèque CC0 — moteur 8.7 ; « à l'octet près » mesuré sur des modèles générés, pas sur l'avocat du Khronos |
| 0.8 la Forge | arbre, inspecteur, poignées de déplacement, bibliothèque, piste de temps, CodeMirror et complétion, coût par nœud et conseils, IndexedDB, import d'objets, export .zip | poignées de rotation et d'échelle ; .vectra en archive (c'est un JSON qui embarque tout) ; coûts mesurés au banc ; test avec cinq personnes — à mesurer |
| 0.9 publier et partager | Worker, codes PRJ-, adresse séparée, galerie, signalements, CLI, Exporter vers GitHub (dépôt privé, déploiement compris) | connexion OAuth et export essayés contre une API GitHub simulée seulement |
| 0.10 ensemble | salons à 8 (contrôlés), entités partagées à 20 Hz avec un propriétaire, classement | — |
| 1.0 ouvert aux créateurs | manuel, référence générée, terrain de jeu, 7 gabarits, vectra nouveau, dossier de production web/, tableau de compatibilité, la doc qui tourne dans la chaîne | site de documentation déployé (le dossier web/ le contient : reste à le pousser) ; « Use this template » (réglage GitHub) |
Et toujours : réalité virtuelle depuis le SDK non (monde.rv.entrer() lève une erreur claire ; noyau séparé du moteur, 8.6) ; formes dans une scène livrée non ; un seul objet importé et un seul nuage de splats par scène (liaisons du moteur 7.9.15) ; textures glTF sous Node : couleur de base seule.
12. Compatibilité
| vectra-sdk | Moteur testé | Moteurs acceptés | Contrat | Remarques |
|---|---|---|---|---|
| 0.12.0 | 7.9.15 | ^7.9.15 || ^8.0.0 | 1 | mode provisoire (sans porte publique) ; bascule seul sur la porte du moteur 8.x |
| 0.11.0 | 7.9.15 | ^7.9.15 || ^8.0.0 | 1 | |
| 0.10.0 | 7.9.15 | ^7.9.15 || ^8.0.0 | 1 | première version |
La même table est publiée avec le site (/version.json, champ compatibilite). Promesse visée pour la 1.0 : rien ne casse dans la 1.x, et toute 1.x marche avec tout moteur 8.x.
13. Glossaire
- Champ de distance : fonction qui donne, pour tout point, la distance à la surface la plus proche. VECTRA dessine en marchant le long des rayons avec elle.
- Graphe : la description d'une scène (nœuds, matières, racines).
- Bloc auteur : le tableau de paramètres de la scène, envoyé au GPU à chaque image.
- Empreinte : résumé de la structure du graphe ; si elle ne change pas, le shader non plus.
- Contrat : ce que le moteur promet au SDK (porte publique, liaisons, formats). Numéro actuel : 1.
- Adaptateur :
packages/sdk/src/moteur.js, le seul fichier qui parle au moteur. - Scène livrée : une scène du moteur (la Plaine, la Ville…), écrite à la main.
- Scène décrite : une scène faite avec le SDK.
Référence
Produite par node outils/doc-reference.mjs à partir du code : elle suit l'API exactement.
Les nœuds du graphe
Chaque nœud a un type, des paramètres (p), des enfants (enfants), et peut avoir un placement (en, rot en degrés, echelle), une matiere et un nom. Un paramètre marqué structure recompile le shader quand il change ; les autres se règlent sans recompiler.
Formes
| Type | Nom (fr / en) | Enfants | Paramètres |
|---|---|---|---|
sphere | Sphère / Sphere | 0 | rayon rayon (f ; défaut 1 ; 0.001 à 1000) |
boite | Boîte / Box | 0 | taille taille (v3 ; défaut [1, 1, 1])arrondi arrondi (f ; défaut 0 ; 0 à 100) |
cylindre | Cylindre / Cylinder | 0 | rayon rayon (f ; défaut 0.5 ; 0.001 à 1000)hauteur hauteur (f ; défaut 1 ; 0.001 à 1000) |
tore | Tore / Torus | 0 | rayon rayon (f ; défaut 1 ; 0.001 à 1000)epaisseur épaisseur (f ; défaut 0.25 ; 0.001 à 1000) |
capsule | Capsule / Capsule | 0 | rayon rayon (f ; défaut 0.3 ; 0.001 à 1000)hauteur hauteur (f ; défaut 1 ; 0 à 1000) |
cone | Cône / Cone | 0 | rayon rayon (f ; défaut 0.5 ; 0.001 à 1000)hauteur hauteur (f ; défaut 1 ; 0.001 à 1000) |
octaedre | Octaèdre / Octahedron | 0 | rayon rayon (f ; défaut 0.6 ; 0.001 à 1000) |
plan | Plan / Plane | 0 | hauteur hauteur (f ; défaut 0 ; -10000 à 10000) |
terrain | Terrain / Terrain | 0 | taille taille (f ; défaut 400 ; 1 à 100000)relief relief (f ; défaut 6 ; 0 à 2000)echelle échelle des collines (f ; défaut 40 ; 0.1 à 10000)graine graine (graine ; défaut « A7K2M9QX ») |
objet | Objet importé / Imported object | 0 | fichier fichier .vobj (texte, structure ; défaut « avocat.vobj ») |
wgsl | WGSL libre / Raw WGSL | 0 | code code (renvoie la distance) (texte, structure ; défaut « return length(p) - 1.0; »)borne demi-taille englobante (0 : sans borne) (v3 ; défaut [0, 0, 0]) |
Opérations
| Type | Nom (fr / en) | Enfants | Paramètres |
|---|---|---|---|
union | Union / Union | 1 à 64 | — |
moins | Moins / Subtract | 2 à 64 | — |
inter | Intersection / Intersect | 2 à 64 | — |
fondre | Fondre / Blend | 2 à 64 | k douceur (f ; défaut 0.5 ; 0.001 à 100) |
morphose | Morphose / Morph | 2 | t passage (0 : première, 1 : seconde) (f ; défaut 0.5 ; 0 à 1) |
Modificateurs
| Type | Nom (fr / en) | Enfants | Paramètres |
|---|---|---|---|
bruit | Bruit / Noise | 1 | amplitude amplitude (f ; défaut 0.15 ; 0 à 100)frequence fréquence (f ; défaut 1.5 ; 0.001 à 100)graine graine (graine ; défaut « VECTRA ») |
fractale | Fractale / Fractal | 1 | iterations itérations (f, structure ; défaut 3 ; 1 à 8)echelle échelle (f ; défaut 2 ; 1.05 à 4)decalage décalage (v3 ; défaut [1, 1, 1]) |
arrondir | Arrondir / Round | 1 | rayon rayon (f ; défaut 0.1 ; 0 à 100) |
creuser | Creuser / Shell | 1 | epaisseur épaisseur (f ; défaut 0.05 ; 0.001 à 100) |
tordre | Tordre / Twist | 1 | force force (radians par mètre) (f ; défaut 0.5 ; -20 à 20) |
plier | Plier / Bend | 1 | force force (f ; défaut 0.2 ; -10 à 10) |
onduler | Onduler / Wave | 1 | amplitude amplitude (f ; défaut 0.2 ; 0 à 100)frequence fréquence (f ; défaut 1 ; 0.001 à 100) |
miroir | Miroir / Mirror | 1 | axe axe (choix, structure ; défaut « x ») |
Répétitions
| Type | Nom (fr / en) | Enfants | Paramètres |
|---|---|---|---|
grille | Grille / Grid | 1 | pas pas (0 : pas de répétition sur l'axe) (v3 ; défaut [4, 0, 4])nombre nombre de chaque côté (0 : sans fin) (v3 ; défaut [0, 0, 0]) |
par-case | Par case / Per cell | 1 | case côté de la case (f ; défaut 6 ; 0.1 à 10000)densite densité (f ; défaut 1 ; 0 à 1)hasard hasard de position (f ; défaut 0.8 ; 0 à 1)varier rotation au hasard (f ; défaut 1 ; 0 à 1)graine graine (graine ; défaut « VECTRA »)sur posé sur (nœud de sol) (ref, structure ; défaut —) |
anneau | Anneau / Ring | 1 | nombre nombre (f ; défaut 8 ; 1 à 512)rayon rayon (f ; défaut 3 ; 0 à 10000) |
Constructeurs de l'API chaînée : sdf.sphere(rayon), sdf.boite(taille, arrondi), sdf.cylindre(rayon, hauteur), sdf.tore(rayon, epaisseur), sdf.capsule(rayon, hauteur), sdf.cone(rayon, hauteur), sdf.octaedre(rayon), sdf.plan(hauteur), sdf.terrain({ taille, relief, echelle, graine }), sdf.wgsl(code, borne), sdf.objet(fichier), sdf.union(...formes).
En anglais : sdf.sphere, sdf.box, sdf.cylinder, sdf.torus, sdf.capsule, sdf.cone, sdf.octahedron, sdf.plane, sdf.terrain, sdf.wgsl, sdf.object.
Les matières
mat.<sorte>(options) : teinte (couleur CSS « #rrggbb » ; en anglais tint), rugosite (roughness), metal, emission, texture (vrai/faux : texture photographiée du moteur).
| Sorte | Nom (fr / en) | Teinte | Rugosité | Métal | Émission | Texture photo |
|---|---|---|---|---|---|---|
mat (0) | Mat / Matte | #b9bcc8 | 0.7 | 0 | 0 | non |
pierre (1) | Pierre / Stone | #8a8378 | 0.85 | 0 | 0 | oui |
bois (2) | Bois / Wood | #8b5a2b | 0.6 | 0 | 0 | oui |
platre (3) | Plâtre / Plaster | #e8e2d6 | 0.9 | 0 | 0 | oui |
metal (4) | Métal / Metal | #c9ccd2 | 0.3 | 1 | 0 | oui |
verre (5) | Verre / Glass | #dfeff5 | 0.05 | 0 | 0 | non |
gelee (6) | Gelée / Jelly | #7fd1a8 | 0.4 | 0 | 0 | non |
lueur (7) | Lueur / Glow | #F5C542 | 0.5 | 0 | 3 | non |
tissu (8) | Tissu / Fabric | #6b4a7a | 0.95 | 0 | 0 | oui |
terre (9) | Terre / Soil | #6b4f36 | 0.95 | 0 | 0 | oui |
eau (10) | Eau / Water | #2a6f86 | 0.05 | 0 | 0 | non |
objet (11) | Couleurs de l'objet / Object colours | #ffffff | 0.6 | 0 | 0 | non |
Les comportements
| Comportement | Anglais | Signature | |
|---|---|---|---|
comportements.tourner | behaviours.spin | (vitesse rad/s = 1, axe = "y") | |
comportements.flotter | behaviours.float | (amplitude = 0.3, frequence = 1) | |
comportements.patrouiller | behaviours.patrol | (points, vitesse = 2) | |
comportements.orbiter | behaviours.orbit | (centre, rayon = 3, vitesse = 0.5) | |
comportements.suivre | behaviours.follow | (cible = "joueur", vitesse = 2, distance = 2) | |
comportements.fuir | behaviours.flee | (cible = "joueur", vitesse = 3, distance = 5) | |
comportements.troupeau | behaviours.herd | ({ centre, rayon = 15, vitesse = 1, peur = 6 }) | |
comportements.pulser | behaviours.pulse | (amplitude = 0.1, frequence = 1) | |
comportements.porte | behaviours.door | ({ deplacement = [0, 3, 0], vitesse = 2, ouverte = false }) → entite.ouvrir() / fermer() / basculer() | |
comportements.interrupteur | behaviours.switch | `({ cible, mode = "basculer" | "plaque", distance = 1.8, action = "interagir", sur, poids })` |
comportements.collecte | behaviours.collectible | ({ compteur = "Score", total, effet = "eclat", son, valeur = 1 }) → événements « collecte », « collecte-finie » | |
comportements.compteARebours | behaviours.countdown | (secondes, fin, { libelle = "Temps" }) | |
comportements.minuterie | behaviours.timer | (secondes, fin) |
Les ciels
| Ciel | Bas | Haut | Soleil | Brume | Force du soleil |
|---|---|---|---|---|---|
jour | 0.78, 0.74, 0.7 | 0.25, 0.47, 0.82 | 0.6, 0.45, -0.5 | 0.0025 | 1 |
heure-bleue | 0.55, 0.45, 0.6 | 0.12, 0.2, 0.42 | 0.5, 0.12, -0.6 | 0.004 | 1 |
aube | 0.95, 0.66, 0.5 | 0.35, 0.45, 0.72 | -0.6, 0.18, -0.5 | 0.003 | 1 |
studio | 0.42, 0.42, 0.46 | 0.2, 0.2, 0.24 | 0.5, 0.6, 0.6 | 0.0005 | 0.45 |
nuit | 0.05, 0.06, 0.12 | 0.01, 0.015, 0.04 | 0.3, 0.5, -0.4 | 0.002 | 1 |
Alias anglais : day, blue-hour, dawn, night.
Les scènes livrées montables par le SDK (moteur 7.9.15)
organismes, cathedrale, abysse, aurore, atelier, genese, maison, plaine, ville. Les Arches (briques en flux) et la photo en relief demandent des données que le SDK ne fournit pas encore.
Les actions et leurs touches par défaut
Touches données par position (KeyboardEvent.code) : KeyW est Z sur un clavier AZERTY.
| Action | Touches | Manette |
|---|---|---|
avancer | KeyW, ArrowUp | stick gauche |
reculer | KeyS, ArrowDown | stick gauche |
gauche | KeyA, ArrowLeft | stick gauche |
droite | KeyD, ArrowRight | stick gauche |
sauter | Space | A (0) |
courir | ShiftLeft, ShiftRight | stick gauche (10) |
interagir | KeyE, Enter | X (2) |
lanterne | KeyL | Y (3) |
monter | KeyR, PageUp | R1 (5) |
descendre | KeyF, PageDown | L1 (4) |
pause | Escape, KeyP | Start (9) |
Lexique : méthodes françaises → anglaises
Monde
| Français | Anglais |
|---|---|
ajouter | add |
repeter | repeat |
entite | entity |
entites | entities |
joueur | player |
quand | when |
chaque | every |
apres | after |
on | on |
off | off |
style | setStyle |
heure | timeOfDay |
lanterne | lantern |
son | sound |
ancrer | anchor |
capture | capture |
pause | pause |
reprendre | resume |
objet | object |
fin | end |
detruire | destroy |
exporter | export |
distance | distance |
sonder | probe |
solSous | groundUnder |
surLeSol | onGround |
hasard | random |
viser | pick |
infos | info |
ui | ui |
camera | camera |
actions | actions |
reseau | network |
rv | vr |
graphe | graph |
objets | objects |
charger | load |
majGraphe | graphChanged |
executer | run |
styles | listStyles |
allerVers | flyTo |
splats | splats |
Camera
| Français | Anglais |
|---|---|
libre | free |
orbite | orbit |
suivre | follow |
poser | set |
allerVers | flyTo |
position | position |
sequence | sequence |
rail | rail |
joueur | firstPerson |
Objet
| Français | Anglais |
|---|---|
en | at |
tourner | rotate |
echelle | scale |
regler | set |
matiere | material |
cacher | hide |
montrer | show |
retirer | remove |
position | position |
rotation | rotationAngles |
visible | visible |
rayon | radius |
centre | center |
donnees | data |
noeud | node |
echelleActuelle | currentScale |
Entite
| Français | Anglais |
|---|---|
avec | with |
sans | without |
comportements | behaviours |
InterfaceJeu
| Français | Anglais |
|---|---|
compteur | counter |
minuterie | timer |
message | message |
fin | end |
effacer | clear |
detruire | destroy |
Forme
| Français | Anglais |
|---|---|
en | at |
tourner | rotate |
echelle | scale |
matiere | material |
nommer | name |
union | union |
moins | subtract |
inter | intersect |
fondre | blend |
arrondir | round |
creuser | shell |
tordre | twist |
plier | bend |
onduler | wave |
miroir | mirror |
grille | grid |
parCase | perCell |
anneau | ring |
morphose | morph |
bruit | noise |
fractale | fractal |
Lexique : options anglaises → françaises
| Anglais | Français |
|---|---|
walk | marche |
jump | saut |
speed | vitesse |
run | course |
gravity | gravite |
radius | rayon |
height | taille |
position | position |
rotation | rotation |
scale | echelle |
shape | forme |
material | matiere |
with | avec |
data | donnees |
onGround | surLeSol |
sky | ciel |
quality | qualite |
seed | graine |
far | loin |
renderer | rendu |
scene | scene |
style | style |
mode | mode |
cinema | cinema |
language | langue |
engine | moteur |
maxPixelRatio | pixelsMax |
transition | transition |
intensity | intensite |
settings | reglages |
distance | distance |
auto | auto |
angle | angle |
duration | duree |
offset | decalage |
text | texte |
replay | rejouer |
label | libelle |
music | musique |
cell | case |
density | densite |
jitter | hasard |
vary | varier |
on | sur |
center | centre |
fear | peur |
elevation | hauteur |
rotates | tourne |
players | joueurs |
ranking | classement |
room | salon |
loop | boucle |
yaw | lacet |
look | regard |
lead | avance |
displacement | deplacement |
opacity | opacite |
open | ouverte |
target | cible |
counter | compteur |
total | total |
effect | effet |
sound | son |
value | valeur |
weights | poids |
action | action |