Skip to main content

texture-generator

Generate random material textures with Python: metal, plastic, wood and paper, as Pillow images or NumPy arrays. Choose a size and seed to create a reproducible texture, then save it as a PNG. Generation runs locally using NumPy and Pillow, without models, downloaded assets or network access.

⚠️ Much of this is AI-generated, and not formally reviewed by hand or eye. It's published chiefly for myself: for my own reference, use, and for experimentation with the whole open-source publishing process. I also use this code: I dogfood it. It works, for me. I also write tests, and run them to check that it works, and does what it says.

Installation

Requires Python 3.12 or later. CI covers Python 3.12, 3.13 and 3.14 with locked dependencies and the lowest compatible NumPy/Pillow wheels and Click release.

pip install texture-generator

The distribution is named texture-generator; the Python import is texture_generators, and the command-line program is texture-gen. Installation includes NumPy, Pillow and Click (used by the CLI).

Quickstart

from texture_generators import generate

image = generate("wood", size=(640, 480), seed=42, variant="board")
image.save("wood.png")
print(image.mode, image.size)
# RGB (640, 480)

This writes wood.png in the current directory. Sizes are (width, height); an integer such as size=512 creates a square. Both dimensions must be at least 2 pixels. The same arguments reproduce the same image with the same package, dependency versions and platform. Omit seed for a fresh texture.

For raw pixels or a labelled sheet of every variant:

from texture_generators import generate_array, sample_sheet

pixels = generate_array("metal", size=256, seed=7, variant="brushed")
print(pixels.shape, pixels.dtype)
# (256, 256, 3) float32

sheet = sample_sheet(size=128, seed=7)
sheet.save("materials.png")

Arrays contain RGB values in [0, 1]. The API reference covers all public functions and material parameters.

Brushing direction

From version 0.4.0, set brush_angle for the brushed metal variant. Angles are degrees clockwise in image coordinates: 0 is horizontal, 90 is vertical, and 45 runs from top left to bottom right. Finite angles wrap at 360 degrees.

image = generate("metal", size=(640, 480), seed=42, variant="brushed", brush_angle=90)
image.save("vertical-brushing.png")

The same keyword works with generate_array(), and can be combined with a metal film override. It controls grooves, scratches, directional shading, sheen and glints, plus groove diffraction on unfilmed metal. The light itself keeps its direction. Omit brush_angle or use None to retain the random direction and existing seeded output. An explicit angle requires material="metal" and variant="brushed".

These examples share seed 42 and a size of 384 × 256 pixels:

0° — horizontal 45° 90° — vertical 135°
Horizontal brushed metal, 0 degrees Diagonal brushed metal, 45 degrees clockwise Vertical brushed metal, 90 degrees Diagonal brushed metal, 135 degrees clockwise

Command line

texture-gen wood --variant board --size 640x480 --seed 42 -o wood.png
texture-gen list
texture-gen sheet --size 128 --seed 7 -o materials.png
texture-gen wood --help
texture-gen metal --variant brushed --brush-angle 90 --seed 42 -o vertical-brushing.png

python -m texture_generators runs the same CLI. It also supports batches, JSON reports, shell completion and browser galleries for comparing seeds and parameters. See the CLI reference.

--brush-angle is available on metal and requires --variant brushed. It also works with --count; JSON reports include the angle when it is supplied.

Materials

Material Variants
Metal brushed, radial, polished, heat_tinted, oil_film, anodised_titanium, engine_turned
Plastic glossy, matte, textured
Wood board, planks
Paper white, kraft, recycled, newsprint, laid, coated

Both wood variants support pine, maple, ash, oak, cherry, walnut, sapele and mahogany; select one with species= in Python, and see the species gallery below or the parameter reference.

image = generate("wood", size=(640, 480), seed=42, variant="board", species="oak")

The generators combine noise, material anatomy and lighting. Albedo, height and roughness share underlying fields so visible features also affect shading. These are procedural approximations with documented calibration assumptions. Metal, plastic and wood do not tile seamlessly; paper tiles when creases are disabled with creases=0.0. Wood's relief is carried in real millimetres, so the same board shades the same at any render size; the documented workflow is to render at 1000 px or more and resample down, which is what the mip test checks.

Read the technical reference for the algorithms, wood and paper models, core modules, performance estimates and limitations. See the changelog for changes and GitHub issues to report a bug.

Examples

Every variant below is rendered at 384 × 384 pixels with seed 42 and an explicit variant name. The full results gallery includes the notebook's outputs and links to each PNG; the recipe manifest records how they were generated.

Metal

Brushed Radial Polished Heat tinted
Brushed metal texture Radial metal texture Polished metal texture Heat tinted metal texture
Oil film Anodised titanium Engine turned
Oil film metal texture Anodised titanium metal texture Engine turned metal texture

Plastic

Glossy Matte Textured
Glossy plastic texture Matte plastic texture Textured plastic texture

Wood

Variants

Board Planks
Board wood texture Planks wood texture

Species

Boards and planks are rendered in eight species. These tiles share seed 42 at 384 × 384 pixels and differ only by species; the other draws are pinned to variant="board", cut="flatsawn", figure="plain", finish="oil", colour_variation=0, mm_across=180, knots=0 and sapwood=0. Omitting species makes a uniform seeded choice.

Pine Maple Ash Oak
Pine wood texture Maple wood texture Ash wood texture Oak wood texture
Cherry Walnut Sapele Mahogany
Cherry wood texture Walnut wood texture Sapele wood texture Mahogany wood texture

Wood's chatoyance — the way figured grain flashes light and dark — lives in the reflection, not the pigment, so it only shows up once light_dir moves. The workflow notebook renders one board six times under different light azimuths and pastes the tiles into a strip: curly maple, quartersawn oak.

Paper

White Kraft Recycled
White paper texture Kraft paper texture Recycled paper texture
Newsprint Laid Coated
Newsprint paper texture Laid paper texture Coated paper texture

Run the notebook

Open the workflow notebook to work through the importable Python API, save images and arrays as PNGs, and build a contact sheet. Preview the standalone wood image, metal array saved as an image and contact sheet.

From the repository root, install the optional notebook tools and launch JupyterLab:

uv sync --group examples
uv run --group examples jupyter lab examples/texture_generator_workflow.ipynb

Choose Run → Run All Cells. The notebook writes the separate PNGs to examples/images/, records their recipes in examples/manifest.json, and regenerates examples/results.md. Notebook tools live in the optional examples dependency group.

Development

Install uv, then:

git clone https://github.com/nmpowell/texture-generator.git
cd texture-generator
uv sync --locked
uv run pytest
uv run ruff check .
uv run ruff format --check .

uv sync --locked installs the project editable and uses the committed lockfile. The .python-version file selects Python 3.14 for development; pass --python 3.12 or --python 3.13 to uv sync and uv run to use an older supported interpreter. See the release guide for commands to check locked and minimum runtime dependencies on all three versions in separate environments. Minimum checks preserve the locked development tools and leave uv.lock unchanged. Use uv run ruff format . to apply formatting. The tests exercise rendering, determinism, material physics, the CLI and built-package contents. Internal mypy checks have existing findings and are informational; see the development notes.

The version lives in pyproject.toml; texture_generators.__version__ reads the installed package metadata. The release guide covers artifact checks and Trusted Publishing.

License

Apache License 2.0.

Metadata

Release files for texture-generator 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for texture-generator 0.6.0
File Size Uploaded
texture_generator-0.6.0.tar.gz 8.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for texture-generator 0.6.0
File Interpreter ABI Platform
texture_generator-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 9.1 MB

Release files / texture_generator-0.6.0.tar.gz

Download URL texture_generator-0.6.0.tar.gz
Size 8.9 MB
Tags Source
SHA-256 checksum
How to use checksums
b8fbf48fac4fcdfa8f91b607c5f93386698521bdcae04be28308d665a6bce48d
BLAKE2b-256 checksum
How to use checksums
f3cff3b59cf486e4a52ab6b5b6cd325c6a7ed47b7899d8b29d5babc15fc22ab1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / texture_generator-0.6.0-py3-none-any.whl

Download URL texture_generator-0.6.0-py3-none-any.whl
Size 166.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
323397da448a0161b8b5261bff3f181cae991f2ba9380ff6c4602f77770143dd
BLAKE2b-256 checksum
How to use checksums
208661c6e4abd11196ee3d5e8737ac6c90aefe079adb19754b65975a3039b50d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.0

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page