
Threejs Image Generator
- 1.1k installs
- 1.2k repo stars
- Updated July 16, 2026
- majidmanzarpour/threejs-game-skills
Helps with ai & agent building tasks.
About
threejs-image-generator is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- threejs-image-generator
- AI & Agent Building
- AI-coding skill
Threejs Image Generator by the numbers
- 1,056 all-time installs (skills.sh)
- +108 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #995 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/majidmanzarpour/threejs-game-skills --skill threejs-image-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.1k |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | July 16, 2026 |
| Repository | majidmanzarpour/threejs-game-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Three.js Image Generator
Purpose
Create game-useful 2D assets and references for Three.js projects. This skill is the image-generation layer for the Three.js game system: it produces concepts, textures, decals, UI art, and 2D inputs that can be handed to threejs-3d-generator for image-to-3D model creation.
Provider: Google's Gemini image API.
When To Use
Use this skill before procedural-only fallback when a Three.js game needs:
- 2D-to-3D reference images for
threejs-3d-generator: characters, creatures, buildings, ships, cars, weapons, props, pickups, terrain modules. - Texture and material references: terrain, road, rock, sand, metal, sci-fi panels, trim sheets, decals, hazard labels, signs.
- Environment images: skies, backdrops, city horizons, nebula plates, menu backgrounds, parallax layers.
- UI art: logos, faction marks, icons, item cards, ability badges, cockpit decals, GUI panels, title art.
- Existing-image edits, style variants, cleanup, palette alignment, or concept sheet refinements.
For premium/AAA/showcase graphics work, generate at least one relevant image for high-value 2D surfaces or image-to-3D inputs unless the credential probe or a real generation attempt shows a blocker.
API Key
Never store API keys in skill files or browser/game code. The script checks:
1. --api-key 2. GEMINI_API_KEY
Before declaring the key unavailable in a threejs-game-director or threejs-aaa-graphics-builder workflow, run the director credential probe and paste its literal SET/MISSING output:
bash ~/.codex/skills/threejs-game-director/scripts/probe_asset_credentials.shFor Claude installs:
bash ~/.claude/skills/threejs-game-director/scripts/probe_asset_credentials.shIf the probe says GEMINI_API_KEY=SET but the script sees no key, run through a shell that sources the user's profile:
zsh -c 'source "$HOME/.zprofile" 2>/dev/null; source "$HOME/.zshrc" 2>/dev/null; uv run ~/.codex/skills/threejs-image-generator/scripts/generate_image.py --prompt "..." --filename assets/concepts/example.png'Tool Script
Run from the user's current project directory so output lands in the game project:
uv run ~/.codex/skills/threejs-image-generator/scripts/generate_image.py --prompt "your image description" --filename assets/concepts/output.png --resolution 2KClaude install path:
uv run ~/.claude/skills/threejs-image-generator/scripts/generate_image.py --prompt "your image description" --filename assets/concepts/output.png --resolution 2KEdit an existing image:
uv run ~/.codex/skills/threejs-image-generator/scripts/generate_image.py \
--input-image assets/concepts/ship.png \
--prompt "turn this into a battle-worn red racing livery with clearer material zones" \
--filename assets/concepts/ship-red-livery.png \
--resolution 2KResolution mapping:
1K: quick concepts, icons, draft sheets.2K: default production reference for image-to-3D, textures, backgrounds, UI panels.4K: hero splash/title art, high-detail texture references, large sky/background plates.
Prompt Patterns
Image-to-3D reference:
Create a clean 3D-generation reference image of [asset]. Centered single object, full object visible, plain light background, readable silhouette, clear material zones, game-ready [genre/style], no motion blur, no cropped parts, no text.Riggable character/creature reference:
Create a full-body [T-pose/A-pose/side-view creature] reference for 3D rigging: [details]. Symmetric stance, visible hands/feet/limbs, plain background, readable costume/anatomy layers, no weapon fused to hands.Texture/material reference:
Create a seamless game texture reference for [surface]. Orthographic/top-down, PBR-friendly albedo, clear material variation, no perspective, no baked strong shadows, [style/material details].Logo/icon/UI art:
Create a crisp game UI [logo/icon/badge/panel] for [faction/item/ability]. Transparent-friendly silhouette, high contrast at small size, [genre styling], no tiny unreadable text.Sky/background:
Create a wide game background plate of [environment]. Layered depth, readable horizon, [time/weather/style], suitable behind a real-time Three.js scene, no foreground subject.Three.js Integration Rules
- Save concepts and image-to-3D sources under
assets/concepts/. - Save textures, decals, icons, and GUI source images under
assets/textures/,assets/decals/, orassets/ui/. - For image-to-3D, hand the saved image path to
threejs-3d-generatorand record the chain in the external asset ledger. - Do not call the image API from client-side game code.
- Convert generated PNGs into runtime formats deliberately: PNG for alpha/UI, JPG/WebP/KTX2 for larger opaque textures where the project pipeline supports it.
- Verify how the image appears in game, not only that the file exists.
Required Report
Report:
- Credential probe output or command blocker.
- Prompt and purpose.
- Output path.
- Resolution.
- Whether the image was used directly, edited further, or handed to
threejs-3d-generator. - Any remaining integration work such as compression, UV assignment, alpha cleanup, or atlas packing.
Do not mark a premium graphics phase complete if the needed image outputs are missing and the only justification is "procedural is enough" for high-value UI, texture, sky, decal, logo, or image-to-3D surfaces.
interface:
display_name: "Three.js Image Generator"
short_description: "Generate concepts, textures, icons, decals, and UI art for Three.js games"
default_prompt: "Generate or edit a game-useful image asset for a Three.js project. Run the credential probe before declaring the key unavailable, save outputs inside the project assets directory, and report the prompt, resolution, output path, intended runtime use, and whether the image feeds threejs-3d-generator."
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "google-genai>=1.0.0",
# "pillow>=10.0.0",
# ]
# ///
"""
Generate images using Google's Gemini image API.
Usage:
uv run generate_image.py --prompt "your image description" --filename "output.png" [--resolution 1K|2K|4K] [--api-key KEY]
"""
import argparse
import os
import sys
from pathlib import Path
def get_api_key(provided_key: str | None) -> str | None:
"""Get API key from argument first, then environment."""
if provided_key:
return provided_key
return os.environ.get("GEMINI_API_KEY")
def main():
parser = argparse.ArgumentParser(
description="Generate images using Google's Gemini image API"
)
parser.add_argument(
"--prompt", "-p",
required=True,
help="Image description/prompt"
)
parser.add_argument(
"--filename", "-f",
required=True,
help="Output filename (e.g., sunset-mountains.png)"
)
parser.add_argument(
"--input-image", "-i",
help="Optional input image path for editing/modification"
)
parser.add_argument(
"--resolution", "-r",
choices=["1K", "2K", "4K"],
default="1K",
help="Output resolution: 1K (default), 2K, or 4K"
)
parser.add_argument(
"--api-key", "-k",
help="Gemini API key (overrides GEMINI_API_KEY env var)"
)
args = parser.parse_args()
# Get API key
api_key = get_api_key(args.api_key)
if not api_key:
print("Error: No API key provided.", file=sys.stderr)
print("Please either:", file=sys.stderr)
print(" 1. Provide --api-key argument", file=sys.stderr)
print(" 2. Set GEMINI_API_KEY environment variable", file=sys.stderr)
sys.exit(1)
# Import here after checking API key to avoid slow import on error
from google import genai
from google.genai import types
from PIL import Image as PILImage
# Initialise client
client = genai.Client(api_key=api_key)
# Set up output path
output_path = Path(args.filename)
output_path.parent.mkdir(parents=True, exist_ok=True)
# Load input image if provided
input_image = None
output_resolution = args.resolution
if args.input_image:
try:
input_image = PILImage.open(args.input_image)
print(f"Loaded input image: {args.input_image}")
# Auto-detect resolution if not explicitly set by user
if args.resolution == "1K": # Default value
# Map input image size to resolution
width, height = input_image.size
max_dim = max(width, height)
if max_dim >= 3000:
output_resolution = "4K"
elif max_dim >= 1500:
output_resolution = "2K"
else:
output_resolution = "1K"
print(f"Auto-detected resolution: {output_resolution} (from input {width}x{height})")
except Exception as e:
print(f"Error loading input image: {e}", file=sys.stderr)
sys.exit(1)
# Build contents (image first if editing, prompt only if generating)
if input_image:
contents = [input_image, args.prompt]
print(f"Editing image with resolution {output_resolution}...")
else:
contents = args.prompt
print(f"Generating image with resolution {output_resolution}...")
try:
response = client.models.generate_content(
model="gemini-3-pro-image-preview",
contents=contents,
config=types.GenerateContentConfig(
response_modalities=["TEXT", "IMAGE"],
image_config=types.ImageConfig(
image_size=output_resolution
)
)
)
# Process response and convert to PNG
image_saved = False
for part in response.parts:
if part.text is not None:
print(f"Model response: {part.text}")
elif part.inline_data is not None:
# Convert inline data to PIL Image and save as PNG
from io import BytesIO
# inline_data.data is already bytes, not base64
image_data = part.inline_data.data
if isinstance(image_data, str):
# If it's a string, it might be base64
import base64
image_data = base64.b64decode(image_data)
image = PILImage.open(BytesIO(image_data))
# Ensure RGB mode for PNG (convert RGBA to RGB with white background if needed)
if image.mode == 'RGBA':
rgb_image = PILImage.new('RGB', image.size, (255, 255, 255))
rgb_image.paste(image, mask=image.split()[3])
rgb_image.save(str(output_path), 'PNG')
elif image.mode == 'RGB':
image.save(str(output_path), 'PNG')
else:
image.convert('RGB').save(str(output_path), 'PNG')
image_saved = True
if image_saved:
full_path = output_path.resolve()
print(f"\nImage saved: {full_path}")
else:
print("Error: No image was generated in the response.", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error generating image: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()