diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 9da4bea1f..0b258a036 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -16,6 +16,14 @@ --- +## 2026-06-23 陶泥儿产品 IP 形象统一为陶罐探出橙色耳朵形象 + +- 背景:平台左上角“陶泥儿”品牌旁产品形象曾分散使用创作主页旧小陶偶、运行态 logo 或局部欢迎图,后续提到产品 IP / 产品形象容易产生歧义。 +- 决策:产品 IP / 产品形象统一定义为 `public/branding/taonier-product-ip.png`,即陶罐中探出的橙色耳朵形象。公共品牌组件 `RpgEntryBrandLogo` 默认展示该图;后续左上角品牌区和产品形象说明默认引用该资产,专题玩法若有独立运行态素材需在对应文档单独说明。 +- 影响范围:平台左上角品牌区、绑定手机号页品牌块、创作主页工作台 chrome、公共品牌资产常量和产品基线文档。 +- 验证方式:运行品牌标识、绑定手机号页和平台首页相关前端测试,确认品牌图 `src` 为 `/branding/taonier-product-ip.png`;执行 `npm run check:encoding` 和 `git diff --check`。 +- 关联文档:`docs/【项目基线】当前产品与工程约束-2026-05-15.md`、`docs/【玩法创作】创作主页与项目入口改版计划-2026-06-18.md`。 + ## 2026-06-22 创作主页精选只展示项目内画布生成资源 - 背景:`/creation` 的 `陶泥儿精选` 曾从账号级素材库读取,并在素材为空时用公开作品图片补充,导致新创作页出现不属于任何当前图片画布项目的素材。 diff --git a/docs/project-memory/shared-memory/project-overview.md b/docs/project-memory/shared-memory/project-overview.md index 81920e365..674dac26e 100644 --- a/docs/project-memory/shared-memory/project-overview.md +++ b/docs/project-memory/shared-memory/project-overview.md @@ -1,11 +1,13 @@ # Genarrative 项目共享概览 -更新时间:`2026-06-12` +更新时间:`2026-06-23` ## 一句话定位 Genarrative / 陶泥儿是一个 AI 原生互动内容与小游戏平台,把 AI 创作、作品草稿、公开分发、运行态、用户账号、钱包任务、后台管理和小程序外壳收在同一套工程中。 +产品 IP / 产品形象统一为 `public/branding/taonier-product-ip.png`:陶罐中探出的橙色耳朵形象。后续提到“产品 IP”“产品形象”或左上角品牌旁形象时默认指该资产。 + ## 当前主要能力 - RPG / 自定义世界创作与运行时。 diff --git a/docs/【玩法创作】创作主页与项目入口改版计划-2026-06-18.md b/docs/【玩法创作】创作主页与项目入口改版计划-2026-06-18.md index d8b7d5064..fa88b6f8c 100644 --- a/docs/【玩法创作】创作主页与项目入口改版计划-2026-06-18.md +++ b/docs/【玩法创作】创作主页与项目入口改版计划-2026-06-18.md @@ -149,7 +149,7 @@ Tab: - 桌面端复用现有平台壳层,保留上方栏和左侧导航栏。 - 主页整体采用浅色布局,避免外站品牌文案。 - 视觉排版参考陶土质感创作工具工作台:首屏标题居中、主按钮与社区按钮使用大号圆角胶囊尺寸,九大创作工具以 3 列大卡片展示,卡片左侧保留大号陶土感图标区域,右侧展示原有标题与描述;桌面平台一级页的顶部栏和左侧导航统一压平成单层工作台 chrome,避免外框套内框;桌面端页面结构必须先分为“左侧完整栏 / 右侧内容区”,左侧完整栏同时包含顶部品牌 Logo 和下方导航页签,右侧内容区再拆为顶部搜索、钱包、账号栏与下方主屏,不能用顶部栏的第一列假装左侧品牌区;左侧栏采用紧凑但保留图标和文字的导航胶囊,顶部搜索栏、泥点入口和账号入口都保持精简宽度,提升推荐、发现、我的、创作主页和项目页的工具感与精致度;只调整样式与布局,不改文案、搜索、登录、导航、项目创建、社区弹层、最近项目、精选素材 Tab 或数据读取逻辑。 -- 背景、顶部品牌小陶偶、左侧导航、按钮和九大创作工具图标使用 `gpt-image-2` / image2 生成资源,统一保存在 `public/creation-home/`;资源只作为装饰图标或背景纹理接入,不包含图内文字,不替换或隐藏现有 UI 文案和交互。 +- 背景、左侧导航、按钮和九大创作工具图标使用 `gpt-image-2` / image2 生成资源,统一保存在 `public/creation-home/`;资源只作为装饰图标或背景纹理接入,不包含图内文字,不替换或隐藏现有 UI 文案和交互。顶部品牌旁产品形象统一使用 `public/branding/taonier-product-ip.png`,不再使用创作主页旧小陶偶作为左上角品牌形象。 - 社群入口复用现有玩家社区弹层,点击后必须停留在 `/creation`。 - 不在 UI 中放规则说明、实现说明或“暂不实装”提示。 - 未登录时不渲染最近项目区;需要创建项目时走登录弹窗和登录后重试。 diff --git a/docs/【项目基线】当前产品与工程约束-2026-05-15.md b/docs/【项目基线】当前产品与工程约束-2026-05-15.md index cfdb5b030..13628c52b 100644 --- a/docs/【项目基线】当前产品与工程约束-2026-05-15.md +++ b/docs/【项目基线】当前产品与工程约束-2026-05-15.md @@ -20,6 +20,7 @@ Genarrative / 陶泥儿是一个 AI 原生互动内容与小游戏平台。当 - 消费单位:泥点。 - 公开账号标识:陶泥号。 - 创作侧称谓:陶泥儿主。 +- 产品 IP / 产品形象:统一指 `public/branding/taonier-product-ip.png`,即陶罐中探出的橙色耳朵形象;后续左上角品牌区、产品形象引用和品牌视觉说明默认使用该形象,除非专题玩法明确要求独立运行态素材。 不要把旧“百梦”等历史命名重新写入新 UI 或新文档。 diff --git a/public/branding/taonier-product-ip.png b/public/branding/taonier-product-ip.png new file mode 100644 index 000000000..566bd25f1 Binary files /dev/null and b/public/branding/taonier-product-ip.png differ diff --git a/public/creation-home/asset-manifest.json b/public/creation-home/asset-manifest.json index 566b5fb3d..605266916 100644 --- a/public/creation-home/asset-manifest.json +++ b/public/creation-home/asset-manifest.json @@ -15,7 +15,7 @@ }, { "file": "/creation-home/brand-mascot.png", - "subject": "陶泥儿品牌小陶偶头像", + "subject": "创作主页旧装饰头像,不作为产品 IP 形象", "bytes": 265352 }, { @@ -114,4 +114,4 @@ "bytes": 280555 } ] -} \ No newline at end of file +} diff --git a/src/components/auth/BindPhoneScreen.test.tsx b/src/components/auth/BindPhoneScreen.test.tsx index 8ba72b65d..773b0cd92 100644 --- a/src/components/auth/BindPhoneScreen.test.tsx +++ b/src/components/auth/BindPhoneScreen.test.tsx @@ -50,6 +50,11 @@ test('绑定手机号表单复用平台输入和字段标题', async () => { expect(screen.getByText('当前登录身份:微信旅人').className).toContain( 'platform-subpanel', ); + expect( + document + .querySelector('.selection-hero-brand__image') + ?.getAttribute('src'), + ).toBe('/branding/taonier-product-ip.png'); await user.type(phoneInput, '13800000000'); await user.type(codeInput, '123456'); diff --git a/src/components/auth/BindPhoneScreen.tsx b/src/components/auth/BindPhoneScreen.tsx index 9d793fc7b..b5a0e7449 100644 --- a/src/components/auth/BindPhoneScreen.tsx +++ b/src/components/auth/BindPhoneScreen.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'; import type { PlatformTheme } from '../../../packages/shared/src/contracts/runtime'; import type { AuthCaptchaChallenge, AuthUser } from '../../services/authService'; +import { BRAND_ASSETS } from '../../uiAssets'; import { PlatformActionButton } from '../common/PlatformActionButton'; import { PlatformFieldLabel } from '../common/PlatformFieldLabel'; import { PlatformStatusMessage } from '../common/PlatformStatusMessage'; @@ -67,7 +68,16 @@ export function BindPhoneScreen({
-
陶泥儿
+
+ +
陶泥儿
+
视觉叙事 RPG

diff --git a/src/components/rpg-entry/RpgEntryBrandLogo.test.tsx b/src/components/rpg-entry/RpgEntryBrandLogo.test.tsx new file mode 100644 index 000000000..5b946656a --- /dev/null +++ b/src/components/rpg-entry/RpgEntryBrandLogo.test.tsx @@ -0,0 +1,25 @@ +/* @vitest-environment jsdom */ + +import { render, screen } from '@testing-library/react'; +import { expect, test } from 'vitest'; + +import { RpgEntryBrandLogo } from './RpgEntryBrandLogo'; + +test('陶泥儿品牌标识展示统一产品形象', () => { + const { container } = render(); + + expect( + screen.getByRole('img', { name: '陶泥儿 GENARRATIVE' }), + ).toBeTruthy(); + expect( + container + .querySelector('.platform-brand-logo__image') + ?.getAttribute('src'), + ).toBe('/branding/taonier-product-ip.png'); +}); + +test('装饰模式不暴露额外品牌朗读入口', () => { + render(); + + expect(screen.queryByRole('img')).toBeNull(); +}); diff --git a/src/components/rpg-entry/RpgEntryBrandLogo.tsx b/src/components/rpg-entry/RpgEntryBrandLogo.tsx index 5265ae96d..c98d88c96 100644 --- a/src/components/rpg-entry/RpgEntryBrandLogo.tsx +++ b/src/components/rpg-entry/RpgEntryBrandLogo.tsx @@ -1,3 +1,5 @@ +import { BRAND_ASSETS } from '../../uiAssets'; + export interface RpgEntryBrandLogoProps { className?: string; decorative?: boolean; @@ -18,10 +20,19 @@ export function RpgEntryBrandLogo({ aria-hidden={decorative || undefined} aria-label={decorative ? undefined : '陶泥儿 GENARRATIVE'} > - - 陶泥 + + + + 陶泥 + + GENARRATIVE - GENARRATIVE ); } diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index e3401d22c..6c5734399 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -3834,6 +3834,11 @@ test('desktop recommend page reuses compact workbench chrome', () => { expect(leftbar).toBeTruthy(); expect(topbar).toBeTruthy(); expect(leftbar?.querySelector('.creation-home-brand-lockup')).toBeTruthy(); + expect( + leftbar + ?.querySelector('.platform-brand-logo__image') + ?.getAttribute('src'), + ).toBe('/branding/taonier-product-ip.png'); expect(topbar?.querySelector('.creation-home-brand-lockup')).toBeNull(); expect( within(leftbar as HTMLElement).getByRole('button', { name: '推荐' }), diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index 8d587a736..4b42010e3 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -331,7 +331,6 @@ const CREATION_HOME_NAV_ICON_SRC: Record = { profile: '/creation-home/nav-profile.png', }; const CREATION_HOME_TOPBAR_ASSETS = { - brandMascot: '/creation-home/brand-mascot.png', search: '/creation-home/topbar-search.png', wallet: '/creation-home/topbar-wallet.png', } as const; @@ -4926,13 +4925,6 @@ export function RpgEntryHomeView({ ) : null; const desktopBrandLockup: ReactNode = ( - ); diff --git a/src/index.css b/src/index.css index 41a737a7a..aa9ff54b8 100644 --- a/src/index.css +++ b/src/index.css @@ -888,6 +888,20 @@ html[data-mobile-keyboard-open='true'] #root { text-align: left; } +.selection-hero-brand__lockup { + display: inline-flex; + align-items: center; + gap: 0.82rem; +} + +.selection-hero-brand__image { + width: clamp(3rem, 10vw, 4.4rem); + height: clamp(3rem, 10vw, 4.4rem); + flex: 0 0 auto; + object-fit: contain; + filter: drop-shadow(0 0.55rem 0.58rem rgba(0, 0, 0, 0.28)); +} + .selection-hero-brand__title { font-family: 'Noto Serif SC', 'Georgia', serif !important; font-size: clamp(3rem, 10vw, 4.6rem); @@ -1485,10 +1499,25 @@ html[data-mobile-keyboard-open='true'] #root { .platform-brand-logo { display: inline-flex; flex: none; + align-items: center; + gap: 0.5rem; + line-height: 1; +} + +.platform-brand-logo__image { + width: clamp(2.1rem, 6vw, 2.95rem); + height: clamp(2.1rem, 6vw, 2.95rem); + flex: 0 0 auto; + object-fit: contain; + filter: drop-shadow(0 0.24rem 0.28rem rgba(112, 62, 32, 0.18)); +} + +.platform-brand-logo__copy { + display: inline-flex; + min-width: 0; flex-direction: column; align-items: flex-start; gap: 0.18rem; - line-height: 1; } .platform-brand-logo__title, @@ -11700,7 +11729,6 @@ button.image-canvas-editor__reference-chip:disabled { gap: 0.7rem; } -.creation-home-brand-lockup__art, .creation-home-nav-art, .creation-home-topbar-art { display: none; @@ -11774,21 +11802,15 @@ button.image-canvas-editor__reference-chip:disabled { .platform-desktop-shell--workbench .creation-home-brand-lockup { align-self: flex-start; - gap: 0.42rem; min-height: 3.28rem; padding-left: 0.28rem; } -.platform-desktop-shell--workbench .creation-home-brand-lockup__art { - display: block; - width: 2.58rem; - height: 2.58rem; +.platform-desktop-shell--workbench .platform-brand-logo__image { + width: 2.82rem; + height: 2.82rem; flex: 0 0 auto; - border-radius: 999px; - object-fit: cover; - object-position: center; filter: drop-shadow(0 0.36rem 0.34rem rgba(112, 62, 32, 0.18)); - mix-blend-mode: multiply; } .platform-desktop-shell--workbench .platform-brand-logo__title { @@ -14204,6 +14226,15 @@ button { gap: 0.6rem; } + .selection-hero-brand__lockup { + gap: 0.58rem; + } + + .selection-hero-brand__image { + width: 2.85rem; + height: 2.85rem; + } + .selection-hero-brand__title { letter-spacing: 0.16em; } diff --git a/src/uiAssets.ts b/src/uiAssets.ts index bf74da99c..eca2ada6d 100644 --- a/src/uiAssets.ts +++ b/src/uiAssets.ts @@ -53,6 +53,7 @@ export const CUSTOM_WORLD_THEME_ICONS = { export const BRAND_ASSETS = { kuranGamesLogo: '/branding/kuran-games-logo.svg', + taonierProductIp: '/branding/taonier-product-ip.png', } as const; export const UI_CHROME = {