# Render a procedural material
Paint a marble material with a typed palette, resolution, and synchronous renderer.

## APIs demonstrated

- [ProceduralTexture](/reference/components/procedural-texture/) from `@pibbl/core/textures`
- [ProceduralTextureProps](/reference/types/textures/) from `@pibbl/core/textures`
- [texturePalettes](/reference/types/textures/) from `@pibbl/core/textures`
- [TextureKind](/reference/types/textures/) from `@pibbl/core/textures`
- [TexturePalette](/reference/types/textures/) from `@pibbl/core/textures`
- [TextureResolution](/reference/types/textures/) from `@pibbl/core/textures`
- [TextureRenderer](/reference/types/textures/) from `@pibbl/core/textures`
- [TextureRenderFrame](/reference/types/textures/) from `@pibbl/core/textures`

## Complete example

[Plain source](/minimal/textures/texture-procedural-component.tsx). Run as a browser module after the document body exists. TSX uses `jsx: "react-jsx"` and `jsxImportSource: "@pibbl/core"`.

```tsx
/** @jsxImportSource @pibbl/core */
import { pibbl } from "@pibbl/core";
import {
  ProceduralTexture,
  texturePalettes,
  type ProceduralTextureProps,
  type TextureKind,
  type TexturePalette,
  type TextureRenderFrame,
  type TextureRenderer,
  type TextureResolution,
} from "@pibbl/core/textures";

const canvas = document.createElement("canvas");
canvas.width = 320;
canvas.height = 200;
document.body.append(canvas);

const kind: TextureKind = "marble";
const resolution: TextureResolution = { width: 320, height: 200 };
const palette: TexturePalette = texturePalettes.lagoon;
const render: TextureRenderer = (
  context,
  frame: Readonly<TextureRenderFrame>,
) => {
  context.drawImage(frame.source, 0, 0, frame.width, frame.height);
  context.globalCompositeOperation = "destination-in";
  context.drawImage(frame.mask, 0, 0, frame.width, frame.height);
};
const props: ProceduralTextureProps = {
  kind,
  resolution,
  palette,
  seed: 42,
  scale: 2,
  detail: 0.3,
  render,
};
const controller = pibbl(
  canvas,
  <ProceduralTexture {...props} style={{ width: 320, height: 200 }} />,
);
window.addEventListener("pagehide", () => controller.dispose(), { once: true });

```

## Usage notes

- The borrowed source and mask canvases are used only inside the render callback.

## Documentation version

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.
