bmad-visual 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/bmad-visual.js +255 -0
- package/package.json +31 -0
- package/templates/.agent/workflows/analyst.md +20 -0
- package/templates/.agent/workflows/architect.md +20 -0
- package/templates/.agent/workflows/bmad-advanced-elicitation.md +5 -0
- package/templates/.agent/workflows/bmad-brainstorming.md +5 -0
- package/templates/.agent/workflows/bmad-check-implementation-readiness.md +5 -0
- package/templates/.agent/workflows/bmad-checkpoint-preview.md +5 -0
- package/templates/.agent/workflows/bmad-code-review.md +5 -0
- package/templates/.agent/workflows/bmad-correct-course.md +5 -0
- package/templates/.agent/workflows/bmad-create-architecture.md +5 -0
- package/templates/.agent/workflows/bmad-create-epics-and-stories.md +5 -0
- package/templates/.agent/workflows/bmad-create-prd.md +5 -0
- package/templates/.agent/workflows/bmad-create-story.md +5 -0
- package/templates/.agent/workflows/bmad-create-ux-design.md +5 -0
- package/templates/.agent/workflows/bmad-dev-story.md +5 -0
- package/templates/.agent/workflows/bmad-distillator.md +5 -0
- package/templates/.agent/workflows/bmad-document-project.md +5 -0
- package/templates/.agent/workflows/bmad-domain-research.md +5 -0
- package/templates/.agent/workflows/bmad-edit-prd.md +5 -0
- package/templates/.agent/workflows/bmad-editorial-review-prose.md +5 -0
- package/templates/.agent/workflows/bmad-editorial-review-structure.md +5 -0
- package/templates/.agent/workflows/bmad-generate-project-context.md +5 -0
- package/templates/.agent/workflows/bmad-help-full.md +5 -0
- package/templates/.agent/workflows/bmad-help.md +5 -0
- package/templates/.agent/workflows/bmad-index-docs.md +5 -0
- package/templates/.agent/workflows/bmad-market-research.md +5 -0
- package/templates/.agent/workflows/bmad-party-mode.md +5 -0
- package/templates/.agent/workflows/bmad-prfaq.md +5 -0
- package/templates/.agent/workflows/bmad-product-brief.md +5 -0
- package/templates/.agent/workflows/bmad-qa-generate-e2e-tests.md +5 -0
- package/templates/.agent/workflows/bmad-quick-dev.md +5 -0
- package/templates/.agent/workflows/bmad-retrospective.md +5 -0
- package/templates/.agent/workflows/bmad-review-adversarial-general.md +5 -0
- package/templates/.agent/workflows/bmad-review-edge-case-hunter.md +5 -0
- package/templates/.agent/workflows/bmad-shard-doc.md +5 -0
- package/templates/.agent/workflows/bmad-sprint-planning.md +5 -0
- package/templates/.agent/workflows/bmad-sprint-status.md +5 -0
- package/templates/.agent/workflows/bmad-technical-research.md +5 -0
- package/templates/.agent/workflows/bmad-validate-prd.md +5 -0
- package/templates/.agent/workflows/dev.md +20 -0
- package/templates/.agent/workflows/pm.md +20 -0
- package/templates/.agent/workflows/qa.md +20 -0
- package/templates/.agent/workflows/sm.md +20 -0
- package/templates/.agent/workflows/solo-dev.md +20 -0
- package/templates/.agent/workflows/ux.md +20 -0
- package/templates/.claude/settings.local.json +50 -0
- package/templates/.claude/skills/analyst/SKILL.md +77 -0
- package/templates/.claude/skills/architect/SKILL.md +72 -0
- package/templates/.claude/skills/bmad-advanced-elicitation/SKILL.md +24 -0
- package/templates/.claude/skills/bmad-brainstorming/SKILL.md +26 -0
- package/templates/.claude/skills/bmad-check-implementation-readiness/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-checkpoint-preview/SKILL.md +17 -0
- package/templates/.claude/skills/bmad-code-review/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-correct-course/SKILL.md +17 -0
- package/templates/.claude/skills/bmad-create-architecture/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-create-epics-and-stories/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-create-prd/SKILL.md +30 -0
- package/templates/.claude/skills/bmad-create-story/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-create-ux-design/SKILL.md +23 -0
- package/templates/.claude/skills/bmad-dev-story/SKILL.md +27 -0
- package/templates/.claude/skills/bmad-distillator/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-document-project/SKILL.md +27 -0
- package/templates/.claude/skills/bmad-domain-research/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-edit-prd/SKILL.md +18 -0
- package/templates/.claude/skills/bmad-editorial-review-prose/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-editorial-review-structure/SKILL.md +25 -0
- package/templates/.claude/skills/bmad-generate-project-context/SKILL.md +20 -0
- package/templates/.claude/skills/bmad-help/SKILL.md +63 -0
- package/templates/.claude/skills/bmad-help-full/SKILL.md +23 -0
- package/templates/.claude/skills/bmad-index-docs/SKILL.md +16 -0
- package/templates/.claude/skills/bmad-market-research/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-party-mode/SKILL.md +24 -0
- package/templates/.claude/skills/bmad-prfaq/SKILL.md +36 -0
- package/templates/.claude/skills/bmad-product-brief/SKILL.md +36 -0
- package/templates/.claude/skills/bmad-qa-generate-e2e-tests/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-quick-dev/SKILL.md +23 -0
- package/templates/.claude/skills/bmad-retrospective/SKILL.md +17 -0
- package/templates/.claude/skills/bmad-review-adversarial-general/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-review-edge-case-hunter/SKILL.md +22 -0
- package/templates/.claude/skills/bmad-shard-doc/SKILL.md +17 -0
- package/templates/.claude/skills/bmad-sprint-planning/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-sprint-status/SKILL.md +17 -0
- package/templates/.claude/skills/bmad-technical-research/SKILL.md +21 -0
- package/templates/.claude/skills/bmad-validate-prd/SKILL.md +22 -0
- package/templates/.claude/skills/dev/SKILL.md +71 -0
- package/templates/.claude/skills/pm/SKILL.md +76 -0
- package/templates/.claude/skills/qa/SKILL.md +64 -0
- package/templates/.claude/skills/sm/SKILL.md +74 -0
- package/templates/.claude/skills/solo-dev/SKILL.md +64 -0
- package/templates/.claude/skills/ux/SKILL.md +71 -0
- package/templates/CLAUDE.md +60 -0
- package/templates/dashboard/index.html +15 -0
- package/templates/dashboard/package.json +30 -0
- package/templates/dashboard/public/assets/avatars/Female1_1wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female1_2wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female1_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female1_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female2_1wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female2_2wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female2_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female2_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female3_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female3_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female3_wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female4_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female4_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female4_wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female5_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female5_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female5_wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female6_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female6_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Female6_wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male1_1wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male1_2wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male1_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male1_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male2_1wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male2_2wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male2_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male2_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male3_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male3_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male3_wave.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male4_blink.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male4_talk.png +0 -0
- package/templates/dashboard/public/assets/avatars/Male4_wave.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_black_down.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_black_down_coding-1.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_black_down_coding.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_black_up.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_white_down.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_white_down_coding-1.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_white_down_coding.png +0 -0
- package/templates/dashboard/public/assets/desks/desktop_set_white_up.png +0 -0
- package/templates/dashboard/public/assets/furniture/armchair_tan.png +0 -0
- package/templates/dashboard/public/assets/furniture/armchair_tan_down.png +0 -0
- package/templates/dashboard/public/assets/furniture/backpack_blue.png +0 -0
- package/templates/dashboard/public/assets/furniture/backpack_red.png +0 -0
- package/templates/dashboard/public/assets/furniture/blinds.png +0 -0
- package/templates/dashboard/public/assets/furniture/blinds_large_closed_white.png +0 -0
- package/templates/dashboard/public/assets/furniture/bookshelf.png +0 -0
- package/templates/dashboard/public/assets/furniture/bookshelf_purple_tall.png +0 -0
- package/templates/dashboard/public/assets/furniture/bulletin_board.png +0 -0
- package/templates/dashboard/public/assets/furniture/clock.png +0 -0
- package/templates/dashboard/public/assets/furniture/coffee_mug.png +0 -0
- package/templates/dashboard/public/assets/furniture/coffee_mug_blue.png +0 -0
- package/templates/dashboard/public/assets/furniture/coffee_table.png +0 -0
- package/templates/dashboard/public/assets/furniture/coffeepot_right.png +0 -0
- package/templates/dashboard/public/assets/furniture/coffeetable_black_horizontal.png +0 -0
- package/templates/dashboard/public/assets/furniture/couch.png +0 -0
- package/templates/dashboard/public/assets/furniture/couch_tan_down.png +0 -0
- package/templates/dashboard/public/assets/furniture/cushion_blue.png +0 -0
- package/templates/dashboard/public/assets/furniture/cushion_tan.png +0 -0
- package/templates/dashboard/public/assets/furniture/desk_wood.png +0 -0
- package/templates/dashboard/public/assets/furniture/fancy_rug.png +0 -0
- package/templates/dashboard/public/assets/furniture/fancy_rug_wide.png +0 -0
- package/templates/dashboard/public/assets/furniture/flowers1.png +0 -0
- package/templates/dashboard/public/assets/furniture/flowers2.png +0 -0
- package/templates/dashboard/public/assets/furniture/lamp_tan.png +0 -0
- package/templates/dashboard/public/assets/furniture/lantern.png +0 -0
- package/templates/dashboard/public/assets/furniture/monstera.png +0 -0
- package/templates/dashboard/public/assets/furniture/monstera_small.png +0 -0
- package/templates/dashboard/public/assets/furniture/picture_frame.png +0 -0
- package/templates/dashboard/public/assets/furniture/plant1.png +0 -0
- package/templates/dashboard/public/assets/furniture/plant2.png +0 -0
- package/templates/dashboard/public/assets/furniture/plant3.png +0 -0
- package/templates/dashboard/public/assets/furniture/plant_poof.png +0 -0
- package/templates/dashboard/public/assets/furniture/plant_spindly.png +0 -0
- package/templates/dashboard/public/assets/furniture/poster_blue.png +0 -0
- package/templates/dashboard/public/assets/furniture/rug.png +0 -0
- package/templates/dashboard/public/assets/furniture/succulent_blue.png +0 -0
- package/templates/dashboard/public/assets/furniture/succulent_green.png +0 -0
- package/templates/dashboard/public/assets/furniture/treasurechest_closed_gold.png +0 -0
- package/templates/dashboard/public/assets/furniture/water_cooler_better.png +0 -0
- package/templates/dashboard/public/assets/furniture/whiteboard.png +0 -0
- package/templates/dashboard/public/assets/furniture/whiteboard_stand_graph.png +0 -0
- package/templates/dashboard/public/assets/furniture/window_blinds_open.png +0 -0
- package/templates/dashboard/public/assets/logo.png +0 -0
- package/templates/dashboard/src/App.tsx +119 -0
- package/templates/dashboard/src/components/SquadCard.tsx +47 -0
- package/templates/dashboard/src/components/SquadSelector.tsx +61 -0
- package/templates/dashboard/src/components/StatusBadge.tsx +32 -0
- package/templates/dashboard/src/components/StatusBar.tsx +97 -0
- package/templates/dashboard/src/hooks/useSquadSocket.ts +137 -0
- package/templates/dashboard/src/lib/formatTime.ts +16 -0
- package/templates/dashboard/src/lib/normalizeState.ts +25 -0
- package/templates/dashboard/src/main.tsx +14 -0
- package/templates/dashboard/src/office/AgentSprite.ts +249 -0
- package/templates/dashboard/src/office/OfficeScene.ts +577 -0
- package/templates/dashboard/src/office/PhaserGame.tsx +101 -0
- package/templates/dashboard/src/office/RoomBuilder.ts +190 -0
- package/templates/dashboard/src/office/assetKeys.ts +150 -0
- package/templates/dashboard/src/office/palette.ts +32 -0
- package/templates/dashboard/src/plugin/squadWatcher.ts +260 -0
- package/templates/dashboard/src/store/useSquadStore.ts +63 -0
- package/templates/dashboard/src/styles/globals.css +41 -0
- package/templates/dashboard/src/types/state.ts +69 -0
- package/templates/dashboard/src/vite-env.d.ts +1 -0
- package/templates/dashboard/tsconfig.json +24 -0
- package/templates/dashboard/tsconfig.tsbuildinfo +1 -0
- package/templates/dashboard/vite.config.ts +13 -0
- package/templates/squads/.gitkeep +0 -0
- package/templates/squads/bmad/agents/analyst.agent.md +87 -0
- package/templates/squads/bmad/agents/architect.agent.md +82 -0
- package/templates/squads/bmad/agents/developer.agent.md +91 -0
- package/templates/squads/bmad/agents/pm.agent.md +86 -0
- package/templates/squads/bmad/agents/qa-engineer.agent.md +84 -0
- package/templates/squads/bmad/agents/scrum-master.agent.md +84 -0
- package/templates/squads/bmad/agents/solo-dev.agent.md +81 -0
- package/templates/squads/bmad/agents/tech-writer.agent.md +86 -0
- package/templates/squads/bmad/agents/ux-designer.agent.md +81 -0
- package/templates/squads/bmad/squad.yaml +70 -0
- package/templates/squads/bmad/state.json +108 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import Phaser from 'phaser';
|
|
2
|
+
import { avatarKeys, DESK_KEYS, FURNITURE_KEYS, type CharacterName } from './assetKeys';
|
|
3
|
+
import { COLORS } from './palette';
|
|
4
|
+
import type { Agent, AgentStatus } from '@/types/state';
|
|
5
|
+
|
|
6
|
+
// Avatar display scale — characters should be prominent at desk
|
|
7
|
+
const AVATAR_SCALE = 0.8;
|
|
8
|
+
|
|
9
|
+
// Status → badge color mapping
|
|
10
|
+
const STATUS_COLORS: Record<AgentStatus, number> = {
|
|
11
|
+
idle: COLORS.statusIdle,
|
|
12
|
+
working: COLORS.statusWorking,
|
|
13
|
+
done: COLORS.statusDone,
|
|
14
|
+
checkpoint: COLORS.statusCheckpoint,
|
|
15
|
+
delivering: COLORS.statusWorking,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Status → display label
|
|
19
|
+
const STATUS_LABELS: Record<AgentStatus, string> = {
|
|
20
|
+
idle: 'Parado',
|
|
21
|
+
working: 'Trabalhando',
|
|
22
|
+
done: 'Concluído',
|
|
23
|
+
checkpoint: 'Aprovação',
|
|
24
|
+
delivering: 'Entregando',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class AgentSprite {
|
|
28
|
+
private scene: Phaser.Scene;
|
|
29
|
+
private deskTable: Phaser.GameObjects.Image;
|
|
30
|
+
private deskShadow: Phaser.GameObjects.Graphics;
|
|
31
|
+
private desk: Phaser.GameObjects.Image;
|
|
32
|
+
private coffeeMug: Phaser.GameObjects.Image;
|
|
33
|
+
private avatar: Phaser.GameObjects.Image;
|
|
34
|
+
private nameText: Phaser.GameObjects.Text;
|
|
35
|
+
private badgeBg: Phaser.GameObjects.Graphics;
|
|
36
|
+
private statusDot: Phaser.GameObjects.Graphics;
|
|
37
|
+
private statusText: Phaser.GameObjects.Text;
|
|
38
|
+
private animTimer?: Phaser.Time.TimerEvent;
|
|
39
|
+
private agent: Agent;
|
|
40
|
+
private characterName: CharacterName;
|
|
41
|
+
private deskVariant: 'black' | 'white';
|
|
42
|
+
private avatarDisplayH: number = 0;
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
scene: Phaser.Scene,
|
|
46
|
+
x: number,
|
|
47
|
+
y: number,
|
|
48
|
+
characterName: CharacterName,
|
|
49
|
+
deskVariant: 'black' | 'white',
|
|
50
|
+
agent: Agent,
|
|
51
|
+
) {
|
|
52
|
+
this.scene = scene;
|
|
53
|
+
this.agent = agent;
|
|
54
|
+
this.characterName = characterName;
|
|
55
|
+
this.deskVariant = deskVariant;
|
|
56
|
+
|
|
57
|
+
// === VERTICAL LAYOUT (sprites, top to bottom on screen) ===
|
|
58
|
+
// desk_wood: 96x64 @ 1.3x = 125x83px → y-42 to y+42
|
|
59
|
+
// desktop_set: ~48x40 @ 1.3x = 62x52px → y-56 to y-4 (center at y-30)
|
|
60
|
+
// avatar: 48x51 @ 0.8x = 38x41px → y-91 to y-50 (center at y-70)
|
|
61
|
+
//
|
|
62
|
+
// Depth order (low = behind, high = front):
|
|
63
|
+
// avatar → y (seated character, lowest — desk will cover lower body)
|
|
64
|
+
// desk_wood → y+1 (desk surface IN FRONT of avatar → covers avatar's lower half)
|
|
65
|
+
// monitor → y+2 (on desk surface, screen faces viewer)
|
|
66
|
+
// coffee mug → y+3 (foreground item on front desk edge)
|
|
67
|
+
// label → 900/901 (always on top)
|
|
68
|
+
//
|
|
69
|
+
// Result: avatar fully visible above monitor, lower body hidden by desk → seated look
|
|
70
|
+
// =========================================
|
|
71
|
+
|
|
72
|
+
// Avatar — positioned further behind the desk so head/torso is clearly visible
|
|
73
|
+
const avatarKey = this.getAvatarKey(agent.status);
|
|
74
|
+
this.avatar = scene.add.image(x, y - 70, avatarKey)
|
|
75
|
+
.setOrigin(0.5, 0.5)
|
|
76
|
+
.setScale(AVATAR_SCALE)
|
|
77
|
+
.setDepth(y); // LOWEST depth — desk and monitor render in front
|
|
78
|
+
// Lock display height so texture swaps between frames of different pixel dimensions
|
|
79
|
+
// don't cause a visible scale jump (e.g. Male1 blink=56px tall vs talk=51px tall).
|
|
80
|
+
// Width is NOT locked — each frame scales proportionally from this height reference.
|
|
81
|
+
this.avatarDisplayH = this.avatar.displayHeight;
|
|
82
|
+
|
|
83
|
+
// Desk table surface — renders IN FRONT of avatar (covers lower body)
|
|
84
|
+
this.deskTable = scene.add.image(x, y, FURNITURE_KEYS.deskWood)
|
|
85
|
+
.setOrigin(0.5, 0.5)
|
|
86
|
+
.setScale(1.3)
|
|
87
|
+
.setDepth(y + 1);
|
|
88
|
+
|
|
89
|
+
// Monitor — screen-facing (_down orientation), sits on desk surface
|
|
90
|
+
const deskKey = this.getDeskKey(agent.status);
|
|
91
|
+
this.desk = scene.add.image(x, y - 30, deskKey)
|
|
92
|
+
.setOrigin(0.5, 0.5)
|
|
93
|
+
.setScale(1.3)
|
|
94
|
+
.setDepth(y + 2); // On top of desk surface, screen visible to viewer
|
|
95
|
+
|
|
96
|
+
// Coffee mug — right side of desk, away from monitor
|
|
97
|
+
this.coffeeMug = scene.add.image(x + 42, y + 8, 'furniture_coffee_mug')
|
|
98
|
+
.setOrigin(0.5, 1).setScale(1.4).setDepth(y + 3);
|
|
99
|
+
|
|
100
|
+
// Shadow (unused graphics object kept for destroy() compatibility)
|
|
101
|
+
this.deskShadow = scene.add.graphics();
|
|
102
|
+
this.deskShadow.setDepth(y - 1);
|
|
103
|
+
|
|
104
|
+
// Name badge — above avatar head (avatar center y-70, head top ≈ y-91, badge at y-140)
|
|
105
|
+
// badge height = 44px → badge bottom at y-96, leaving 5px gap above avatar top
|
|
106
|
+
const labelY = y - 140;
|
|
107
|
+
|
|
108
|
+
// Background pill behind name + status
|
|
109
|
+
this.badgeBg = scene.add.graphics();
|
|
110
|
+
|
|
111
|
+
// Name text — bold, clean, high contrast
|
|
112
|
+
this.nameText = scene.add.text(x, labelY + 5, agent.name, {
|
|
113
|
+
fontFamily: '"Segoe UI", "Helvetica Neue", Arial, sans-serif',
|
|
114
|
+
fontSize: '16px',
|
|
115
|
+
fontStyle: 'bold',
|
|
116
|
+
color: '#ffffff',
|
|
117
|
+
align: 'center',
|
|
118
|
+
stroke: '#000000',
|
|
119
|
+
strokeThickness: 4,
|
|
120
|
+
resolution: 2,
|
|
121
|
+
}).setOrigin(0.5, 0);
|
|
122
|
+
this.nameText.setDepth(901);
|
|
123
|
+
|
|
124
|
+
// Status dot
|
|
125
|
+
this.statusDot = scene.add.graphics();
|
|
126
|
+
|
|
127
|
+
// Status text — colored with outline
|
|
128
|
+
const statusColor = this.getStatusHexColor(agent.status);
|
|
129
|
+
this.statusText = scene.add.text(x, labelY + 24, STATUS_LABELS[agent.status], {
|
|
130
|
+
fontFamily: '"Segoe UI", "Helvetica Neue", Arial, sans-serif',
|
|
131
|
+
fontSize: '13px',
|
|
132
|
+
fontStyle: 'bold',
|
|
133
|
+
color: statusColor,
|
|
134
|
+
align: 'center',
|
|
135
|
+
stroke: '#000000',
|
|
136
|
+
strokeThickness: 3,
|
|
137
|
+
resolution: 2,
|
|
138
|
+
}).setOrigin(0.5, 0);
|
|
139
|
+
this.statusText.setDepth(901);
|
|
140
|
+
|
|
141
|
+
// Draw background and status dot
|
|
142
|
+
this.drawLabelBackground(x, labelY);
|
|
143
|
+
this.drawStatusDot(x, labelY + 22, agent.status);
|
|
144
|
+
|
|
145
|
+
this.startAnimation(agent.status);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private getStatusHexColor(status: AgentStatus): string {
|
|
149
|
+
const num = STATUS_COLORS[status] ?? COLORS.statusIdle;
|
|
150
|
+
return '#' + num.toString(16).padStart(6, '0');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private getDeskKey(_status: AgentStatus): string {
|
|
154
|
+
// Always show coding desk — all agents are always working
|
|
155
|
+
return this.deskVariant === 'black' ? DESK_KEYS.blackCoding : DESK_KEYS.whiteCoding;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private getAvatarKey(_status: AgentStatus): string {
|
|
159
|
+
// Always start in talk frame — animation will cycle from there
|
|
160
|
+
return avatarKeys(this.characterName).talk;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private drawLabelBackground(x: number, labelY: number): void {
|
|
164
|
+
const nameW = Math.max(this.nameText.width, this.statusText.width + 18);
|
|
165
|
+
const bgW = nameW + 20;
|
|
166
|
+
const bgH = 44;
|
|
167
|
+
// Solid dark background with rounded corners
|
|
168
|
+
this.badgeBg.fillStyle(0x0f1629, 0.95);
|
|
169
|
+
this.badgeBg.fillRoundedRect(x - bgW / 2, labelY, bgW, bgH, 5);
|
|
170
|
+
// Subtle border
|
|
171
|
+
this.badgeBg.lineStyle(1, 0x1a2540, 0.6);
|
|
172
|
+
this.badgeBg.strokeRoundedRect(x - bgW / 2, labelY, bgW, bgH, 4);
|
|
173
|
+
this.badgeBg.setDepth(900);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private drawStatusDot(x: number, _statusY: number, status: AgentStatus): void {
|
|
177
|
+
const dotColor = STATUS_COLORS[status] ?? COLORS.statusIdle;
|
|
178
|
+
const textW = Math.max(this.statusText.width, 24);
|
|
179
|
+
this.statusDot.fillStyle(dotColor, 1);
|
|
180
|
+
this.statusDot.fillCircle(x - textW / 2 - 5, this.statusText.y + this.statusText.height / 2, 3);
|
|
181
|
+
this.statusDot.setDepth(901);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private setAvatarFrame(key: string): void {
|
|
185
|
+
this.avatar.setTexture(key);
|
|
186
|
+
// Scale uniformly so height matches the reference (talk frame) — preserves aspect ratio
|
|
187
|
+
this.avatar.setScale(this.avatarDisplayH / this.avatar.height);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private startAnimation(_status: AgentStatus): void {
|
|
191
|
+
// Always run the working animation regardless of status
|
|
192
|
+
const keys = avatarKeys(this.characterName);
|
|
193
|
+
let frame = 0;
|
|
194
|
+
this.animTimer = this.scene.time.addEvent({
|
|
195
|
+
delay: 500,
|
|
196
|
+
loop: true,
|
|
197
|
+
callback: () => {
|
|
198
|
+
frame = (frame + 1) % 2;
|
|
199
|
+
this.setAvatarFrame(frame === 0 ? keys.talk : keys.blink);
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
updateStatus(agent: Agent): void {
|
|
205
|
+
if (this.agent.status === agent.status) return;
|
|
206
|
+
this.agent = agent;
|
|
207
|
+
|
|
208
|
+
this.desk.setTexture(this.getDeskKey(agent.status));
|
|
209
|
+
this.setAvatarFrame(this.getAvatarKey(agent.status));
|
|
210
|
+
|
|
211
|
+
this.animTimer?.destroy();
|
|
212
|
+
this.startAnimation(agent.status);
|
|
213
|
+
|
|
214
|
+
// Update status text and dot
|
|
215
|
+
this.statusText.setText(STATUS_LABELS[agent.status]);
|
|
216
|
+
this.statusText.setColor(this.getStatusHexColor(agent.status));
|
|
217
|
+
|
|
218
|
+
this.statusDot.clear();
|
|
219
|
+
const dotColor = STATUS_COLORS[agent.status] ?? COLORS.statusIdle;
|
|
220
|
+
this.statusDot.fillStyle(dotColor, 1);
|
|
221
|
+
const textW = Math.max(this.statusText.width, 24);
|
|
222
|
+
this.statusDot.fillCircle(
|
|
223
|
+
this.statusText.x - textW / 2 - 5,
|
|
224
|
+
this.statusText.y + this.statusText.height / 2,
|
|
225
|
+
3,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
hideAvatar(): void {
|
|
230
|
+
this.avatar.setVisible(false);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
showAvatar(): void {
|
|
234
|
+
this.avatar.setVisible(true);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
destroy(): void {
|
|
238
|
+
this.animTimer?.destroy();
|
|
239
|
+
this.deskTable.destroy();
|
|
240
|
+
this.deskShadow.destroy();
|
|
241
|
+
this.desk.destroy();
|
|
242
|
+
this.coffeeMug.destroy();
|
|
243
|
+
this.avatar.destroy();
|
|
244
|
+
this.nameText.destroy();
|
|
245
|
+
this.badgeBg.destroy();
|
|
246
|
+
this.statusDot.destroy();
|
|
247
|
+
this.statusText.destroy();
|
|
248
|
+
}
|
|
249
|
+
}
|