Configure JSX
Pibbl publishes automatic-runtime entries at @pibbl/core/jsx-runtime and
@pibbl/core/jsx-dev-runtime. Compilers generate those imports; application code
normally imports Canvas/runtime values from @pibbl/core.
Start with a Canvas scene
Section titled “Start with a Canvas scene”Install @pibbl/core, configure the automatic runtime, then describe a scene in
an ordinary .tsx component and mount it with pibbl(canvas, root). Pibbl JSX
creates branded Canvas elements; React and the DOM are not involved. The
interactive workbench linked after this guide contains a complete first scene with
stateful click feedback and disposal.
Pibbl does not install a global JSX namespace and has no React dependency. Its
module-scoped JSX types accept synchronous Pibbl component functions, require
uppercase imported values, validate component props and children, and reject
lowercase intrinsic tags.
TypeScript
Section titled “TypeScript”For a Pibbl-only package, configure the runtime once:
{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@pibbl/core", "moduleResolution": "Bundler", "strict": true }}react-jsxdev is also supported for an explicit development build. It uses
@pibbl/core/jsx-dev-runtime, whose jsxDEV records filename, line, and column
for runtime diagnostics.
To opt in one file instead, put the pragma before imports:
/** @jsxImportSource @pibbl/core */import { Rectangle } from "@pibbl/core";
export const swatch = <Rectangle style={{ width: 20, height: 20 }} />;The pragma chooses the runtime; it does not import React or a Fragment name.
The fragment shorthand <>...</> is compiled against Pibbl automatically.
Vite and esbuild
Section titled “Vite and esbuild”Vite honors the TypeScript configuration above for .tsx and .jsx input.
If configuring esbuild directly, use the automatic transform and Pibbl import
source:
import { build } from "esbuild";
await build({ entryPoints: ["src/main.tsx"], bundle: true, format: "esm", jsx: "automatic", jsxImportSource: "@pibbl/core", outfile: "dist/main.js",});Equivalent CLI flags are --jsx=automatic --jsx-import-source=@pibbl/core.
Do not configure the classic transform; Pibbl documents the automatic runtime.
Babel automatic runtime
Section titled “Babel automatic runtime”Use Babel’s JSX transform with runtime: "automatic" and
importSource: "@pibbl/core":
{ "plugins": [ [ "@babel/plugin-transform-react-jsx", { "runtime": "automatic", "importSource": "@pibbl/core" } ] ]}For development-source metadata, select the corresponding Babel development
transform in development builds with the same runtime and importSource.
Despite the plugin’s historical name, the emitted constructor imports come
from Pibbl, and react is not required.
JavaScript
Section titled “JavaScript”JavaScript authors use .jsx, the same automatic-runtime configuration, and
normal ESM imports:
/** @jsxImportSource @pibbl/core */import { Rectangle, Text, pibbl } from "@pibbl/core";
function Scene() { return ( <> <Rectangle style={{ width: 240, height: 120, fill: "navy" }} /> <Text style={{ left: 16, top: 16, fill: "white" }}>JavaScript</Text> </> );}
const controller = pibbl(document.querySelector("canvas"), <Scene />);window.addEventListener("pagehide", () => controller.dispose(), { once: true });JavaScript receives the same runtime validation as TypeScript but not static prop checking. Keep styles explicit and use the diagnostics in JSX troubleshooting.
A complete interactive scene
Section titled “A complete interactive scene”import { Group, Rectangle, Text, pibbl, useSignal, type PibblController, type PibblNode,} from "@pibbl/core";
interface PosterProps { initialMessage: string;}
function Poster({ initialMessage }: PosterProps): PibblNode { const message = useSignal(initialMessage);
return ( <Group> <Rectangle style={{ width: 400, height: 240, fill: "#1f4bd8", cursor: "pointer" }} onClick={() => message.update((old) => (old === "Hello" ? "Pibbl!" : "Hello")) } /> <Text pointerEvents="none" style={{ left: 200, top: 100, fill: "#fff", font: "800 48px sans-serif", textAlign: "center", }} > {message} </Text> </Group> );}
export function mountPoster(canvas: HTMLCanvasElement): PibblController { return pibbl(canvas, <Poster initialMessage="Hello" />);}const controller = mountPoster(document.querySelector("canvas")!);controller.dispose();controller.dispose(); // Idempotent.One runtime per file
Section titled “One runtime per file”A compiler chooses one JSX runtime for the whole file. It cannot switch based on an individual expression. In a React/Preact/Pibbl codebase:
- keep Pibbl JSX in
.pibbl.tsxfiles using the Pibbl pragma or a Pibbl-specific includedtsconfig; - keep host JSX in its own files using the host runtime;
- pass Pibbl component functions across the boundary, not already-created foreign elements;
- when both trees truly belong in one file, keep JSX for the dominant runtime
and build the minority Pibbl tree with
createElement as createPibblElement.
The strict Bundler and NodeNext fixture
playground/package-consumer/jsx.tsx
exercises both compiler subpaths without React installed. See React
coexistence for the full host pattern.
defineThreeLayer() from @pibbl/three returns a normal Pibbl component, so it can
share a Pibbl JSX file without changing the runtime:
import { Rectangle } from "@pibbl/core";import { defineThreeLayer } from "@pibbl/three";
const ProductScene = defineThreeLayer({ create() { // Return an ordinary Three scene and camera. return createProductScene(); },});
const scene = ( <> <Rectangle pointerEvents="none" style={{ width: 320, height: 180 }} /> <ProductScene style={{ width: 320, height: 180 }} /> </>);Continue with Use Three.js inside Pibbl.
Open the interactive workbench
Implementation guidance for agents
Section titled “Implementation guidance for agents”Read the Authoring, signals, and lifecycle companion for ownership, adaptation, failure modes, and verification. Agent start provides the version-selection workflow.
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision c321a83. ALPHA — NOT FOR PRODUCTION USE.