feat: refine wooden fish runtime generation

This commit is contained in:
2026-05-22 03:49:35 +08:00
parent d81cc49549
commit 5f1128540e
30 changed files with 804 additions and 126 deletions

View File

@@ -54,6 +54,10 @@ export function WoodenFishResultView({
: draft.hitObjectAsset;
const hitObjectSrc =
hitObjectAsset?.imageSrc?.trim() || WOODEN_FISH_DEFAULT_HIT_OBJECT_SRC;
const backgroundAsset = isWorkProfile
? profile.backgroundAsset ?? draft.backgroundAsset
: draft.backgroundAsset;
const backgroundSrc = backgroundAsset?.imageSrc?.trim() || '';
const hitSoundAsset = isWorkProfile
? profile.hitSoundAsset
: draft.hitSoundAsset;
@@ -118,13 +122,24 @@ export function WoodenFishResultView({
{description}
</div>
) : null}
<div className="mt-4 grid min-h-0 flex-1 place-items-center rounded-[1.1rem] border border-[var(--platform-subpanel-border)] bg-white/78 p-5">
<ResolvedAssetImage
src={hitObjectSrc}
fallbackSrc={WOODEN_FISH_DEFAULT_HIT_OBJECT_SRC}
alt="敲击物图案"
className="max-h-[min(46vh,22rem)] w-full object-contain drop-shadow-[0_18px_28px_rgba(15,23,42,0.18)]"
/>
<div className="mt-4 grid min-h-0 flex-1 place-items-center">
<div className="relative grid aspect-[9/16] h-full max-h-[min(58vh,34rem)] w-full max-w-[20rem] place-items-center overflow-hidden rounded-[1.1rem] border border-[var(--platform-subpanel-border)] bg-white/78">
{backgroundSrc ? (
<ResolvedAssetImage
src={backgroundSrc}
alt=""
aria-hidden="true"
className="absolute inset-0 h-full w-full object-cover"
/>
) : null}
<div className="absolute inset-0 bg-white/10" />
<ResolvedAssetImage
src={hitObjectSrc}
fallbackSrc={WOODEN_FISH_DEFAULT_HIT_OBJECT_SRC}
alt="敲击物图案"
className="relative z-10 w-[68%] object-contain drop-shadow-[0_18px_28px_rgba(15,23,42,0.18)]"
/>
</div>
</div>
</section>

View File

@@ -95,6 +95,10 @@ export function WoodenFishRuntimeShell({
profile?.hitObjectAsset?.imageSrc?.trim() ||
profile?.draft.hitObjectAsset?.imageSrc?.trim() ||
WOODEN_FISH_DEFAULT_HIT_OBJECT_SRC;
const backgroundSrc =
profile?.backgroundAsset?.imageSrc?.trim() ||
profile?.draft.backgroundAsset?.imageSrc?.trim() ||
'';
const hitSoundSrc =
profile?.hitSoundAsset?.audioSrc ?? profile?.draft.hitSoundAsset?.audioSrc;
const { resolvedUrl: resolvedAudioUrl } = useResolvedAssetReadUrl(hitSoundSrc);
@@ -217,6 +221,16 @@ export function WoodenFishRuntimeShell({
onPointerDown={registerTap}
>
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_18%,rgba(255,255,255,0.92),transparent_26%),linear-gradient(180deg,#fff8e8_0%,#eef7ed_55%,#e5f2f7_100%)]" />
{backgroundSrc ? (
<ResolvedAssetImage
src={backgroundSrc}
alt=""
aria-hidden="true"
draggable={false}
className="pointer-events-none absolute inset-0 h-full w-full object-cover"
/>
) : null}
<div className="pointer-events-none absolute inset-0 bg-white/10" />
<header
data-wooden-fish-functional="true"

View File

@@ -356,7 +356,7 @@ describe('miniGameDraftGenerationProgress', () => {
]);
});
test('wooden fish draft generation exposes hit object and sound pipeline', () => {
test('wooden fish draft generation exposes hit object, background and sound pipeline', () => {
const state = createMiniGameDraftGenerationState('wooden-fish');
const progress = buildMiniGameDraftGenerationProgress(
@@ -367,6 +367,7 @@ describe('miniGameDraftGenerationProgress', () => {
expect(progress?.steps.map((step) => step.id)).toEqual([
'wooden-fish-draft',
'wooden-fish-hit-object',
'wooden-fish-background',
'wooden-fish-hit-sound',
'wooden-fish-write-draft',
]);

View File

@@ -66,6 +66,7 @@ export type MiniGameDraftGenerationPhase =
| 'jump-hop-write-draft'
| 'wooden-fish-draft'
| 'wooden-fish-hit-object'
| 'wooden-fish-background'
| 'wooden-fish-hit-sound'
| 'wooden-fish-write-draft'
| 'puzzle-images'
@@ -327,25 +328,31 @@ const WOODEN_FISH_STEPS = [
id: 'wooden-fish-draft',
label: '整理玩法草稿',
detail: '保存作品信息、敲击物、音效和飘字配置。',
weight: 10,
weight: 8,
},
{
id: 'wooden-fish-hit-object',
label: '生成敲击物图案',
detail: '使用 image2 生成最终运行态敲击物图案。',
weight: 48,
weight: 34,
},
{
id: 'wooden-fish-background',
label: '生成背景环境图',
detail: '使用 image2 生成敲击背景环境图。',
weight: 34,
},
{
id: 'wooden-fish-hit-sound',
label: '准备敲击音效',
detail: '生成或写回短促敲击音效资产。',
weight: 30,
weight: 16,
},
{
id: 'wooden-fish-write-draft',
label: '写入正式草稿',
detail: '保存图案、音效、飘字和封面摘要。',
weight: 12,
detail: '保存图案、背景、音效、飘字和封面摘要。',
weight: 8,
},
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
@@ -530,9 +537,12 @@ function resolveWoodenFishPhaseByElapsedMs(
if (elapsedMs >= 270_000) {
return 'wooden-fish-write-draft';
}
if (elapsedMs >= 185_000) {
if (elapsedMs >= 240_000) {
return 'wooden-fish-hit-sound';
}
if (elapsedMs >= 120_000) {
return 'wooden-fish-background';
}
if (elapsedMs >= 12_000) {
return 'wooden-fish-hit-object';
}

View File

@@ -106,6 +106,8 @@ function normalizeWoodenFishWorkProfile(
summary,
draft: flattened.draft,
hitObjectAsset: flattened.hitObjectAsset,
backgroundAsset:
flattened.backgroundAsset ?? flattened.draft?.backgroundAsset ?? null,
hitSoundAsset: flattened.hitSoundAsset,
floatingWords: flattened.floatingWords,
};