Skip to content

objectFit

objectFit is a utility function from pixi-solid/utils that imperatively applies object-fit style scaling and positioning to any Pixi.Container.

Unlike the ObjectFitContainer component, which wraps children and manages reactive updates automatically, objectFit is a one-shot imperative call. It is well-suited for use inside ref callbacks, createEffect, event handlers, or anywhere you need direct control over when the fit is applied.

It supports these fit modes:

  • contain — scale uniformly to fit within bounds, preserving aspect ratio
  • cover — scale uniformly to fill bounds, preserving aspect ratio (may clip)
  • fill — stretch to fill bounds exactly, ignoring aspect ratio
  • scale-down — same as contain but never scales up beyond original size
  • none — no scaling applied

It also supports these positions:

  • center (default)
  • top, right, bottom, left
  • top-left, top-right, bottom-left, bottom-right
  • { x: number, y: number } where 0 is start, 0.5 is center, and 1 is end

Import it from utils:

import { objectFit } from "pixi-solid/utils";
objectFit(
object: Pixi.Container,
bounds: { width: number; height: number },
fitMode: ObjectFitMode,
position?: ObjectPosition,
): void

The function mutates object.scale, object.x, and object.y in place. It reads the object's local bounds via getLocalBounds() to determine the original dimensions before scaling.

The most common use is inside a ref callback to fit a container once on mount:

import { objectFit } from "pixi-solid/utils";
<Graphics
ref={(graphics) => {
graphics.rect(0, 0, 200, 100).fill(0xff0000);
objectFit(graphics, { width: 400, height: 300 }, "contain");
}}
/>;

To re-apply whenever a signal changes, use createEffect:

import { objectFit } from "pixi-solid/utils";
import { createEffect, createSignal } from "solid-js";
const [fitMode, setFitMode] = createSignal("contain");
let graphicsRef;
createEffect(() => {
if (!graphicsRef) return;
objectFit(graphicsRef, { width: 400, height: 300 }, fitMode());
});
<Graphics
ref={(g) => {
graphicsRef = g;
g.rect(0, 0, 200, 100).fill(0xff0000);
objectFit(g, { width: 400, height: 300 }, fitMode());
}}
/>;
demo-app.tsx
import { Container, Graphics, PixiCanvas, usePixiScreen } from "pixi-solid";
import type { ObjectFitMode, ObjectPosition } from "pixi-solid/utils";
import { objectFit } from "pixi-solid/utils";
import type * as Pixi from "pixi.js";
import type { JSX } from "solid-js";
import { createEffect, createSignal } from "solid-js";
const fitModes: ObjectFitMode[] = ["contain", "cover", "fill", "scale-down", "none"];
type ObjectPositionPreset = Exclude<ObjectPosition, { x?: number; y?: number }>;
const positions: ObjectPositionPreset[] = [
"center",
"top",
"right",
"bottom",
"left",
"top-left",
"top-right",
"bottom-left",
"bottom-right",
];
const bounds = { width: 400, height: 200 };
const DemoScene = (props: { fitMode: ObjectFitMode; objectPosition: ObjectPositionPreset }) => {
const pixiScreen = usePixiScreen();
let graphicsRef: Pixi.Graphics | undefined;
createEffect(() => {
if (!graphicsRef) return;
objectFit(graphicsRef, bounds, props.fitMode, props.objectPosition);
});
return (
<Container
x={pixiScreen.width * 0.5 - bounds.width * 0.5}
y={pixiScreen.height * 0.5 - bounds.height * 0.5}
>
<Graphics
ref={(g) => {
g.rect(0, 0, bounds.width, bounds.height).fill("#aeff00");
}}
/>
<Graphics
ref={(g) => {
graphicsRef = g;
g.rect(0, 0, 100, 200).fill("#bc3232").circle(50, 100, 35).fill("#519d70");
objectFit(g, bounds, props.fitMode, props.objectPosition);
}}
/>
</Container>
);
};
export const DemoApp = (): JSX.Element => {
const [fitMode, setFitMode] = createSignal<ObjectFitMode>("contain");
const [objectPosition, setObjectPosition] = createSignal<ObjectPositionPreset>("center");
return (
<div style={{ display: "grid", gap: "0.75rem" }}>
<label style={{ display: "inline-flex", gap: "0.5rem", "align-items": "center" }}>
<span>Fit mode</span>
<select
value={fitMode()}
onInput={(e) => setFitMode(e.currentTarget.value as ObjectFitMode)}
>
{fitModes.map((mode) => (
<option value={mode}>{mode}</option>
))}
</select>
</label>
<label style={{ display: "inline-flex", gap: "0.5rem", "align-items": "center" }}>
<span>Position</span>
<select
value={objectPosition()}
onInput={(e) => setObjectPosition(e.currentTarget.value as ObjectPositionPreset)}
>
{positions.map((pos) => (
<option value={pos}>{pos}</option>
))}
</select>
</label>
<PixiCanvas style={{ width: "100%", height: "300px" }}>
<DemoScene fitMode={fitMode()} objectPosition={objectPosition()} />
</PixiCanvas>
</div>
);
};