461 lines
10 KiB
Markdown
461 lines
10 KiB
Markdown
Tileset Generator — Design Document
|
||
1. Overview
|
||
|
||
Tileset Generator is a simple browser-based image tool that lets a user upload an image and convert it into a tileable texture. The tool hides obvious seams by offsetting the image, blending or healing the exposed center seams, and exporting the result as a resized .webp texture suitable for games, web backgrounds, 3D materials, and UI art.
|
||
|
||
The tool should run fully client-side in the browser. No server upload is required.
|
||
|
||
2. Core User Flow
|
||
User opens the Tileset Generator page.
|
||
User uploads or drags in an image.
|
||
The app displays:
|
||
Original preview
|
||
Tileable preview
|
||
Repeated texture preview
|
||
The app shifts the image by 50% horizontally and vertically.
|
||
The app hides the newly exposed seams using a selected seam-repair method.
|
||
User adjusts settings:
|
||
Output size
|
||
Seam blend width
|
||
Repair strength
|
||
Export quality
|
||
Crop or fit behavior
|
||
User exports the result as a .webp file.
|
||
3. Primary Features
|
||
Image Upload
|
||
|
||
Supported formats:
|
||
|
||
.png
|
||
.jpg
|
||
.jpeg
|
||
.webp
|
||
|
||
Input methods:
|
||
|
||
File picker
|
||
Drag and drop
|
||
Optional paste from clipboard
|
||
|
||
The image should be processed locally using browser APIs.
|
||
|
||
Seam Offset
|
||
|
||
The standard tile-generation operation is a 50% offset:
|
||
|
||
Original image:
|
||
|
||
[A B]
|
||
[C D]
|
||
|
||
After 50% offset:
|
||
|
||
[D C]
|
||
[B A]
|
||
|
||
This moves the original outer edges into the center of the image, making seams visible and easier to hide.
|
||
|
||
User-facing option:
|
||
|
||
Offset Mode:
|
||
- Auto 50% offset
|
||
- Horizontal only
|
||
- Vertical only
|
||
- Custom offset
|
||
|
||
For V1, Auto 50% offset is enough.
|
||
|
||
Seam Hiding
|
||
|
||
The exposed seam appears as a vertical and horizontal cross through the center of the offset image.
|
||
|
||
V1 should use a simple but effective blend-based repair approach.
|
||
|
||
V1 Seam Repair Method
|
||
|
||
Use a soft blur/blend region around the center seams:
|
||
|
||
Define a seam band around the vertical center.
|
||
Define a seam band around the horizontal center.
|
||
Sample pixels from both sides of the seam.
|
||
Blend across the seam using a smooth falloff.
|
||
Optionally add subtle noise preservation to avoid overly blurry lines.
|
||
|
||
User controls:
|
||
|
||
Seam Width: 8–128 px
|
||
Blend Strength: 0–100%
|
||
Detail Preservation: Low / Medium / High
|
||
|
||
Default:
|
||
|
||
Seam Width: 32 px
|
||
Blend Strength: 70%
|
||
Detail Preservation: Medium
|
||
Repeated Preview
|
||
|
||
The app should show the generated texture repeated in a grid so the user can visually inspect tiling quality.
|
||
|
||
Preview modes:
|
||
|
||
Single Tile
|
||
2x2 Repeat
|
||
3x3 Repeat
|
||
4x4 Repeat
|
||
|
||
Default:
|
||
|
||
3x3 Repeat
|
||
|
||
This is critical because a texture can look good alone but fail when repeated.
|
||
|
||
Resize and Export
|
||
|
||
The user can export the final image as .webp.
|
||
|
||
Output size options:
|
||
|
||
Original Size
|
||
512 x 512
|
||
1024 x 1024
|
||
2048 x 2048
|
||
Custom Width / Height
|
||
|
||
Resize behavior:
|
||
|
||
Crop to Square
|
||
Fit Within Size
|
||
Stretch to Size
|
||
Keep Aspect Ratio
|
||
|
||
Default:
|
||
|
||
1024 x 1024
|
||
Crop to Square
|
||
WebP Quality: 90
|
||
|
||
Export filename pattern:
|
||
|
||
tileset-generator-[width]x[height].webp
|
||
|
||
Example:
|
||
|
||
tileset-generator-1024x1024.webp
|
||
4. Interface Layout
|
||
Suggested Layout
|
||
+------------------------------------------------------+
|
||
| Tileset Generator |
|
||
| Upload image → Generate tileable WebP texture |
|
||
+------------------------------------------------------+
|
||
|
||
+----------------------+-------------------------------+
|
||
| Controls | Preview |
|
||
| | |
|
||
| Upload Image | [ Single / Repeated Preview ] |
|
||
| Output Size | |
|
||
| Seam Width | |
|
||
| Blend Strength | |
|
||
| Export Quality | |
|
||
| | |
|
||
| [Generate] [Export] | |
|
||
+----------------------+-------------------------------+
|
||
Control Panel
|
||
|
||
Controls should appear in this order:
|
||
|
||
Upload image
|
||
Output size
|
||
Resize behavior
|
||
Seam width
|
||
Blend strength
|
||
Preview repeat count
|
||
WebP quality
|
||
Export button
|
||
5. Recommended Tech Stack
|
||
|
||
For a lightweight browser tool:
|
||
|
||
Vite + React + TypeScript
|
||
Canvas 2D API
|
||
browser-image-compression optional
|
||
FileSaver optional
|
||
|
||
Recommended stack:
|
||
|
||
React for UI
|
||
TypeScript for safer image-processing code
|
||
Canvas 2D API for pixel manipulation
|
||
OffscreenCanvas / Web Worker optional for larger images
|
||
WebP export via canvas.toBlob()
|
||
|
||
No backend required.
|
||
|
||
6. Image Processing Pipeline
|
||
Step 1 — Load Image
|
||
File → Object URL → ImageBitmap → Canvas
|
||
|
||
Use createImageBitmap() when available.
|
||
|
||
Step 2 — Normalize Image
|
||
|
||
Depending on the selected resize behavior:
|
||
|
||
Crop to square
|
||
Fit within output bounds
|
||
Stretch
|
||
Preserve aspect ratio
|
||
|
||
For texture generation, square textures are strongly preferred.
|
||
|
||
Recommended internal working size:
|
||
|
||
1024 x 1024 by default
|
||
Step 3 — Offset Image
|
||
|
||
Draw the source image into a new canvas in four wrapped quadrants.
|
||
|
||
Pseudo-code:
|
||
|
||
function offsetCanvas(source, offsetX, offsetY) {
|
||
draw source shifted by offsetX / offsetY
|
||
wrap overflowing regions to opposite edges
|
||
}
|
||
|
||
For 50% offset:
|
||
|
||
offsetX = width / 2
|
||
offsetY = height / 2
|
||
Step 4 — Repair Seam
|
||
|
||
Repair the vertical seam centered at:
|
||
|
||
x = width / 2
|
||
|
||
Repair the horizontal seam centered at:
|
||
|
||
y = height / 2
|
||
|
||
For each pixel inside the seam band:
|
||
|
||
distanceFromSeam = abs(pixelPosition - seamCenter)
|
||
blendAmount = 1 - smoothstep(0, seamWidth, distanceFromSeam)
|
||
|
||
Blend nearby pixels from both sides of the seam.
|
||
|
||
A simple practical V1 approach:
|
||
|
||
For each seam pixel:
|
||
- Sample left/right or top/bottom neighbor pixels
|
||
- Average them based on distance from seam center
|
||
- Mix the averaged color with the original pixel
|
||
|
||
This gives a soft seam-hiding effect without needing AI/inpainting.
|
||
|
||
Step 5 — Preview Repetition
|
||
|
||
Create a preview canvas or CSS background using the generated image.
|
||
|
||
For repeated preview:
|
||
|
||
background-image: url(generated-texture.webp);
|
||
background-repeat: repeat;
|
||
background-size: tileSize tileSize;
|
||
|
||
Canvas-based repeated preview is also fine.
|
||
|
||
Step 6 — Export WebP
|
||
|
||
Use:
|
||
|
||
canvas.toBlob(
|
||
blob => saveBlob(blob, filename),
|
||
"image/webp",
|
||
quality
|
||
);
|
||
|
||
Where quality is:
|
||
|
||
quality = userQuality / 100;
|
||
7. V1 Scope
|
||
Include in V1
|
||
Local image upload
|
||
Canvas-based 50% offset
|
||
Basic seam blending
|
||
Output resize options
|
||
Repeated texture preview
|
||
WebP export
|
||
Quality slider
|
||
Drag-and-drop support
|
||
Exclude from V1
|
||
AI inpainting
|
||
Multi-texture PBR export
|
||
Normal map generation
|
||
Roughness/metalness map generation
|
||
Batch processing
|
||
Account system
|
||
Server-side processing
|
||
8. Nice-to-Have Features
|
||
|
||
Good V2 additions:
|
||
|
||
Brush-based manual seam repair
|
||
Clone-stamp tool
|
||
Random patch sampling
|
||
Content-aware seam healing
|
||
Generate normal map
|
||
Generate roughness map
|
||
Batch export
|
||
Presets:
|
||
Pixel art
|
||
Stone
|
||
Fabric
|
||
Terrain
|
||
Sci-fi panel
|
||
Organic texture
|
||
Export as:
|
||
.webp
|
||
.png
|
||
.jpg
|
||
Save/load project settings
|
||
Before/after comparison slider
|
||
9. Data Model
|
||
type ResizeMode =
|
||
| "crop-square"
|
||
| "fit"
|
||
| "stretch"
|
||
| "keep-aspect";
|
||
|
||
type PreviewMode =
|
||
| "single"
|
||
| "repeat-2"
|
||
| "repeat-3"
|
||
| "repeat-4";
|
||
|
||
type TilesetSettings = {
|
||
outputWidth: number;
|
||
outputHeight: number;
|
||
resizeMode: ResizeMode;
|
||
seamWidth: number;
|
||
blendStrength: number;
|
||
detailPreservation: "low" | "medium" | "high";
|
||
webpQuality: number;
|
||
previewMode: PreviewMode;
|
||
};
|
||
|
||
Default settings:
|
||
|
||
const defaultSettings: TilesetSettings = {
|
||
outputWidth: 1024,
|
||
outputHeight: 1024,
|
||
resizeMode: "crop-square",
|
||
seamWidth: 32,
|
||
blendStrength: 70,
|
||
detailPreservation: "medium",
|
||
webpQuality: 90,
|
||
previewMode: "repeat-3",
|
||
};
|
||
10. Main Components
|
||
App
|
||
├── UploadPanel
|
||
├── SettingsPanel
|
||
├── PreviewPanel
|
||
│ ├── OriginalPreview
|
||
│ ├── TilePreview
|
||
│ └── RepeatedPreview
|
||
├── ExportPanel
|
||
└── ProcessingWorker optional
|
||
11. Performance Considerations
|
||
|
||
For V1, Canvas 2D is enough.
|
||
|
||
Recommended limits:
|
||
|
||
Max input image size: 4096 x 4096
|
||
Default working size: 1024 x 1024
|
||
Warning above: 2048 x 2048
|
||
|
||
For large files:
|
||
|
||
Downscale before seam repair.
|
||
Use createImageBitmap() for efficient decoding.
|
||
Consider Web Worker processing later.
|
||
Avoid repeatedly processing on every slider movement.
|
||
Debounce setting changes by 150–300 ms.
|
||
12. Error Handling
|
||
|
||
Show user-friendly errors for:
|
||
|
||
Unsupported file type
|
||
Image failed to load
|
||
Image too large
|
||
Browser does not support WebP export
|
||
Canvas export failed
|
||
|
||
Example messages:
|
||
|
||
This file type is not supported. Please upload a PNG, JPG, or WebP image.
|
||
This image is very large. The tool will resize it before processing.
|
||
13. Export Behavior
|
||
|
||
Export button should be disabled until:
|
||
|
||
An image is uploaded
|
||
Processing is complete
|
||
A valid output size exists
|
||
|
||
Export metadata:
|
||
|
||
Format: WebP
|
||
Quality: user-selected
|
||
Dimensions: user-selected
|
||
Color space: browser default / sRGB
|
||
Transparency: preserve if source supports alpha
|
||
14. Practical V1 Algorithm
|
||
1. Load uploaded image.
|
||
2. Resize/crop to target working canvas.
|
||
3. Offset image by 50% width and 50% height.
|
||
4. Blend center vertical seam.
|
||
5. Blend center horizontal seam.
|
||
6. Display single and repeated previews.
|
||
7. Export final canvas as WebP.
|
||
|
||
Pseudo-code:
|
||
|
||
async function generateTileableTexture(file: File, settings: TilesetSettings) {
|
||
const bitmap = await createImageBitmap(file);
|
||
|
||
const normalizedCanvas = normalizeImage(bitmap, settings);
|
||
const offsetCanvas = applyWrappedOffset(
|
||
normalizedCanvas,
|
||
settings.outputWidth / 2,
|
||
settings.outputHeight / 2
|
||
);
|
||
|
||
const repairedCanvas = repairCenterSeams(offsetCanvas, {
|
||
seamWidth: settings.seamWidth,
|
||
blendStrength: settings.blendStrength,
|
||
detailPreservation: settings.detailPreservation,
|
||
});
|
||
|
||
return repairedCanvas;
|
||
}
|
||
15. Success Criteria
|
||
|
||
The tool is successful when:
|
||
|
||
A user can upload an image and export a tileable .webp in under a minute.
|
||
The exported texture repeats without obvious hard seams.
|
||
The UI is understandable without instructions.
|
||
The tool runs fully in-browser.
|
||
The output is usable in game engines, websites, and 3D material workflows.
|
||
16. Suggested MVP Build Order
|
||
Build image upload and preview.
|
||
Add canvas normalization/resizing.
|
||
Implement 50% wrapped offset.
|
||
Add basic vertical/horizontal seam blend.
|
||
Add repeated preview.
|
||
Add WebP export.
|
||
Add settings controls.
|
||
Add drag-and-drop polish.
|
||
Add error handling.
|
||
Test with photos, fabric, stone, clouds, sci-fi panels, and terrain textures. |