Skip to main content

Language Integration

Fabula's core is a Rust library. If your project uses a different language, this page explains your options.

Quick Summary

ApproachLanguagesMaturityUse When
WASMJavaScript, TypeScript, any WASM hostShipping (powers this site's playgrounds)Browser apps, Node.js services, Deno
C FFIC, C++, Go (via cgo), Python (via ctypes)PlannedNative integration, game engines
PyO3PythonPlannedData science, Jupyter notebooks, scripting
Embedded DSLAny language with a text parserAvailable nowDefine patterns as .fabula text files, evaluate via WASM or FFI
Service wrapperAny language via HTTP/gRPCRoll your ownMicroservice architecture, language-agnostic

WASM (JavaScript / TypeScript)

The fabula-wasm crate compiles to WebAssembly via wasm-bindgen. This is how the interactive playgrounds on this documentation site work.

Building

# Install the wasm32 target if you haven't
rustup target add wasm32-unknown-unknown

# Build the WASM package
wasm-pack build --target web crates/fabula-wasm

This produces a pkg/ directory with .wasm, .js, and .d.ts files ready for import.

API Surface

The core WASM evaluation functions accept DSL text and return JSON:

  • evaluate_batch(pattern_dsl, graph_dsl) -- batch evaluation, returns matches
  • evaluate_incremental(pattern_dsl, graph_dsl) -- step-by-step replay
  • why_not(pattern_dsl, graph_dsl) -- gap analysis

Additional utility functions (parse_and_validate_pattern, parse_and_validate_graph, allen_relation) are also available for validation and temporal reasoning.

import init, { evaluate_batch } from './pkg/fabula_wasm.js';

await init();

const result = evaluate_batch(
`pattern lateral_movement {
stage e1 { e1.type = "login" e1.host -> ?host_a e1.cred -> ?cred }
stage e2 { e2.type = "login" e2.host -> ?host_b e2.cred -> ?cred }
temporal e1 before e2
}`,
`graph {
@1 ev1.type = "login" @1 ev1.host = "web01" @1 ev1.cred = "admin"
@5 ev2.type = "login" @5 ev2.host = "db01" @5 ev2.cred = "admin"
}`
);

console.log(JSON.parse(result));
// { ok: true, matches: [{ pattern: "lateral_movement", bindings: { "?cred": "Str(\"admin\")", ... } }] }
// Note: binding values use Rust Debug format (e.g., Str("admin"), Node("web01"))

Node.js / Deno

Use --target nodejs for Node.js:

wasm-pack build --target nodejs crates/fabula-wasm

Limitations

  • WASM bindings use the in-memory graph adapter (MemGraph). For custom data sources, you need Rust.
  • Pattern registration is per-call (no persistent engine state across WASM calls).
  • Performance is ~2-5x slower than native Rust due to WASM overhead.

Embedded DSL (Any Language)

If your language can call WASM or a C library, you can define patterns as .fabula text files and evaluate them without writing Rust:

  1. Write patterns in .fabula files using the DSL syntax
  2. Define your graph data as edge tuples
  3. Call evaluate_batch() or evaluate_incremental() via WASM or FFI

This is the recommended approach for non-Rust teams. The DSL is the same syntax used in the interactive playgrounds.

Python (Planned)

Python bindings via PyO3 are planned but not yet available. In the meantime:

C / C++ / Go (Planned)

C FFI bindings via cbindgen are planned. This would enable:

  • Unity/Unreal integration via C plugins
  • Go integration via cgo
  • Any language with C interop

Game Engine Integration

Current state

No official game engine plugins exist yet. The recommended path for game developers:

  1. Godot (GDScript/C#): Compile to WASM, call via GDExtension (Godot 4)
  2. Unity (C#): Compile to WASM, call via JavaScript interop in WebGL builds; or await C FFI for native builds
  3. Unreal (C++): Await C FFI, or embed Rust via cxx crate
  4. Bevy / custom Rust engine: Use fabula directly as a Rust dependency (zero friction)

Pattern-as-config workflow

For game teams that don't write Rust, the recommended workflow is:

  1. Author patterns in .fabula text files (the DSL)
  2. Load and evaluate at runtime via WASM or FFI
  3. React to match results in your game logic layer

This separates pattern authoring (designers, in DSL) from pattern evaluation (engine, in Rust/WASM).

Choosing an Approach

"I want the fastest path to trying fabula" -- Use the interactive playgrounds. No installation needed.

"I'm building a web app" -- WASM. Build fabula-wasm, import in your frontend or Node.js backend.

"I'm a Python data scientist" -- WASM via wasmtime-py, or wrap in an HTTP service.

"I'm building a game in Unity/Godot" -- WASM for prototyping; await C FFI for production.

"I'm a Rust developer" -- Use fabula directly. See Getting Started.