React integration for PixiJS enabling declarative 2D graphics programming with JSX and React patterns.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
@pixi/react provides type-safe JSX elements for all PixiJS components through a sophisticated type system. Components must be registered with extend() before use, supporting both prefixed and unprefixed usage patterns.
All extended PixiJS components are available as JSX elements with automatic type safety and event handling.
/**
* Type-safe JSX elements for PixiJS components
* Components must be registered via extend() before use
*/
interface PixiElements extends PrefixedPixiElements {}
type PrefixedPixiElements = {
[K in keyof UnprefixedPixiElements as `pixi${Capitalize<string & K>}`]: UnprefixedPixiElements[K];
};
type UnprefixedPixiElements = {
[K in PixiComponents as K extends keyof NameOverrides ? NameOverrides[K] : Uncapitalize<K>]:
PixiReactElementProps<typeof PIXI[K]>;
};
type PixiReactElementProps<T extends new (...args: any) => any> =
BaseNodeProps<InstanceType<T>>
& GraphicsProps<InstanceType<T>>
& EventHandlers
& ConstructorOptions<T>;Usage Examples:
import { extend } from "@pixi/react";
import { Container, Graphics, Text, Sprite } from "pixi.js";
extend({ Container, Graphics, Text, Sprite });
// Basic element usage
const BasicElements = () => (
<pixiContainer x={100} y={100} alpha={0.8}>
<pixiText
text="Hello World!"
x={50}
y={50}
style={{ fontSize: 24, fill: "white" }}
/>
<pixiSprite
texture={myTexture}
anchor={0.5}
interactive
onPointerDown={(event) => console.log("Clicked!", event)}
/>
</pixiContainer>
);
// All PixiJS properties are supported
const AdvancedElements = () => (
<pixiContainer
x={200}
y={150}
rotation={Math.PI / 4}
scale={{ x: 1.5, y: 1.5 }}
pivot={{ x: 50, y: 50 }}
alpha={0.9}
visible={true}
interactive={true}
interactiveChildren={true}
hitArea={new Rectangle(0, 0, 100, 100)}
mask={maskGraphics}
filters={[blurFilter]}
zIndex={10}
>
<pixiGraphics
draw={(graphics) => {
graphics.clear();
graphics.setFillStyle({ color: "red" });
graphics.rect(0, 0, 100, 100);
graphics.fill();
}}
interactive
onPointerMove={(event) => {
console.log("Mouse position:", event.global.x, event.global.y);
}}
/>
</pixiContainer>
);Graphics components have special support for the draw callback function.
/**
* Graphics elements support special draw callback for rendering
*/
type GraphicsProps<T> = T extends Graphics ? { draw: DrawCallback } : unknown;
type DrawCallback = (graphics: Graphics) => void;Usage Examples:
import { extend } from "@pixi/react";
import { Graphics } from "pixi.js";
import { useCallback, useState } from "react";
extend({ Graphics });
// Simple graphics drawing
const SimpleGraphics = () => {
const drawRect = useCallback((graphics: Graphics) => {
graphics.clear();
graphics.setFillStyle({ color: "blue" });
graphics.rect(0, 0, 100, 100);
graphics.fill();
}, []);
return <pixiGraphics draw={drawRect} x={100} y={100} />;
};
// Dynamic graphics with state
const DynamicGraphics = () => {
const [color, setColor] = useState("red");
const drawCircle = useCallback((graphics: Graphics) => {
graphics.clear();
graphics.setFillStyle({ color });
graphics.circle(0, 0, 50);
graphics.fill();
graphics.setStrokeStyle({ color: "white", width: 2 });
graphics.stroke();
}, [color]);
return (
<pixiContainer>
<pixiGraphics
draw={drawCircle}
x={200}
y={200}
interactive
onPointerTap={() => {
const colors = ["red", "green", "blue", "yellow"];
const nextColor = colors[Math.floor(Math.random() * colors.length)];
setColor(nextColor);
}}
/>
</pixiContainer>
);
};
// Complex graphics shapes
const ComplexGraphics = () => {
const drawShape = useCallback((graphics: Graphics) => {
graphics.clear();
// Draw a star shape
graphics.setFillStyle({
color: "gold",
alpha: 0.8
});
const outerRadius = 60;
const innerRadius = 30;
const points = 5;
graphics.moveTo(outerRadius, 0);
for (let i = 1; i <= points * 2; i++) {
const radius = i % 2 === 0 ? outerRadius : innerRadius;
const angle = (i * Math.PI) / points;
graphics.lineTo(
Math.cos(angle) * radius,
Math.sin(angle) * radius
);
}
graphics.closePath();
graphics.fill();
// Add stroke
graphics.setStrokeStyle({ color: "orange", width: 3 });
graphics.stroke();
}, []);
return <pixiGraphics draw={drawShape} x={300} y={300} />;
};All PixiJS events are supported with automatic type conversion from React event props.
/**
* Event handlers for PixiJS interaction events
* React event prop names are automatically converted to PixiJS event names
*/
interface EventHandlers {
// Pointer events
onPointerDown?: (event: FederatedPointerEvent) => void;
onPointerUp?: (event: FederatedPointerEvent) => void;
onPointerMove?: (event: FederatedPointerEvent) => void;
onPointerTap?: (event: FederatedPointerEvent) => void;
onPointerOver?: (event: FederatedPointerEvent) => void;
onPointerOut?: (event: FederatedPointerEvent) => void;
onPointerEnter?: (event: FederatedPointerEvent) => void;
onPointerLeave?: (event: FederatedPointerEvent) => void;
// Mouse events
onMouseDown?: (event: FederatedMouseEvent) => void;
onMouseUp?: (event: FederatedMouseEvent) => void;
onMouseMove?: (event: FederatedMouseEvent) => void;
onMouseOver?: (event: FederatedMouseEvent) => void;
onMouseOut?: (event: FederatedMouseEvent) => void;
// Touch events
onTouchStart?: (event: FederatedTouchEvent) => void;
onTouchEnd?: (event: FederatedTouchEvent) => void;
onTouchMove?: (event: FederatedTouchEvent) => void;
// Wheel events
onWheel?: (event: FederatedWheelEvent) => void;
}Usage Examples:
// Interactive sprite with multiple event handlers
const InteractiveSprite = ({ texture }) => {
const [isHovered, setIsHovered] = useState(false);
const [isPressed, setIsPressed] = useState(false);
return (
<pixiSprite
texture={texture}
interactive
alpha={isHovered ? 0.8 : 1}
scale={isPressed ? 0.9 : 1}
onPointerEnter={() => setIsHovered(true)}
onPointerLeave={() => setIsHovered(false)}
onPointerDown={() => setIsPressed(true)}
onPointerUp={() => setIsPressed(false)}
onPointerTap={(event) => {
console.log("Tapped at:", event.global.x, event.global.y);
}}
onRightClick={(event) => {
event.preventDefault();
console.log("Right clicked!");
}}
/>
);
};
// Draggable container
const DraggableContainer = ({ children }) => {
const [isDragging, setIsDragging] = useState(false);
const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
const [position, setPosition] = useState({ x: 0, y: 0 });
return (
<pixiContainer
x={position.x}
y={position.y}
interactive
onPointerDown={(event) => {
setIsDragging(true);
setDragStart({
x: event.global.x - position.x,
y: event.global.y - position.y,
});
}}
onPointerMove={(event) => {
if (isDragging) {
setPosition({
x: event.global.x - dragStart.x,
y: event.global.y - dragStart.y,
});
}
}}
onPointerUp={() => setIsDragging(false)}
onPointerUpOutside={() => setIsDragging(false)}
>
{children}
</pixiContainer>
);
};All PixiJS component properties are supported with full type safety.
/**
* Base properties available on all PixiJS components
*/
interface BaseNodeProps<T> {
/** Child components (Container types only) */
children?: T extends Container ? PixiReactChildNode : never;
/** React key for list rendering */
key?: Key;
/** React ref for imperative access */
ref?: Ref<T>;
}
/**
* Constructor options and properties from PixiJS components
* Automatically inferred from the component class
*/
type ConstructorOptions<T> = ExcludeFunctionProps<T>;Usage Examples:
// Container with all supported properties
const FullContainer = () => (
<pixiContainer
// Transform properties
x={100}
y={150}
rotation={Math.PI / 6}
scale={{ x: 1.2, y: 1.2 }}
skew={{ x: 0.1, y: 0 }}
pivot={{ x: 50, y: 50 }}
anchor={0.5} // If supported by component
// Display properties
alpha={0.8}
visible={true}
renderable={true}
// Interaction properties
interactive={true}
interactiveChildren={true}
buttonMode={true}
cursor="pointer"
// Rendering properties
mask={maskObject}
filters={[blurFilter, colorFilter]}
cacheAsBitmap={false}
// Layout properties
zIndex={5}
sortableChildren={true}
// Event properties
onPointerDown={(event) => console.log("Clicked")}
>
{/* Children go here */}
</pixiContainer>
);
// Text with typography properties
const StyledText = () => (
<pixiText
text="Styled Text"
style={{
fontFamily: "Arial",
fontSize: 24,
fill: "white",
stroke: "black",
strokeThickness: 2,
fontWeight: "bold",
textAlign: "center",
}}
anchor={0.5}
x={400}
y={300}
/>
);
// Sprite with texture properties
const ConfiguredSprite = ({ texture }) => (
<pixiSprite
texture={texture}
anchor={{ x: 0.5, y: 1 }}
tint="0xff0000"
blendMode="multiply"
pluginName="batch"
roundPixels={true}
/>
);The JSX element system provides comprehensive type safety:
draw prop only available on Graphics componentsComponents must be registered before use:
import { extend } from "@pixi/react";
import { Container, Graphics, Text, Sprite, AnimatedSprite } from "pixi.js";
// Register before using in JSX
extend({
Container, // Available as <pixiContainer>
Graphics, // Available as <pixiGraphics>
Text, // Available as <pixiText>
Sprite, // Available as <pixiSprite>
AnimatedSprite, // Available as <pixiAnimatedSprite>
});Attempting to use unregistered components will result in TypeScript errors and runtime warnings.
Install with Tessl CLI
npx tessl i tessl/npm-pixi--react