Utiliser FERS depuis JavaScript
Le solveur FERS est publié sous forme de compilation WebAssembly du même moteur Rust qui anime l’application web. Il s’exécute dans le navigateur ou sous Node, calcule sans aller-retour serveur et ne demande pas de clé d’API dans l’offre gratuite.
Installation
Deux paquets sont publiés depuis le même moteur avec une API identique : seuls l’installation et la configuration du bundler diffèrent. Prenez -web pour tout ce qui passe par un bundler, et le paquet sans suffixe pour Node côté serveur.
# Browser apps (Vite, Next.js, webpack):
npm install @ferscloud/fers-calculation-web
# Node.js / server-side:
npm install @ferscloud/fers-calculationLes deux paquets portent la version du moteur et avancent ensemble. Épinglez-les à la même version exacte plutôt qu’à une plage avec accent circonflexe.
Configurer le bundler
@ferscloud/fers-calculation-web est un module ES WASM qui s’initialise via un await de niveau supérieur. La plupart des bundlers demandent un réglage unique ; le paquet Node n’en demande aucun.
Vite
Ajoutez le plugin puis définissez une cible de build qui prend en charge l’await de niveau supérieur.
npm i -D vite-plugin-wasmConfiguration Vite
// vite.config.ts
import wasm from "vite-plugin-wasm";
// The package initialises with a top-level await, so the build target
// has to be one that supports it. esnext needs no second plugin.
export default {
plugins: [wasm()],
build: { target: "esnext" },
};Next.js et webpack
Transpilez le paquet et activez le WebAssembly asynchrone. asyncFunction est nécessaire parce que le module s’initialise avec un await de niveau supérieur.
// next.config.js
module.exports = {
transpilePackages: ["@ferscloud/fers-calculation-web"],
webpack(config) {
config.experiments = { ...config.experiments, asyncWebAssembly: true };
config.output.environment = {
...config.output.environment,
asyncFunction: true,
};
return config;
},
};Le solveur est synchrone et gourmand en CPU. Pour les grands modèles, exécutez-le dans un Web Worker afin que le fil d’interface reste réactif.
Calculer un modèle
Pas d’appel à init() et pas de clé d’API. L’offre gratuite couvre tout modèle jusqu’à 100 barres.
import { calculate_from_json } from "@ferscloud/fers-calculation";
// No init() call needed — the nodejs and bundler builds initialise the
// WASM module automatically on import.
const res = JSON.parse(calculate_from_json(JSON.stringify(myModel)));
if (res.ok) {
const data = res.result; // displacements, member_results, unity_checks, …
} else {
console.error(res.error.code, res.error.message);
}L’enveloppe de réponse
Chaque appel au solveur renvoie une enveloppe JSON : vous analysez une fois et vous branchez sur ok, sans jamais avoir à deviner si la chaîne renvoyée ressemble à une erreur. La valeur renvoyée est toujours du JSON valide.
// success
{ "ok": true, "result": { /* the full result document */ } }
// failure (invalid model, over the member limit, malformed JSON, …)
{ "ok": false, "error": { "code": "LimitExceeded",
"message": "Number of members (250) exceeds allowed maximum of 100" } }| error.code | Signification |
|---|---|
InvalidJson | La chaîne du modèle n’était pas du JSON analysable. |
LimitExceeded | Plus de barres que l’offre active n’autorise (100 en gratuit, 10,000 en Pro). |
SolveError | Le modèle a été lu mais n’a pas pu être résolu — le plus souvent une matrice de rigidité singulière due à un appui manquant ou insuffisant. |
InternalPanic | Un défaut du moteur. Merci de le signaler. |
InternalSerialization | Les résultats n’ont pas pu être sérialisés. Également un défaut à signaler. |
Types TypeScript
Le paquet navigateur fournit des types de modèle générés à côté des signatures de fonctions. Ils sont produits à partir du schéma OpenAPI du moteur : ils suivent donc la version publiée au lieu d’être maintenus à la main.
import type {
FERS,
ResultsBundle,
} from "@ferscloud/fers-calculation-web/fers-models";
// FERS — the input model
// ResultsBundle — the `result` payload of a successful envelope
// Both are generated from the engine's OpenAPI schema, so they track
// the published version.Créditer FERS sur l’offre gratuite
Les résultats de l’offre gratuite portent un objet attribution produit à l’intérieur du solveur. Les résultats Pro, calculés avec un jeton valide, ne le portent pas : le même code affiche donc un crédit en gratuit et reste en marque blanche en Pro, sans aucun réglage à poser.
getFersAttribution, fersAttributionText et createFersBadge sont exportés à ses côtés. Tous acceptent l’enveloppe, le modèle analysé ou le jeu de résultats, et tous ne renvoient rien pour un résultat Pro ou une enveloppe d’erreur.
import { fersAttributionHtml } from "@ferscloud/fers-calculation-web/badge.js";
// Free-tier results carry result.attribution; this renders the credit.
// With a Pro solve token the field is absent and this returns "" — the
// same code white-labels, with no flag to set.
const credit = fersAttributionHtml(res);Si vous diffusez l’offre gratuite dans une application, merci d’afficher le crédit. C’est la seule chose que l’offre gratuite vous demande. Disponible à partir du moteur 0.2.61.
Limites Pro avec un jeton de calcul
Les limites Pro se débloquent en passant un jeton signé de courte durée émis par le serveur FERS Cloud. Le jeton est vérifié à l’intérieur du module WebAssembly contre une clé publique Ed25519 intégrée au binaire : il ne peut donc pas être falsifié.
Votre serveur détient la clé d’API et l’échange contre un jeton de 30 minutes ; le navigateur ne voit jamais que le jeton. Gardez FERS_API_KEY côté serveur, jamais dans du code navigateur.
// pages/api/solve-token.ts
const FERS_API_KEY = process.env.FERS_API_KEY!;
let cached: { token: string; expiresAt: number } | null = null;
export default async function handler(req, res) {
const now = Date.now();
// Re-use if more than 5 minutes remain
if (cached && cached.expiresAt - now > 5 * 60 * 1000) {
return res.json({ token: cached.token });
}
const resp = await fetch("https://ferscloud.com/api/solver/token", {
method: "POST",
headers: { "X-API-Key": FERS_API_KEY },
});
if (!resp.ok) return res.status(502).json({ error: "Token fetch failed" });
const { token, expiresAt } = await resp.json();
cached = { token, expiresAt: new Date(expiresAt).getTime() };
return res.json({ token });
}Appeler le solveur avec un jeton
Si le jeton est absent, expiré ou invalide, le solveur revient à la limite gratuite de barres : il ne lève jamais d’exception. Un vrai échec de calcul arrive toujours sous la forme { ok: false, error } et non d’une exception.
import { calculate_from_json_with_token } from "@ferscloud/fers-calculation";
const { token } = await fetch("/api/solve-token").then((r) => r.json());
const res = JSON.parse(
calculate_from_json_with_token(JSON.stringify(myModel), token),
);
if (!res.ok) throw new Error(`${res.error.code}: ${res.error.message}`);
const data = res.result;| Gratuit | Pro | |
|---|---|---|
| Nombre maximal de barres | 100 | 10,000 |
| Fonction | calculate_from_json | calculate_from_json_with_token |
| Jeton requis | Non | Oui |
| Durée du jeton | — | 30 minutes |
Déformée
Activez include_member_deflected_shape dans les options d’analyse du modèle pour obtenir par barre une déformée prête à tracer et exacte vis-à-vis de la charge — le déplacement global de la barre échantillonné sur sa longueur — au lieu de reconstruire la courbe vous-même.
Elle est désactivée par défaut pour alléger la réponse, et absente de member_results si elle n’est pas demandée.
const model = {
/* … model + load cases … */
analysis: {
/* … */
options: {
/* … */
include_member_deflected_shape: true,
},
},
};
const res = JSON.parse(calculate_from_json(JSON.stringify(model)));
const mr = res.result.results.loadcases["…"].member_results["1"];
// mr.member_displacements: [{ x_frac, displacement: [dx, dy, dz] }, …]
// x_frac 0–1 along the member; displacement in the global input frame.Autres voies
- Pourquoi calculer des structures en JavaScript : les arguments pour un solveur côté client.
- API REST : appeler le solveur en HTTP depuis n’importe quel langage.
- Serveur MCP : laisser Claude, ChatGPT, Cursor ou VS Code piloter FERS directement.
- Paquet Python : le même moteur depuis un script.
Pages associées
Référence de l’API REST
Chaque point de terminaison du SDK avec requête et réponse : authentification, clés, calcul, validation, vérification de poutre et gestion des modèles.
Démarrage : votre premier modèle dans le navigateur
Construire et calculer un portique 3D dans le navigateur : matériaux, sections, nœuds, appuis, barres, charges, Calculer.
Voir aussi
Questions fréquentes
Ai-je besoin d’une clé d’API pour calculer dans le navigateur ?
calculate_from_json fonctionne sans clé et sans compte pour des modèles jusqu’à 100 barres. Une clé n’est nécessaire que pour émettre le jeton de calcul Pro.Le modèle quitte-t-il le navigateur ?
Pourquoi Vite a-t-il besoin d’une configuration supplémentaire ?
await de niveau supérieur. vite-plugin-wasm prend en charge l’import WebAssembly, et build.target: "esnext" conserve cet await dans la sortie — cela demande Chrome, Edge ou Firefox 89+, ou Safari 15+. webpack a besoin de asyncWebAssembly et asyncFunction dans ses réglages experiments et output. Si vite-plugin-top-level-await figure encore dans votre configuration à cause d’une version antérieure de cette page, vous pouvez le retirer : avec les versions récentes de @swc/core, il fait échouer vite build.Dois-je exécuter le solveur dans un Web Worker ?
Faut-il un appel à init() ?
await init() ; ce n’est plus nécessaire.Que se passe-t-il si le jeton de calcul a expiré ?
LimitExceeded.Quel paquet utiliser côté serveur ?
@ferscloud/fers-calculation, compilé pour Node. Il ne demande aucune configuration de bundler et s’initialise seul à l’import.