ui: match Agents entry artwork to module cards

This commit is contained in:
2026-09-14 14:05:52 +08:00
parent da6684b03e
commit 10df9fd740
5 changed files with 79 additions and 6 deletions

View File

@@ -0,0 +1,67 @@
# Task: Replace Agents entry artwork
## Identity
- Task ID: 20260914-agents-entry-art-0242f8f3
- Mode: Feature
- Branch: codex/20260914-agents-entry-art-0242f8f3-agents-entry-art
- Worktree: D:\Datas\OthersProjects\.codex-worktrees\makelore\20260914-agents-entry-art-0242f8f3
- Base commit: da6684b03e8ef7be17cb35b8b42130f11b3bc797
- Owner: codex
- Status: Ready for Integration
## Scope
- Replace the Agents module chooser placeholder with a generated cinematic illustration in `src/assets/module-agents.webp`.
- Reuse the existing module image container, center crop, accessibility text, disabled grayscale and navigation. Require artwork for all four module entries and remove the now-unused placeholder branch.
- Update existing module navigation unit/Electron coverage and this task record only.
## Intent And Constraints
- Concurrent Task Gate and Planning Gate passed. Official start exited 0 and status matched the task ID, feature mode, branch, absolute worktree and base above. All subsequent operations use this isolated worktree; primary `main` has other ownership and three pre-existing untracked task records.
- Loaded the planning entry, own task, memory index, integrated current state, positioning, decision index, architecture, relevant domain/success criteria, accepted personal-cloud-Agent ADR, README and peer scope/intent/promotion sections. Registry holds 28 other planning tasks and 162 ready tasks; historical placeholder scopes remain unknown coordination state. The recent WeChat diagnosis is read-only, and prior Agents entry/platform work is integrated. No concrete semantic dependency on this artwork was identified.
- Older three-module prose and positioning placeholders are stale; README, accepted cloud Agent decision and current source confirm four entries. No architecture, backend, route, configuration or product-direction change is required.
- User requested matching the three existing image entry styles. Built-in imagegen produced a full-bleed dark blue/violet holographic digital companion. Preserve the source PNG outside the repository and ship only the 960x540 WebP, matching the other entry asset dimensions. No subagents were used.
- Plan: generate and inspect artwork; wire the existing image rendering; verify image decoding/layout, module navigation, type checking and production asset bundling; finish task documentation.
## Outcome
- Generated and connected the blue/violet holographic Agent artwork. All four entries use the same bundled-image rendering; obsolete violet placeholder markup is removed. Existing card spacing, image crop, labels, policy state and routes are preserved.
- Visually inspected the real 1280x800 Electron chooser screenshot: the central figure remains recognizable inside the same 164x132 image region as its neighbors. The existing E2E also verifies the layout after resizing to 1100x700.
- Result is in this isolated feature branch. The occupied primary main checkout and installed application were not updated. No push, package, deployment or subagents.
## Verification
- Frozen install succeeded using the exact pinned pnpm 10.33.4. Generated WebP is 960x540, 90,688 bytes.
- `pnpm run typecheck`: passed.
- `pnpm exec vitest run tests/unit/module-navigation.test.tsx tests/unit/module-access.test.ts tests/unit/cloud-agents-page.test.tsx --maxWorkers=2`: 25 tests across 3 files passed; covers artwork rendering, module access, navigation and Agents entry behavior.
- Scoped ESLint on the changed page and unit/E2E files: passed.
- `pnpm run build:vite`: passed for Renderer/Main/Preload/utility; production bundle contains the local WebP. Existing Browserslist and chunk warnings remain.
- `pnpm exec playwright test tests/e2e/main-navigation.spec.ts --grep 'keeps the four module entries' --workers=1`: 1 passed. All four images decoded; proportional layout and hover/focus remain stable across window resizing.
- Visual evidence is the ignored test output `test-results/main-navigation-Makelore-m-77439-k-while-resizing-the-window/module-entry-artwork.png`; no reports/build/cache files belong to the source handoff.
- Task Documentation Gate: inspected the complete source diff and new asset since the recorded base; `git diff --check` and task-aware documentation drift check passed. No canonical-memory promotion is required; README's existing unified horizontal-card description remains accurate.
## Follow-ups
- Integrate this feature branch when the primary worktree ownership is available. An installed client needs a later build/install to display the new artwork.
## Promotion Candidates
- None. This is a presentation-only replacement within the existing module chooser design.
## Image Generation Prompt
- Tool: built-in `image_gen` (no fallback CLI).
- Final asset: `src/assets/module-agents.webp`.
- Original: `C:/Users/7brot/.codex/generated_images/01a09e7c-53f0-79d1-afe0-fb9435d77854/exec-6bd2ccdf-d601-44d4-a80f-6fb1444efbde.png`.
```text
Use case: stylized-concept.
Asset type: a finished landscape raster illustration for the Makelore Agents AI assistant module entry thumbnail, matching adjacent cinematic sci-fi game art and a photoreal dark robotics workshop. Generate only the image asset, no UI mockup.
Primary request: a visually striking intelligent digital companion, an elegant translucent holographic humanlike head and shoulders made of luminous violet and cyan light, facing three-quarter toward the viewer, focused and approachable, actively orchestrating a few floating abstract task panels and connected glowing knowledge nodes. It must read immediately as a software AI agent.
Scene/backdrop: deep navy futuristic digital workspace, restrained atmospheric depth, a few flowing luminous connections and softly blurred screens; full bleed richly rendered scene.
Style/medium: premium cinematic 3D concept art with realistic light, fine materials, detailed but strong readable silhouette, matching sophisticated sci-fi game key art; no flat vector symbol.
Composition/framing: landscape 16:9, 1536x864 output if possible. Main head and upper torso large, occupying the central 55% of the canvas; eyes/head entirely inside central 55% for a center crop to a 164x132 thumbnail. Key accents remain near the center. Leave breathing room around the silhouette, clear foreground/background separation.
Lighting/palette: saturated electric cyan and violet highlights, dark indigo and midnight blue environment, controlled bright rim light, subtle warm highlights, balanced exposure so the face reads at small size. The character is luminous rather than metallic hardware.
Constraints: no text, letters, numerals, brand, logo, watermark, border, rounded corners, white margins, sparkles icon, cartoon mascot, weapons or threatening expression. A single coherent illustration, no panels or collage.
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import moduleAgentsImage from '@/assets/module-agents.webp';
import moduleCanvasImage from '@/assets/module-canvas-neon.webp';
import moduleGameImage from '@/assets/module-game.webp';
import moduleRobotImage from '@/assets/module-robot.webp';
@@ -12,8 +13,8 @@ import { cn } from '@/lib/utils';
import { useAuthStore } from '@/stores/auth';
import { getUserProfileDisplayName } from '@/stores/user-profile';
const moduleSelectionContent: Record<AiModuleId, { label: string; image?: string; imageAlt: string }> = {
cloud_agents: { label: 'Agents 智能体', imageAlt: '个人云智能体' },
const moduleSelectionContent: Record<AiModuleId, { label: string; image: string; imageAlt: string }> = {
cloud_agents: { label: 'Agents 智能体', image: moduleAgentsImage, imageAlt: '个人云智能体' },
programming: { label: 'Code 编程', image: moduleGameImage, imageAlt: '游戏创作工作台' },
painting: { label: 'Canvas 设计', image: moduleCanvasImage, imageAlt: '数位板设计创作' },
robot: { label: 'Robot 机器', image: moduleRobotImage, imageAlt: '青少年管理机器人硬件与设备绑定' },
@@ -90,14 +91,12 @@ export function ModuleSelection({ authRequired = true }: { authRequired?: boolea
<span className="module-option-card-frame" aria-hidden="true" />
<div className="module-option-card-surface relative flex h-full w-full rounded-lg bg-background">
<div className="module-option-card-image relative shrink-0">
{content.image ? <img
<img
src={content.image}
alt={content.imageAlt}
className={cn('module-option-card-image-media h-full w-full object-cover', !enabled && 'grayscale')}
draggable="false"
/> : <div className="flex h-full w-full items-center justify-center bg-violet-50 text-violet-600">
<module.Icon className="h-12 w-12" strokeWidth={1.25} />
</div>}
/>
</div>
<div className="module-option-card-content relative min-h-0 flex-1">
<p className="module-option-card-title font-medium tracking-[-0.02em]">{content.label}</p>

View File

@@ -89,6 +89,11 @@ test.describe('Makelore module navigation without setup flow', () => {
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
const moduleCards = page.locator('[data-testid^="ai-module-option-"]');
await expect(moduleCards.locator('img')).toHaveCount(4);
await expect.poll(async () => await moduleCards.locator('img').evaluateAll((images) =>
images.every((image) => image.complete && image.naturalWidth > 0),
)).toBe(true);
await page.screenshot({ path: test.info().outputPath('module-entry-artwork.png') });
const readCardMetrics = async () => await moduleCards.evaluateAll((elements) => elements.map((element) => {
const bounds = element.getBoundingClientRect();
const image = element.querySelector('.module-option-card-image')?.getBoundingClientRect();

View File

@@ -90,6 +90,8 @@ describe('AI module navigation', () => {
expect(robotOption).toHaveTextContent('Robot 机器');
expect(robotOption).toHaveTextContent('制作你的第一个机器人小伙伴');
expect(screen.getByAltText('青少年管理机器人硬件与设备绑定')).toBeInTheDocument();
expect(screen.getByAltText('个人云智能体')).toHaveAttribute('src', expect.stringContaining('module-agents.webp'));
expect(screen.getByAltText('个人云智能体')).toHaveClass('module-option-card-image-media', 'object-cover');
fireEvent.click(screen.getByTestId('ai-module-option-painting'));
expect(await screen.findByTestId('location-path')).toHaveTextContent('/image-canvas');