Files
Kokorone/apps/api/src/tachie/tachie.controller.ts
T
JefferyandClaude Sonnet 5 0f3d16059c feat: 完成 O 群組 — 立繪子系統
後端(apps/api/src/tachie/):立繪 manifest(身體姿勢/服裝/表情眉眼口/
效果層/微動態的資產目錄,服裝目錄有 M-1 登錄時優先採用);表情解析依
情緒引擎六狀態對照眉/眼/口/效果/姿勢,依 RelationshipStage 分層解鎖
(陌生~認識/朋友/摯友/羈絆,哭臉限羈絆才會出現),依角色外顯度縮放
差分幅度(magnitude = expressiveness × 情緒強度);emotionTag(實際
套用)與 rawEmotionTag(情緒引擎真實判定)分離,讓文字生成與表情解析
維持兩條獨立資料流,「文字與立繪故意不一致」是這個設計的自然結果,
不需要額外邏輯;視線方向依思考/迴避/警戒切換。

前端(apps/web/components/TachieStage.tsx):以 PixiJS 實作分層合成
與眨眼/呼吸微動態,預留 TachieRenderer 介面供未來 Live2D Cubism SDK
實作(未引入任何 Live2D 相依或授權,純架構佔位);接上 ChatView 取代
H 群組的佔位立繪,聊天回應後先查詢表情、延遲約 220ms 才顯示文字,
在非串流架構下盡力模擬「表情先變化、文字後出現」。

以 scratchpad 暫裝 playwright-core 實測瀏覽器行為(本環境無
chromium-cli),確認情緒變化即時反映在立繪、微動態持續運作。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:46:50 +08:00

32 lines
1.0 KiB
TypeScript

import { Controller, Get, Param, Query } from "@nestjs/common";
import { ManifestService } from "./manifest.service.js";
import { ExpressionResolverService } from "./expression-resolver.service.js";
@Controller("tachie")
export class TachieController {
constructor(
private readonly manifest: ManifestService,
private readonly expression: ExpressionResolverService,
) {}
@Get(":characterId/manifest")
async getManifest(@Param("characterId") characterId: string) {
return this.manifest.getManifest(characterId);
}
@Get(":characterId/:userId/expression")
async getExpression(
@Param("characterId") characterId: string,
@Param("userId") userId: string,
@Query("now") now?: string,
@Query("isThinking") isThinking?: string,
@Query("isDeflecting") isDeflecting?: string,
) {
return this.expression.resolveExpression(characterId, userId, {
now: now ? new Date(now) : undefined,
isThinking: isThinking === "true",
isDeflecting: isDeflecting === "true",
});
}
}