Initial commit
This commit is contained in:
@@ -0,0 +1,461 @@
|
|||||||
|
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.
|
||||||
Reference in New Issue
Block a user