Usar FERS desde JavaScript
El solver de FERS se publica como compilación WebAssembly del mismo motor en Rust que impulsa la aplicación web. Se ejecuta en el navegador o en Node, calcula sin ida y vuelta al servidor y no necesita clave de API en el plan gratuito.
Instalación
Del mismo motor se publican dos paquetes con una API idéntica: solo cambian la instalación y la configuración del empaquetador. Elija -web para todo lo que pase por un empaquetador y el paquete sin sufijo para Node en el servidor.
# Browser apps (Vite, Next.js, webpack):
npm install @ferscloud/fers-calculation-web
# Node.js / server-side:
npm install @ferscloud/fers-calculationAmbos paquetes llevan la versión del motor y avanzan juntos. Fíjelos a la misma versión exacta en lugar de a un rango con acento circunflejo.
Configurar el empaquetador
@ferscloud/fers-calculation-web es un módulo ES de WASM que se inicializa mediante un await de nivel superior. La mayoría de los empaquetadores necesitan un ajuste único de configuración; el paquete de Node no necesita ninguno.
Vite
Añada el plugin y defina después un target de compilación que admita await de nivel superior.
npm i -D vite-plugin-wasmConfiguración de 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 y webpack
Transpile el paquete y active WebAssembly asíncrono. asyncFunction es necesario porque el módulo se inicializa con un await de nivel superior.
// 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;
},
};El solver es síncrono y consume CPU. Para modelos grandes, ejecútelo dentro de un Web Worker para que el hilo de interfaz siga respondiendo.
Calcular un modelo
Sin llamada a init() y sin clave de API. El plan gratuito cubre cualquier modelo de hasta 100 barras.
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);
}El envoltorio de respuesta
Cada llamada al solver devuelve un envoltorio JSON, de modo que analiza una vez y bifurca según ok: nunca tiene que olfatear si la cadena devuelta parece un error. El valor devuelto siempre es JSON válido.
// 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 | Significado |
|---|---|
InvalidJson | La cadena del modelo no era JSON analizable. |
LimitExceeded | Más barras de las que permite el plan activo (100 gratis, 10,000 Pro). |
SolveError | El modelo se leyó pero no pudo resolverse; casi siempre una matriz de rigidez singular por un apoyo ausente o insuficiente. |
InternalPanic | Un fallo del motor. Le agradecemos el aviso. |
InternalSerialization | Los resultados no pudieron serializarse. También es un fallo que conviene reportar. |
Tipos de TypeScript
El paquete de navegador incluye tipos de modelo generados junto a las firmas de las funciones. Se generan a partir del esquema OpenAPI del motor, de modo que siguen a la versión publicada en lugar de mantenerse a mano.
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.Acreditar a FERS en el plan gratuito
Los resultados del plan gratuito llevan un objeto attribution generado dentro del solver. Los resultados Pro, calculados con un token válido, no lo llevan: el mismo código muestra el crédito en el plan gratuito y queda en blanco con Pro, sin ninguna opción que activar.
Junto a él se exportan getFersAttribution, fersAttributionText y createFersBadge. Todos aceptan el envoltorio, el modelo analizado o el conjunto de resultados, y todos devuelven vacío para un resultado Pro o un envoltorio de error.
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 usa el plan gratuito en una aplicación, muestre el crédito. Es lo único que el plan gratuito le pide. Disponible desde el motor 0.2.61.
Límites Pro con un token de cálculo
Los límites Pro se desbloquean pasando un token firmado de corta duración emitido por el servidor de FERS Cloud. El token se verifica dentro del módulo WebAssembly contra una clave pública Ed25519 incrustada en el binario, así que no puede falsificarse.
Su servidor guarda la clave de API y la intercambia por un token de 30 minutos; el navegador solo ve el token. Mantenga FERS_API_KEY en el servidor, nunca en código de navegador.
// 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 });
}Llamar al solver con un token
Si el token falta, ha caducado o no es válido, el solver vuelve al límite gratuito de barras: nunca lanza una excepción. Un fallo real de cálculo sigue llegando como { ok: false, error } y no como excepción.
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;| Gratis | Pro | |
|---|---|---|
| Barras máximas | 100 | 10,000 |
| Función | calculate_from_json | calculate_from_json_with_token |
| Requiere token | No | Sí |
| Validez del token | — | 30 minutos |
Deformada
Active include_member_deflected_shape en las opciones de análisis del modelo para obtener por barra una deformada lista para dibujar y exacta respecto a la carga — el desplazamiento global de la barra muestreado a lo largo de su longitud — en lugar de reconstruir la curva usted mismo.
Está desactivada por defecto para que la respuesta sea ligera, y se omite de member_results cuando no se solicita.
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.Otras vías
- Por qué calcular estructuras en JavaScript: los argumentos para llevar el solver al cliente.
- API REST: llamar al solver por HTTP desde cualquier lenguaje.
- Servidor MCP: dejar que Claude, ChatGPT, Cursor o VS Code gobiernen FERS directamente.
- Paquete de Python: el mismo motor desde un script.
Páginas relacionadas
Referencia de la API REST
Todos los puntos finales del SDK con petición y respuesta: autenticación, claves, cálculo, validación, comprobación de vigas y gestión de modelos.
Inicio rápido: su primer modelo en el navegador
Construya y calcule un pórtico 3D en el navegador: materiales, secciones, nudos, apoyos, barras, cargas y Calcular.
Véase también
Preguntas frecuentes
¿Necesito clave de API para calcular en el navegador?
calculate_from_json funciona sin clave y sin cuenta para modelos de hasta 100 barras. La clave solo hace falta para emitir el token de cálculo Pro.¿El modelo sale del navegador?
¿Por qué Vite necesita configuración adicional?
await de nivel superior. vite-plugin-wasm se encarga de la importación de WebAssembly, y build.target: "esnext" mantiene ese await en la salida — requiere Chrome, Edge o Firefox 89+, o Safari 15+. webpack necesita asyncWebAssembly y asyncFunction en sus ajustes de experiments y output. Si vite-plugin-top-level-await sigue en tu configuración por una versión anterior de esta página, puedes quitarlo: con versiones recientes de @swc/core hace fallar vite build.¿Debo ejecutar el solver en un Web Worker?
¿Necesito una llamada a init()?
await init(); ya no es necesario.¿Qué ocurre si el token de cálculo ha caducado?
LimitExceeded.¿Qué paquete uso en el servidor?
@ferscloud/fers-calculation, compilado para Node. No necesita configuración de empaquetador y se inicializa solo al importarlo.