- Created `EnlargableImage` component in `src/ui/components/EnlargableImage.tsx`.
- Updated `ExtractionStage` to use `EnlargableImage` for displaying extraction results.
- Supports full-screen image viewing with zoom-in/out cursors and click-to-close behavior.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Refactor Extractor workflow to use atomic extraction
* Refactor Extractor workflow to use atomic extraction
* Refactor Extractor workflow to use atomic, sequential extraction
* fix(extractor): resolve overflow issues in SelectionStage
- Constrain `ScrollArea` in `SelectionStage` with `min-h-0` to ensure proper scrolling within flex container.
- Add `overflow-hidden` to `SelectionStage` container.
- Add `overflow-hidden` to `ExtractorDialog` content area to prevent content spillover.
- Ensure header in `SelectionStage` does not shrink (`shrink-0`).
* fix: ensure equipment is updated on re-extraction
- Verified that `src/api/extract.ts` uses `equipmentService.updateEquipment` when `previousEquipmentId` is provided.
- Confirmed that `src/service/equipment.ts` performs an SQL UPDATE and cleans up the old asset file.
- No new code changes were needed as the previous submission already covered this requirement.
* fix: use default extract model in re-extract dialog
- Updated `ExtractorDialog` to fetch `default_extract_model` from settings.
- Passed `defaultModel` to `ExtractionStage`.
- Updated `ExtractionStage` to initialize the re-extract model selection with `defaultModel`.
* fix: correct setting key for default extract model
- Updated `ExtractorDialog` to use `step_refine_model` instead of `default_extract_model` to fetch the default extraction model from settings, as confirmed by the `ExtractionFlowDesigner` configuration.
* fix: update extraction stage layout and buttons
- Enforced a square aspect ratio for the image container in extraction cards using `aspect-square`.
- Removed the "Cancel" button from the footer in `ExtractionStage`.
- Updated the footer to be always visible.
- Changed the "Finish" button to display "Extracting..." and be disabled while extraction is in progress, and "Finish" when complete.
* fix: resolve lint errors and refine extraction UI
- Removed unused `onCancel` prop from `ExtractionStage` to fix linting error.
- Updated `ExtractorDialog` to remove the unused `onCancel` callback passed to `ExtractionStage`.
- Ensured consistent image sizing (square aspect ratio) in extraction cards.
- Refined footer behavior to always show actions, with dynamic "Extracting..." state.
* refine ui
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: yiling ji <njjyl723@gmail.com>
* Add Chinese README and language switcher
* Add Chinese README and language switcher
* Update READMEs with model recommendation for Refine Asset step
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Fix `RefineStage` overflow by applying `overflow-hidden` to the parent container and `min-h-0` to the `ScrollArea`.
- Update `generateTextureSheet` to use Chroma Green background.
- Update `refineAsset` prompt to extract the main equipment into a white background, using name and description for context.
- Update tests and API to support these changes.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Update Look Details Dialog with image zoom and scrollable list
* add missing migration
* minor change
* fix test
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: yiling ji <njjyl723@gmail.com>
- Updated `getGridDimensions` in `src/service/extraction.ts` to use a 2x2 grid for 4 or fewer assets, and a 3x3 grid otherwise.
- Updated `src/service/extraction.test.ts` to reflect the new grid dimensions in the `cropAssets` test.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Renamed the keyframes in `AnalyzeStage.tsx` to `scanline-analyze` to prevent conflict with the global `scanline` animation.
Also removed unused `scanline` keyframes from `RefineStage.tsx` to avoid potential future conflicts.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* feat(ai): use OpenAI Image Edit API instead of Responses API
Replaces the deprecated/unofficial Responses API usage for image generation with the standard `client.images.edit` API.
This change supports multi-image inputs and follows the user's provided example for `gpt-image-1.5` model compatibility.
- Updates `generateImageOpenAI` in `src/service/ai.ts` to use `client.images.edit`.
- Handles conversion of text prompts and inline/reference images to the required format using `toFile`.
- Updates `src/service/ai.test.ts` to mock the new API call and verify correct behavior.
* feat(ai): use OpenAI Image Edit API instead of Responses API
Replaces the deprecated/unofficial Responses API usage for image generation with the standard `client.images.edit` API.
This change supports multi-image inputs and follows the user's provided example for `gpt-image-1.5` model compatibility.
- Updates `generateImageOpenAI` in `src/service/ai.ts` to use `client.images.edit`.
- Removes `response_format` parameter as it's not supported/needed for GPT image models (which default to base64).
- Handles conversion of text prompts and inline/reference images to the required format using `toFile`.
- Updates `src/service/ai.test.ts` to mock the new API call and verify correct behavior.
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Fix toast visibility z-index issue and Create Look dialog error handling
- Moved `<Toaster />` outside of `SidebarProvider` in `Layout.tsx` and increased z-index to ensure toasts appear above dialog overlays.
- Updated `CreateLookDialog.tsx` to use `toast.error()` for API errors instead of displaying them inline at the bottom of the dialog.
* Fix Extractor error handling, toast visibility, and Create Look dialog errors
- Updated `ExtractorDialog.tsx` to reset the stage to `'selection'` on refinement error, preventing infinite loading.
- Updated `CreateLookDialog.tsx` to use `toast.error()` for API errors instead of inline text.
- Moved `<Toaster />` in `Layout.tsx` outside of `SidebarProvider` to ensure toasts appear above dialog overlays.
- Ensured `package.json` and `sonner.tsx` remain clean (reverted temporary changes).
* fix sonner
* fix lint
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: yiling ji <njjyl723@gmail.com>
- Moved `GithubIcon` to `src/ui/components/Icons.tsx` as `Icons.Github`.
- Updated `src/ui/Layout.tsx` to use the new `Icons.Github` component.
- Increased icon size to `h-7 w-7`.
- Deleted `src/ui/components/GithubIcon.tsx`.
- Removed `subCategory` field from Equipment model (DB), API, and UI.
- Generated Prisma migration `20260219022619_remove_subcategory_and_update_settings`.
- Implemented API Key masking (******) in settings service and UI.
- Updated Settings page to show 'Saved' state for API Key/URL buttons.
- Renamed 'Extraction Flow Defaults' to 'Default Models' in Settings.
- Fixed Fitting Room scrolling issue by adding `min-h-0` constraints.
- Updated tests and verifying scripts.
- Added download option to VibeCard dropdown menu when an image is present.
- Added download option to Fitting Room generated look card dropdown menu.
- Implemented client-side download logic using temporary anchor tag.
- Verified with typecheck and tests.
- Update `VibeCard` to support custom `children` content and ensure text readability with a gradient overlay.
- Refactor Outfit list in `Equipments.tsx` to use a grid of `VibeCard` components.
- Implement a 3x3 equipment preview grid inside Outfit cards, with overflow (+N) handling.
- Center the preview grid to 80% height as per design requirements.
- Update `CreateOutfitDialog` to support editing existing outfits (PUT request).
- Change category selection in `CreateOutfitDialog` to single-select.
- Update equipment selection grid in `CreateOutfitDialog` to fixed 3 columns.
- Add "Edit" action to Outfit cards.
- Fitting Room:
- Constrain page height to viewport.
- Use `ScrollArea` for "Generated Looks".
- Ensure character image uses `object-contain` and empty state is centered.
- Extractor:
- Add "Save as Outfit" checkbox and name input to `RefineStage`.
- Implement API call to create outfit upon completion.
- Dockerfile:
- Copy `example-data` directory to final image.
- Fixed Fitting Room page overflow by constraining height and using ScrollArea for the Generated Looks section.
- Added "Save as Outfit" checkbox and input to the Refine stage of the Extractor dialog.
- Installed @radix-ui/react-checkbox and added Shadcn Checkbox component.
- Updated Dockerfile to include example-data directory in the final image.
- Removed hardcoded `BUILTIN_POSES` and `BUILTIN_EXPRESSIONS` constants.
- Updated `PoseService` and `ExpressionService` to only list and delete items from the database.
- Removed the `type` field ('builtin' | 'custom') from `PoseItem` and `ExpressionItem`.
- Updated `GenerationService` to resolve pose and expression assets strictly from the database (`data/files`) instead of falling back to `public/`.
- Updated `Poses.tsx` and `Expressions.tsx` to remove "SYSTEM" vs "CUSTOM" UI distinction and enable deletion for all items.
- Updated `pose.test.ts` and created `expression.test.ts` to verify the new behavior.
- Fixed `generation.test.ts` to mock database calls correctly for pose/expression lookups and avoid polluting other tests.
- Removed hardcoded `BUILTIN_POSES` and `BUILTIN_EXPRESSIONS` constants.
- Updated `PoseService` and `ExpressionService` to only list and delete items from the database.
- Removed the `type` field ('builtin' | 'custom') from `PoseItem` and `ExpressionItem`.
- Updated `GenerationService` to resolve pose and expression assets strictly from the database (`data/files`) instead of falling back to `public/`.
- Updated `Poses.tsx` and `Expressions.tsx` to remove "SYSTEM" vs "CUSTOM" UI distinction and enable deletion for all items.
- Updated `pose.test.ts` and created `expression.test.ts` to verify the new behavior.
- Added `POST /api/equipments` endpoint to create equipment from an existing asset.
- Created `UploadEquipmentDialog` component with drag-and-drop and clipboard paste support.
- Added "Upload" button to the Equipments page header.
- Verified new equipment creation flow via frontend verification script.
- Added `POST /api/equipments` endpoint to create equipment from an existing asset.
- Created `UploadEquipmentDialog` component with drag-and-drop and clipboard paste support.
- Added "Upload" button to the Equipments page header.
- Verified new equipment creation flow via frontend verification script.
- Update prisma/schema.prisma to use @default(ulid()) for all relevant models
- Remove manual ulid() calls from all service files
- Update list APIs to order by id descending
- Update AssetService tests to match new behavior
- Update AGENTS.md with new conventions
- Remove empty migration file (20260217022222_add_ulid_default)
* I added `DialogFooter` to `ExtractorDialog`.
* I moved the action buttons (Start, Cancel, and the finish button) from `AnalyzeStage`, `SelectionStage`, and `RefineStage` to the `ExtractorDialog` footer.
* I lifted the `selectedIndices` state from `SelectionStage` to `ExtractorDialog`.
* I updated `AnalyzeStage` to show the status in the primary action button.
* I enabled cancellation during analysis.
* I ensured that `onSuccess` is called only when the user clicks the finish button in the Refine stage.
- Refactor `ExtractorDialog.tsx` into modular stages: `UploadStage`, `AnalyzeStage`, `SelectionStage`, `RefineStage`.
- Implement new UI flow: Upload -> Analyze -> Select -> Refine.
- Adapt "vibe" reference visuals to application's Light Mode theme (Slate/Cyan/Amber).
- Implement real-time status updates for analysis and refinement steps using backend streams.
- Add drag-and-drop and paste support for image upload.
- Visualize candidate selection grid and refinement progress.
- Implement manual confirmation for analysis start.
- Increase dialog size to `max-w-[98vw]` and `h-[95vh]`.
- Simplify title bar and adjust candidate grid cell size to 140px.
Updates the test expectations in `src/service/extraction.test.ts` to match the actual prompt content used in `src/service/extraction.ts`. The previous test was asserting the presence of specific instructions regarding cropping artifacts that are no longer present in the codebase. The updated test now verifies the presence of the task name and the instruction to return only the image.
- Add semi-transparent dark background to delete button for better visibility on light images.
- Remove equipment labels from generation cards in Fitting Room.
- Implement `ExampleDataService` to export/import Characters, Equipments, Poses, Expressions, and Generations.
- Add `generate-example` script to `package.json` to generate example data from current DB.
- Add startup logic in `src/index.ts` to seed example data if system is uninitialized and no data exists.
- Store system initialization state in `Setting` table.
- Add comprehensive tests for `ExampleDataService` in `src/service/example-data.test.ts` mocking `Bun` file API and `node:fs`.
- Refactor `src/service/example-data.ts` to use `Bun.file` and `Bun.write` for file I/O, ensuring better compatibility with Bun's test runner.
- Implement `ExampleDataService` to export/import Characters, Equipments, Poses, Expressions, and Generations.
- Add `generate-example` script to `package.json` to generate example data from current DB.
- Add startup logic in `src/index.ts` to seed example data if system is uninitialized and no data exists.
- Store system initialization state in `Setting` table.
- Add comprehensive tests for `ExampleDataService` in `src/service/example-data.test.ts` mocking filesystem and database operations.
- Refactor `src/service/example-data.ts` to use default `node:fs` import for better test compatibility.
- Implement `ExampleDataService` to export/import Characters, Equipments, Poses, Expressions, and Generations.
- Add `generate-example` script to `package.json` to generate example data from current DB.
- Add startup logic in `src/index.ts` to seed example data if system is uninitialized and no data exists.
- Store system initialization state in `Setting` table.
- Add comprehensive tests for `ExampleDataService` in `src/service/example-data.test.ts` mocking filesystem and database operations.
- Implement `ExampleDataService` to export/import Characters, Equipments, Poses, Expressions, and Generations.
- Add `generate-example` script to `package.json` to generate example data from current DB.
- Add startup logic in `src/index.ts` to seed example data if system is uninitialized and no data exists.
- Store system initialization state in `Setting` table.
- Add comprehensive tests for `ExampleDataService` in `src/service/example-data.test.ts` mocking filesystem and database operations.
- Add `DELETE /api/equipments/:id` endpoint.
- Add `deleteEquipment` method to `EquipmentService` which also cleans up associated assets and generation references.
- Implement delete action in `Equipments` page UI.
- Pass `actions` prop to `VibeCard` to enable context menu.
Split the equipment extraction process into two phases:
1. Analyze & Split: Generates texture sheet and crops assets.
2. Refine & Save: Allows user to select which assets to keep before refining and saving.
- Refactored `src/api/extract.ts` to expose `/analyze` and `/refine` endpoints.
- Updated `src/ui/components/ExtractorDialog.tsx` to handle the multi-step flow and selection UI.
- Added `CandidateAsset` type and updated `ExtractionStatus` in `src/ui/types.ts`.
- Added `deleteFile` to `FileService` and `deleteAsset` to `AssetService` to support file deletion.
- Implemented cascading deletion in `CharacterService` (delete looks -> delete character image -> delete character).
- Updated `GenerationService`, `PoseService`, and `ExpressionService` to delete associated image assets upon deletion.
- Added `DELETE /api/generations/:id` endpoint.
- Created `DropdownMenu` and `DeleteConfirmDialog` UI components.
- Updated `VibeCard` to include an internal `DropdownMenu` driven by a new `actions` prop.
- Updated `Characters`, `Poses`, and `Expressions` pages to use the new `VibeCard` `actions` prop for deletion.
- Updated `FittingRoom` page to use the `DropdownMenu` and `DeleteConfirmDialog` for deleting looks.
- Updated `CreateLookDialog` to enforce single selection for equipment categories.
- Added necessary tests adjustments.