Fix ORA editor layer visibility and mask preview
- Layer visibility toggles now show/hide individual layer images on canvas - Added tint red checkbox per layer for manual mask verification - Mask preview modal uses CSS mask-image to show red overlay only on selected areas (white pixels become semi-transparent red, black pixels remain transparent) - Added spinner icons to Open and Extract Mask buttons during long operations
This commit is contained in:
@@ -99,7 +99,8 @@ All file paths are relative to the project root: `/home/noti/dev/ai-game-2`
|
||||
|
||||
| Operation | Description |
|
||||
|-----------|-------------|
|
||||
| **Toggle Visibility** | Show/hide layer on canvas |
|
||||
| **Toggle Visibility** | Show/hide specific layer image on canvas |
|
||||
| **Tint Red Preview** | Apply red tint to layer for mask verification (client-only) |
|
||||
| **Rename** | Change layer/entity name |
|
||||
| **Delete** | Remove layer from ORA |
|
||||
| **Reorder** | Move layer up/down in stack (changes z-index) |
|
||||
@@ -109,18 +110,25 @@ All file paths are relative to the project root: `/home/noti/dev/ai-game-2`
|
||||
|
||||
## Canvas Display
|
||||
|
||||
### Image Rendering
|
||||
- Layers rendered as stacked `<img>` elements with CSS positioning
|
||||
- Base layer at bottom, entity layers stacked above
|
||||
- Visibility controlled by `opacity: 0` or `opacity: 1`
|
||||
### Image Rendering
|
||||
- Individual layers rendered as stacked `<img>` elements with CSS positioning
|
||||
- Layers stacked in order from list (visual z-index matches layer order)
|
||||
- Visibility togglecheckbox hides/shows each layer's image on canvas
|
||||
- Tint checkbox applies semi-transparent red overlay for mask verification (client-only, visual aid)
|
||||
- No server-side compositing for preview
|
||||
|
||||
### Layer DOM Structure
|
||||
```html
|
||||
<div class="relative w-full h-full">
|
||||
<img src="/api/image/base" class="absolute inset-0">
|
||||
<img src="/api/image/door_0" class="absolute inset-0" style="opacity: 1">
|
||||
<img src="/api/image/chest_0" class="absolute inset-0" style="opacity: 0">
|
||||
<!-- Individual layers rendered in order (x-show controls visibility) -->
|
||||
<template x-for="layer in layers">
|
||||
<img
|
||||
x-show="layer.visible"
|
||||
:src="'/api/image/layer/' + layer.name"
|
||||
class="absolute inset-0"
|
||||
:style="layer.tintRed ? 'mix-blend-multiply; opacity: 0.6;' : ''"
|
||||
>
|
||||
</template>
|
||||
<!-- Polygon overlay when active -->
|
||||
<canvas id="polygon-canvas" class="absolute inset-0 pointer-events-auto"></canvas>
|
||||
</div>
|
||||
@@ -193,9 +201,12 @@ canvas.addEventListener('click', (e) => {
|
||||
### Mask Preview Modal
|
||||
When mask is ready:
|
||||
1. Full-screen modal appears
|
||||
2. Shows base image with mask applied as colored tint overlay
|
||||
2. Shows base image with semi-transparent red overlay where the mask is white (selected area)
|
||||
- Uses CSS `mask-image` property to use grayscale values as alpha channel
|
||||
- White pixels = fully opaque red tint, black/dark pixels = transparent (no tint)
|
||||
- Dark/gray areas of the mask remain invisible so you can clearly see the mask boundary
|
||||
3. Three buttons:
|
||||
- **Re-roll**: Re-run extraction with same params
|
||||
- **Re-roll**: Re-run extraction with same params
|
||||
- **Use This Mask**: Add masked layer to ORA, close modal
|
||||
- **Cancel**: Discard mask, close modal
|
||||
|
||||
@@ -355,6 +366,14 @@ Serve a layer PNG. Returns image data.
|
||||
#### `GET /api/image/base`
|
||||
Serve base/merged image.
|
||||
|
||||
#### `GET /api/image/layer/<layer_name>`
|
||||
Serve a specific layer as image.
|
||||
|
||||
**Query params:**
|
||||
- `ora_path`: Path to ORA file
|
||||
|
||||
**Response:** PNG image data or 404 if layer not found.
|
||||
|
||||
#### `GET /api/image/polygon`
|
||||
Serve polygon overlay image (for drawing mode).
|
||||
|
||||
@@ -506,12 +525,13 @@ Check if temp file was modified.
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ [Open: ________________________] [Open File] [Settings ⚙] │
|
||||
│ [Open: ________________________] [🌀 Open] [Settings ⚙] │
|
||||
├───────────────────┬──────────────────────────────────────────────────┤
|
||||
│ LAYERS │ │
|
||||
│ ☑ base │ │
|
||||
│ ☑ door_0 │ [Image Canvas with │
|
||||
│ ☐ chest_0 │ stacked layers] │
|
||||
│ ☑ □ base │ │
|
||||
│ ☑ □ door_0 │ [Image Canvas with │
|
||||
│ ☐ ☒ chest_0 │ stacked layers - visibility toggles │
|
||||
│ │ show/hide individual layer images] │
|
||||
│ │ │
|
||||
│ [Rename] [Delete] │ │
|
||||
│ [▲ Up] [▼ Down] │ │
|
||||
@@ -528,7 +548,7 @@ Check if temp file was modified.
|
||||
│ MASK EXTRACTION │ │
|
||||
│ Subject: [______]│ │
|
||||
│ ☑ Use polygon │ │
|
||||
│ [Extract Mask] │ │
|
||||
│ [🌀 Extract Mask]│ (spinner shown when extracting) │
|
||||
│ │ │
|
||||
│ ─────────────────│ │
|
||||
│ [Open in Krita] │ │
|
||||
@@ -538,6 +558,8 @@ Check if temp file was modified.
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Legend: ☑ = visible checkbox, ☒ = tint red checkbox (red when checked)
|
||||
|
||||
---
|
||||
|
||||
## Mask Preview Modal
|
||||
@@ -547,7 +569,8 @@ Check if temp file was modified.
|
||||
│ EXTRACTED MASK │
|
||||
│ ───────────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ [Base image with mask applied as tinted overlay] │
|
||||
│ [Base image with RED mask overlay] │
|
||||
│ (mask shown in semi-transparent red) │
|
||||
│ │
|
||||
│ [Re-roll] [Use This Mask] [Cancel] │
|
||||
│ │
|
||||
@@ -557,6 +580,7 @@ Check if temp file was modified.
|
||||
- **Re-roll**: Re-runs extraction with same params
|
||||
- **Use This Mask**: Calls `POST /api/layer/add`, closes modal
|
||||
- **Cancel**: Closes modal, mask discarded
|
||||
- **Red tint**: Uses CSS filter to render grayscale mask as semi-transparent red
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user