@agent-os-lab/agent-game-sdk 0.1.1

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.
Files changed (68) hide show
  1. package/README.md +99 -0
  2. package/package.json +38 -0
  3. package/src/core/agent-game-store.ts +110 -0
  4. package/src/core/agent-service-event-adapter.ts +20 -0
  5. package/src/core/assets.ts +119 -0
  6. package/src/core/commands.ts +42 -0
  7. package/src/core/errors.ts +19 -0
  8. package/src/core/event-adapter.ts +40 -0
  9. package/src/core/index.ts +23 -0
  10. package/src/core/life-presets.ts +54 -0
  11. package/src/core/movement.ts +50 -0
  12. package/src/core/office-building-layout.ts +376 -0
  13. package/src/core/office-layout.ts +152 -0
  14. package/src/core/pixel-character-avatar.ts +87 -0
  15. package/src/core/pixel-character.ts +684 -0
  16. package/src/core/realtime-events.ts +44 -0
  17. package/src/core/realtime-transport.ts +39 -0
  18. package/src/core/reducer.ts +105 -0
  19. package/src/core/scene.ts +144 -0
  20. package/src/core/schedule.ts +20 -0
  21. package/src/core/sequence.ts +48 -0
  22. package/src/core/state.ts +26 -0
  23. package/src/core/svg-pixel-avatar.ts +372 -0
  24. package/src/core/town-office-assets.ts +109 -0
  25. package/src/core/town-office-room-presets.ts +455 -0
  26. package/src/core/town-office-seat-layout.ts +238 -0
  27. package/src/graph.ts +112 -0
  28. package/src/index.ts +2 -0
  29. package/src/office/core/projection.ts +89 -0
  30. package/src/office/core/source.ts +46 -0
  31. package/src/office/core/types.ts +110 -0
  32. package/src/office/index.ts +4 -0
  33. package/src/office/mount.ts +104 -0
  34. package/src/office/react/AgentGameOfficeView.ts +58 -0
  35. package/src/office/react/index.ts +1 -0
  36. package/src/office/renderers/three/agent-activity-effects.ts +161 -0
  37. package/src/office/renderers/three/agent-animation.ts +205 -0
  38. package/src/office/renderers/three/agent-body-instancing.ts +119 -0
  39. package/src/office/renderers/three/agent-label.ts +82 -0
  40. package/src/office/renderers/three/agent-layout.ts +72 -0
  41. package/src/office/renderers/three/agent-mesh.ts +145 -0
  42. package/src/office/renderers/three/mount.ts +253 -0
  43. package/src/office/renderers/three/scene.ts +790 -0
  44. package/src/phaser/agent-game-scene.ts +87 -0
  45. package/src/phaser/anchor-debug.ts +22 -0
  46. package/src/phaser/avatar-registry.ts +46 -0
  47. package/src/phaser/camera-controls.ts +419 -0
  48. package/src/phaser/camera-model.ts +81 -0
  49. package/src/phaser/create-agent-game.ts +242 -0
  50. package/src/phaser/debug-overlay.ts +21 -0
  51. package/src/phaser/index.ts +13 -0
  52. package/src/phaser/movement-tween.ts +59 -0
  53. package/src/phaser/office-background.ts +48 -0
  54. package/src/phaser/office-building-renderer.ts +87 -0
  55. package/src/phaser/office-layout-renderer.ts +58 -0
  56. package/src/phaser/render-layers.ts +30 -0
  57. package/src/phaser/scene-reconciler.ts +614 -0
  58. package/src/phaser/scene-renderer.ts +138 -0
  59. package/src/phaser/text-style.ts +8 -0
  60. package/src/phaser/town-office-business-props.ts +256 -0
  61. package/src/phaser/town-office-environment.ts +89 -0
  62. package/src/phaser/town-office-furniture.ts +182 -0
  63. package/src/phaser/town-office-primitives.ts +53 -0
  64. package/src/phaser/town-office-renderer.ts +429 -0
  65. package/src/phaser/types.ts +67 -0
  66. package/src/phaser/viewport.ts +88 -0
  67. package/src/runtime-client.ts +435 -0
  68. package/src/types.ts +80 -0
@@ -0,0 +1,138 @@
1
+ import {
2
+ AgentGameError,
3
+ type AgentGameSceneDefinition,
4
+ type OfficeBuildingLayout,
5
+ type OfficeLayoutDefinition,
6
+ } from "../core/index.js";
7
+ import { drawOfficeBackground } from "./office-background.js";
8
+ import { drawOfficeBuildingLayout } from "./office-building-renderer.js";
9
+ import { drawOfficeLayout } from "./office-layout-renderer.js";
10
+ import type { PhaserReconcilerSceneLike } from "./scene-reconciler.js";
11
+ import { drawTownOfficeBuildingLayout, type TownOfficeBuildingRenderOptions } from "./town-office-renderer.js";
12
+
13
+ export type AgentGameSceneRenderer = {
14
+ preload?: (scene: PhaserReconcilerSceneLike) => void;
15
+ create: (scene: PhaserReconcilerSceneLike) => void;
16
+ };
17
+
18
+ export type AgentGameSceneRendererFactory<TOptions = unknown> = (options: TOptions) => AgentGameSceneRenderer;
19
+
20
+ export type AgentGameSceneRendererRegistry = {
21
+ register<TOptions>(kind: string, factory: AgentGameSceneRendererFactory<TOptions>): void;
22
+ create(kind: string, options: unknown): AgentGameSceneRenderer;
23
+ has(kind: string): boolean;
24
+ };
25
+
26
+ export type AgentGameRendererConfig = {
27
+ kind: string;
28
+ options: unknown;
29
+ };
30
+
31
+ export type BackgroundRendererOptions = {
32
+ definition: AgentGameSceneDefinition;
33
+ width: number;
34
+ height: number;
35
+ backgroundImage?: {
36
+ key: string;
37
+ url: string;
38
+ width: number;
39
+ height: number;
40
+ };
41
+ };
42
+
43
+ export type OfficeLayoutRendererOptions = {
44
+ atlasKey: string;
45
+ imageUrl: string;
46
+ atlasUrl: string;
47
+ definition: OfficeLayoutDefinition;
48
+ };
49
+
50
+ export type OfficeBuildingAtlasRendererOptions = {
51
+ atlasKey: string;
52
+ imageUrl: string;
53
+ atlasUrl: string;
54
+ layout: OfficeBuildingLayout;
55
+ };
56
+
57
+ export type TownOfficeBuildingRendererOptions = {
58
+ layout: OfficeBuildingLayout;
59
+ } & TownOfficeBuildingRenderOptions;
60
+
61
+ export function createAgentGameSceneRendererRegistry(): AgentGameSceneRendererRegistry {
62
+ const factories = new Map<string, AgentGameSceneRendererFactory>();
63
+
64
+ return {
65
+ register(kind, factory) {
66
+ factories.set(kind, factory as AgentGameSceneRendererFactory);
67
+ },
68
+ create(kind, options) {
69
+ const factory = factories.get(kind);
70
+ if (!factory) {
71
+ throw new AgentGameError("invalid_renderer", `Unknown agent game scene renderer: ${kind}`);
72
+ }
73
+ return factory(options);
74
+ },
75
+ has(kind) {
76
+ return factories.has(kind);
77
+ },
78
+ };
79
+ }
80
+
81
+ export function createDefaultAgentGameSceneRendererRegistry(): AgentGameSceneRendererRegistry {
82
+ const registry = createAgentGameSceneRendererRegistry();
83
+ registry.register<BackgroundRendererOptions>("background", createBackgroundRenderer);
84
+ registry.register<OfficeLayoutRendererOptions>("office-layout", createOfficeLayoutRenderer);
85
+ registry.register<OfficeBuildingAtlasRendererOptions>("office-building-atlas", createOfficeBuildingAtlasRenderer);
86
+ registry.register<TownOfficeBuildingRendererOptions>("town-office-building", createTownOfficeBuildingRenderer);
87
+ return registry;
88
+ }
89
+
90
+ function createBackgroundRenderer(options: BackgroundRendererOptions): AgentGameSceneRenderer {
91
+ return {
92
+ preload(scene) {
93
+ if (options.backgroundImage) {
94
+ scene.load?.image?.(options.backgroundImage.key, options.backgroundImage.url);
95
+ }
96
+ },
97
+ create(scene) {
98
+ drawOfficeBackground(scene, options.definition, {
99
+ width: options.width,
100
+ height: options.height,
101
+ sceneImage: options.backgroundImage,
102
+ });
103
+ },
104
+ };
105
+ }
106
+
107
+ function createOfficeLayoutRenderer(options: OfficeLayoutRendererOptions): AgentGameSceneRenderer {
108
+ return {
109
+ preload(scene) {
110
+ scene.load?.atlas(options.atlasKey, options.imageUrl, options.atlasUrl);
111
+ },
112
+ create(scene) {
113
+ drawOfficeLayout(scene, options.definition, { atlasKey: options.atlasKey });
114
+ },
115
+ };
116
+ }
117
+
118
+ function createOfficeBuildingAtlasRenderer(options: OfficeBuildingAtlasRendererOptions): AgentGameSceneRenderer {
119
+ return {
120
+ preload(scene) {
121
+ scene.load?.atlas(options.atlasKey, options.imageUrl, options.atlasUrl);
122
+ },
123
+ create(scene) {
124
+ drawOfficeBuildingLayout(scene, options.layout, { atlasKey: options.atlasKey });
125
+ },
126
+ };
127
+ }
128
+
129
+ function createTownOfficeBuildingRenderer(options: TownOfficeBuildingRendererOptions): AgentGameSceneRenderer {
130
+ return {
131
+ create(scene) {
132
+ drawTownOfficeBuildingLayout(scene, options.layout, {
133
+ debugOverlays: options.debugOverlays,
134
+ domOverlayRoot: options.domOverlayRoot,
135
+ });
136
+ },
137
+ };
138
+ }
@@ -0,0 +1,8 @@
1
+ export const PHASER_TEXT_RESOLUTION = 4;
2
+
3
+ export function crispTextStyle(style: Record<string, unknown>): Record<string, unknown> {
4
+ return {
5
+ ...style,
6
+ resolution: PHASER_TEXT_RESOLUTION,
7
+ };
8
+ }
@@ -0,0 +1,256 @@
1
+ import { rect, text, type TownOfficeSceneLike } from "./town-office-primitives.js";
2
+
3
+ export function drawServerRack(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
4
+ const s = scale;
5
+ rect(scene, x, y, 12 * s, 22 * s, "#2a2a30", y);
6
+ for (let row = 0; row < 3; row++) {
7
+ rect(scene, x, y - 8 * s + row * 5 * s, 8 * s, 3 * s, "#1a1a20", y + 1);
8
+ rect(scene, x - 2 * s, y - 8 * s + row * 5 * s, 2 * s, 1 * s, "#44bb44", y + 2);
9
+ rect(scene, x + 2 * s, y - 8 * s + row * 5 * s, 2 * s, 1 * s, row === 1 ? "#ffaa44" : "#44bb44", y + 2);
10
+ }
11
+ rect(scene, x, y + 6 * s, 10 * s, 1 * s, "#3a3a40", y + 1);
12
+ rect(scene, x, y + 10 * s, 8 * s, 4 * s, "#1a1a20", y + 1);
13
+ }
14
+
15
+ export function drawTV(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
16
+ const s = scale;
17
+ rect(scene, x, y, 28 * s, 18 * s, "#2a2a30", y);
18
+ rect(scene, x, y - 1 * s, 26 * s, 14 * s, "#4a8abb", y + 1);
19
+ rect(scene, x, y + 8 * s, 6 * s, 3 * s, "#2a2a30", y + 2);
20
+ rect(scene, x, y + 11 * s, 10 * s, 2 * s, "#3a3a40", y + 2);
21
+ }
22
+
23
+ export function drawMonitorWall(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
24
+ const s = scale;
25
+ const width = 72 * s;
26
+ const height = 32 * s;
27
+ rect(scene, x, y, width, height, "#1a2030", y);
28
+ rect(scene, x, y + height / 2 + 2 * s, width, 3 * s, "#0d1018", y + 1);
29
+ for (let row = 0; row < 2; row++) {
30
+ for (let col = 0; col < 3; col++) {
31
+ const cellX = x - width / 2 + 4 * s + col * 23 * s;
32
+ const cellY = y - height / 2 + 4 * s + row * 14 * s;
33
+ const fill = (row + col) % 3 === 0 ? "#1e5c3a" : (row + col) % 3 === 1 ? "#5c2a1e" : "#1e3a5c";
34
+ const accent = (row + col) % 3 === 0 ? "#3fcc7a" : (row + col) % 3 === 1 ? "#ff6b6b" : "#5bb3ff";
35
+ rect(scene, cellX + 10 * s, cellY + 5 * s, 20 * s, 10 * s, fill, y + 1);
36
+ rect(scene, cellX + 10 * s, cellY + 2 * s, 16 * s, 1 * s, accent, y + 2);
37
+ }
38
+ }
39
+ }
40
+
41
+ export function drawTickerBoard(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
42
+ const s = scale;
43
+ const width = 64 * s;
44
+ rect(scene, x, y, width, 14 * s, "#0a0a0a", y);
45
+ rect(scene, x, y - 6 * s, width, 2 * s, "#222222", y + 1);
46
+ for (let index = 0; index < 4; index++) {
47
+ const color = index % 2 === 0 ? "#22dd66" : "#ff4444";
48
+ rect(scene, x - 24 * s + index * 16 * s, y + 2 * s, 12 * s, 1 * s, color, y + 1);
49
+ rect(scene, x - 24 * s + index * 16 * s, y - 2 * s, 8 * s, 2 * s, color, y + 1);
50
+ }
51
+ }
52
+
53
+ export function drawTestRack(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
54
+ const s = scale;
55
+ rect(scene, x, y, 28 * s, 36 * s, "#3a3a45", y);
56
+ rect(scene, x, y - 12 * s, 24 * s, 10 * s, "#0e1a2e", y + 1);
57
+ rect(scene, x, y + 2 * s, 24 * s, 6 * s, "#1a1a22", y + 1);
58
+ rect(scene, x - 7 * s, y + 2 * s, 3 * s, 2 * s, "#22dd66", y + 2);
59
+ rect(scene, x, y + 2 * s, 3 * s, 2 * s, "#ffcc22", y + 2);
60
+ rect(scene, x, y + 13 * s, 24 * s, 12 * s, "#222222", y + 1);
61
+ rect(scene, x - 6 * s, y + 13 * s, 4 * s, 4 * s, "#5bb3ff", y + 2);
62
+ rect(scene, x + 6 * s, y + 13 * s, 4 * s, 4 * s, "#ff8866", y + 2);
63
+ }
64
+
65
+ export function drawSolarPanel(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
66
+ const s = scale;
67
+ rect(scene, x, y, 24 * s, 16 * s, "#1a2a4a", y);
68
+ for (let row = 0; row < 2; row++) {
69
+ for (let col = 0; col < 4; col++) {
70
+ rect(scene, x - 9 * s + col * 6 * s, y - 4 * s + row * 7 * s, 5 * s, 6 * s, "#3a6fb5", y + 1);
71
+ }
72
+ }
73
+ rect(scene, x, y + 11 * s, 2 * s, 6 * s, "#666666", y + 1);
74
+ rect(scene, x, y + 15 * s, 10 * s, 2 * s, "#666666", y + 1);
75
+ }
76
+
77
+ export function drawCertBadge(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
78
+ const s = scale;
79
+ rect(scene, x, y - 2 * s, 18 * s, 16 * s, "#c8a020", y);
80
+ rect(scene, x, y - 2 * s, 12 * s, 10 * s, "#e8c840", y + 1);
81
+ rect(scene, x - 2 * s, y - 1 * s, 2 * s, 6 * s, "#ffffff", y + 2);
82
+ rect(scene, x + 3 * s, y - 4 * s, 2 * s, 10 * s, "#ffffff", y + 2);
83
+ rect(scene, x - 3 * s, y + 12 * s, 3 * s, 6 * s, "#c02020", y);
84
+ rect(scene, x + 3 * s, y + 12 * s, 3 * s, 6 * s, "#c02020", y);
85
+ }
86
+
87
+ export function drawHenanMap(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
88
+ const s = scale;
89
+ rect(scene, x, y, 80 * s, 60 * s, "#faf3e0", y);
90
+ rect(scene, x, y, 58 * s, 38 * s, "#c8a458", y + 1);
91
+ rect(scene, x - 6 * s, y + 7 * s, 22 * s, 14 * s, "#d8b868", y + 2);
92
+ rect(scene, x - 16 * s, y + 7 * s, 5 * s, 5 * s, "#ffd700", y + 3);
93
+ rect(scene, x + 10 * s, y - 4 * s, 3 * s, 3 * s, "#c02020", y + 3);
94
+ text(scene, x, y + 25 * s, "河南", 5 * s, "#8b6914", y + 4);
95
+ }
96
+
97
+ export function drawBattery(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
98
+ const s = scale;
99
+ rect(scene, x, y, 22 * s, 14 * s, "#3a4a3a", y);
100
+ rect(scene, x + 12 * s, y, 2 * s, 6 * s, "#3a4a3a", y);
101
+ rect(scene, x - 6 * s, y, 5 * s, 10 * s, "#3fcc7a", y + 1);
102
+ rect(scene, x, y, 5 * s, 10 * s, "#3fcc7a", y + 1);
103
+ rect(scene, x + 6 * s, y, 5 * s, 10 * s, "#3fcc7a", y + 1);
104
+ rect(scene, x, y, 4 * s, 8 * s, "#ffee44", y + 2);
105
+ }
106
+
107
+ export function drawTree(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
108
+ const s = scale;
109
+ rect(scene, x, y + 14 * s, 4 * s, 18 * s, "#5a3818", y);
110
+ rect(scene, x, y, 18 * s, 28 * s, "#3a8b4a", y + 1);
111
+ rect(scene, x - 5 * s, y - 8 * s, 10 * s, 12 * s, "#4aa058", y + 2);
112
+ rect(scene, x + 5 * s, y - 8 * s, 10 * s, 12 * s, "#4aa058", y + 2);
113
+ rect(scene, x, y - 16 * s, 8 * s, 8 * s, "#5bc066", y + 3);
114
+ }
115
+
116
+ export function drawEVCharger(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
117
+ const s = scale;
118
+ rect(scene, x, y, 14 * s, 22 * s, "#2a4a3a", y);
119
+ rect(scene, x, y - 6 * s, 10 * s, 6 * s, "#0e1a0e", y + 1);
120
+ text(scene, x, y - 6 * s, "EV", 4 * s, "#3fcc7a", y + 2);
121
+ rect(scene, x, y + 1 * s, 4 * s, 8 * s, "#ffee44", y + 1);
122
+ rect(scene, x, y + 12 * s, 16 * s, 2 * s, "#1a2a1a", y + 1);
123
+ rect(scene, x + 10 * s, y - 5 * s, 6 * s, 2 * s, "#444444", y + 1);
124
+ }
125
+
126
+ export function drawMegaphone(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
127
+ const s = scale;
128
+ rect(scene, x - 5 * s, y, 10 * s, 10 * s, "#d87838", y);
129
+ rect(scene, x + 5 * s, y, 12 * s, 14 * s, "#d87838", y);
130
+ rect(scene, x - 13 * s, y, 4 * s, 4 * s, "#8b4818", y + 1);
131
+ rect(scene, x + 17 * s, y - 3 * s, 2 * s, 8 * s, "#ffcc22", y + 1);
132
+ rect(scene, x, y + 11 * s, 2 * s, 6 * s, "#666666", y + 1);
133
+ rect(scene, x, y + 16 * s, 10 * s, 2 * s, "#666666", y + 1);
134
+ }
135
+
136
+ export function drawChartBoard(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
137
+ const s = scale;
138
+ rect(scene, x, y, 50 * s, 30 * s, "#fafafa", y);
139
+ rect(scene, x - 18 * s, y + 10 * s, 4 * s, 8 * s, "#5bb3ff", y + 1);
140
+ rect(scene, x - 12 * s, y + 8 * s, 4 * s, 12 * s, "#5bb3ff", y + 1);
141
+ rect(scene, x - 6 * s, y + 6 * s, 4 * s, 16 * s, "#3fcc7a", y + 1);
142
+ rect(scene, x, y + 8 * s, 4 * s, 10 * s, "#5bb3ff", y + 1);
143
+ rect(scene, x + 6 * s, y + 3 * s, 4 * s, 20 * s, "#3fcc7a", y + 1);
144
+ rect(scene, x + 12 * s, y + 6 * s, 4 * s, 14 * s, "#5bb3ff", y + 1);
145
+ rect(scene, x + 6 * s, y - 7 * s, 28 * s, 1 * s, "#ff4444", y + 2);
146
+ }
147
+
148
+ export function drawRedBanner(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
149
+ const s = scale;
150
+ rect(scene, x, y, 80 * s, 12 * s, "#c02020", y);
151
+ rect(scene, x - 38 * s, y + 8 * s, 4 * s, 4 * s, "#8b1010", y);
152
+ rect(scene, x + 38 * s, y + 8 * s, 4 * s, 4 * s, "#8b1010", y);
153
+ text(scene, x, y, "决策", 6 * s, "#ffee44", y + 1);
154
+ }
155
+
156
+ export function drawBeaker(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
157
+ const s = scale;
158
+ rect(scene, x, y + 1 * s, 12 * s, 14 * s, "#d8dde4", y);
159
+ rect(scene, x, y + 4 * s, 10 * s, 5 * s, "#5bb3ff", y + 1);
160
+ rect(scene, x, y - 7 * s, 10 * s, 2 * s, "#666666", y + 1);
161
+ rect(scene, x - 2 * s, y + 4 * s, 1 * s, 1 * s, "#ffffff", y + 2);
162
+ rect(scene, x + 2 * s, y + 3 * s, 1 * s, 1 * s, "#ffffff", y + 2);
163
+ }
164
+
165
+ export function drawPingPongTable(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
166
+ const s = scale;
167
+ rect(scene, x, y, 40 * s, 24 * s, "#1a6b3a", y);
168
+ rect(scene, x, y - 11 * s, 40 * s, 2 * s, "#228b44", y + 1);
169
+ rect(scene, x, y, 2 * s, 24 * s, "#ffffff", y + 1);
170
+ rect(scene, x, y - 10 * s, 4 * s, 2 * s, "#888888", y + 2);
171
+ rect(scene, x - 16 * s, y + 15 * s, 4 * s, 6 * s, "#5a5a60", y + 1);
172
+ rect(scene, x + 16 * s, y + 15 * s, 4 * s, 6 * s, "#5a5a60", y + 1);
173
+ }
174
+
175
+ export function drawPodium(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
176
+ const s = scale;
177
+ rect(scene, x, y, 14 * s, 18 * s, "#6b4a28", y);
178
+ rect(scene, x, y - 6 * s, 12 * s, 3 * s, "#ffd700", y + 1);
179
+ rect(scene, x, y, 8 * s, 6 * s, "#3a2a18", y + 1);
180
+ rect(scene, x - 2 * s, y - 11 * s, 1 * s, 3 * s, "#888888", y + 1);
181
+ }
182
+
183
+ export function drawPartyFlag(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
184
+ const s = scale;
185
+ rect(scene, x - 11 * s, y, 1.2 * s, 32 * s, "#5a4028", y);
186
+ rect(scene, x, y - 9 * s, 20 * s, 13 * s, "#c41e3a", y + 1);
187
+ text(scene, x - 5 * s, y - 8 * s, "*", 6 * s, "#ffd700", y + 2);
188
+ }
189
+
190
+ export function drawWindTurbine(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
191
+ const s = scale;
192
+ rect(scene, x, y + 8 * s, 2 * s, 28 * s, "#d8dce4", y);
193
+ rect(scene, x, y - 7 * s, 4 * s, 4 * s, "#9aa0ac", y + 1);
194
+ rect(scene, x, y - 13 * s, 2 * s, 12 * s, "#ffffff", y + 2);
195
+ rect(scene, x + 6 * s, y - 6 * s, 12 * s, 2 * s, "#ffffff", y + 2);
196
+ rect(scene, x - 6 * s, y - 6 * s, 12 * s, 2 * s, "#ffffff", y + 2);
197
+ rect(scene, x, y + 24 * s, 6 * s, 2 * s, "#5a6070", y + 1);
198
+ }
199
+
200
+ export function drawTransmissionTower(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
201
+ const s = scale;
202
+ rect(scene, x, y, 2 * s, 30 * s, "#7a8090", y);
203
+ rect(scene, x - 3 * s, y + 4 * s, 2 * s, 24 * s, "#7a8090", y);
204
+ rect(scene, x + 3 * s, y + 4 * s, 2 * s, 24 * s, "#7a8090", y);
205
+ rect(scene, x, y - 5 * s, 10 * s, 1 * s, "#7a8090", y + 1);
206
+ rect(scene, x, y + 3 * s, 12 * s, 1 * s, "#7a8090", y + 1);
207
+ rect(scene, x, y + 12 * s, 14 * s, 1 * s, "#7a8090", y + 1);
208
+ }
209
+
210
+ export function drawGazebo(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
211
+ const s = scale;
212
+ rect(scene, x, y - 8 * s, 24 * s, 8 * s, "#a05030", y);
213
+ rect(scene, x, y - 14 * s, 16 * s, 6 * s, "#8b3818", y + 1);
214
+ rect(scene, x - 10 * s, y + 8 * s, 2 * s, 16 * s, "#6b3818", y);
215
+ rect(scene, x + 10 * s, y + 8 * s, 2 * s, 16 * s, "#6b3818", y);
216
+ rect(scene, x, y + 16 * s, 16 * s, 4 * s, "#c8a878", y + 1);
217
+ rect(scene, x, y + 9 * s, 12 * s, 6 * s, "#e8d8b8", y + 1);
218
+ }
219
+
220
+ export function drawBicycleRack(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
221
+ const s = scale;
222
+ rect(scene, x, y - 3 * s, 32 * s, 1.5 * s, "#5a6070", y);
223
+ for (let index = 0; index < 5; index++) {
224
+ rect(scene, x - 14 * s + index * 7 * s, y - 6 * s, 1 * s, 6 * s, "#5a6070", y + 1);
225
+ }
226
+ rect(scene, x - 6 * s, y + 5 * s, 6 * s, 6 * s, "#1a1a1a", y + 1);
227
+ rect(scene, x + 2 * s, y + 5 * s, 6 * s, 6 * s, "#1a1a1a", y + 1);
228
+ rect(scene, x - 2 * s, y + 5 * s, 10 * s, 1 * s, "#c03030", y + 2);
229
+ }
230
+
231
+ export function drawBigScreen(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
232
+ const s = scale;
233
+ rect(scene, x, y, 90 * s, 32 * s, "#0a1428", y);
234
+ rect(scene, x, y, 86 * s, 28 * s, "#0f1f3a", y + 1);
235
+ for (let index = 0; index < 8; index++) {
236
+ rect(scene, x - 37 * s + index * 10 * s, y + 10 * s, 7 * s, (3 + (index * 5) % 8) * s, "#3fcc7a", y + 2);
237
+ }
238
+ rect(scene, x, y - 6 * s, 60 * s, 1 * s, "#5bc0ff", y + 2);
239
+ }
240
+
241
+ export function drawKpiCard(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
242
+ const s = scale;
243
+ rect(scene, x, y, 36 * s, 18 * s, "#ffffff", y);
244
+ rect(scene, x, y - 7 * s, 36 * s, 4 * s, "#3a6faa", y + 1);
245
+ text(scene, x, y - 7 * s, "KPI", 3 * s, "#ffffff", y + 2);
246
+ text(scene, x, y + 3 * s, "98", 6 * s, "#1a2840", y + 2);
247
+ }
248
+
249
+ export function drawSeal(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
250
+ const s = scale;
251
+ rect(scene, x, y, 16 * s, 16 * s, "#c41e3a", y);
252
+ rect(scene, x, y, 11 * s, 11 * s, "#ffffff", y + 1);
253
+ rect(scene, x, y, 8 * s, 8 * s, "#c41e3a", y + 2);
254
+ text(scene, x, y, "章", 4 * s, "#ffffff", y + 3);
255
+ rect(scene, x, y + 9 * s, 8 * s, 2 * s, "#7a0f1a", y);
256
+ }
@@ -0,0 +1,89 @@
1
+ import type { OfficeRoomBounds } from "../core/index.js";
2
+ import { drawBookshelf, drawWhiteboard } from "./town-office-furniture.js";
3
+ import { rect, type TownOfficeSceneLike } from "./town-office-primitives.js";
4
+
5
+ export type TownOfficeRoomStyle = {
6
+ floor: string;
7
+ wallTop: string;
8
+ accent: string;
9
+ };
10
+
11
+ const HEADER_HEIGHT = 34;
12
+
13
+ export function drawRoomEnvironment(
14
+ scene: TownOfficeSceneLike,
15
+ bounds: OfficeRoomBounds,
16
+ roomType: string,
17
+ style: TownOfficeRoomStyle,
18
+ ): void {
19
+ rect(scene, bounds.x + bounds.width / 2, bounds.y + bounds.height - 2, bounds.width, 3, style.wallTop, 2);
20
+ if (roomType === "dispatch" || roomType === "testing" || roomType === "resource") {
21
+ drawWhiteboard(scene, bounds.x + bounds.width / 2 - 44, bounds.y + HEADER_HEIGHT + 18, 88, 26);
22
+ }
23
+ if (roomType === "lounge" || roomType === "archive" || roomType === "library") {
24
+ drawBookshelf(scene, bounds.x + bounds.width - 46, bounds.y + HEADER_HEIGHT + 14, 1.2);
25
+ }
26
+ }
27
+
28
+ export function drawWindow(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
29
+ const s = scale;
30
+ rect(scene, x, y, 24 * s, 12 * s, "#1a2a40", y);
31
+ rect(scene, x, y, 22 * s, 10 * s, "#6aafe8", y + 1);
32
+ rect(scene, x, y - 3 * s, 22 * s, 4 * s, "#8cc8f8", y + 2);
33
+ rect(scene, x, y, 1 * s, 10 * s, "#e0e4e8", y + 3);
34
+ rect(scene, x, y, 22 * s, 1 * s, "#e0e4e8", y + 3);
35
+ }
36
+
37
+ export function drawAirConditioner(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
38
+ const s = scale;
39
+ rect(scene, x, y, 24 * s, 8 * s, "#e8e8e8", y);
40
+ rect(scene, x, y - 2 * s, 22 * s, 2 * s, "#f0f0f0", y + 1);
41
+ rect(scene, x, y + 2 * s, 20 * s, 1 * s, "#d0d0d0", y + 1);
42
+ rect(scene, x + 8 * s, y - 2 * s, 3 * s, 1 * s, "#44bb44", y + 2);
43
+ }
44
+
45
+ export function drawExitSign(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
46
+ const s = scale;
47
+ rect(scene, x, y, 18 * s, 8 * s, "#228b22", y);
48
+ rect(scene, x, y, 16 * s, 6 * s, "#33aa33", y + 1);
49
+ rect(scene, x - 4 * s, y, 4 * s, 4 * s, "#ffffff", y + 2);
50
+ rect(scene, x + 4 * s, y, 6 * s, 2 * s, "#ffffff", y + 2);
51
+ }
52
+
53
+ export function drawPicture(scene: TownOfficeSceneLike, x: number, y: number, scale: number, color: string): void {
54
+ const s = scale;
55
+ rect(scene, x, y, 14 * s, 10 * s, "#6b4a10", y);
56
+ rect(scene, x, y, 12 * s, 8 * s, color, y + 1);
57
+ rect(scene, x - 3 * s, y + 2 * s, 5 * s, 3 * s, "#4a7a3a", y + 2);
58
+ rect(scene, x + 2 * s, y + 1 * s, 4 * s, 4 * s, "#3a6a2a", y + 2);
59
+ rect(scene, x + 4 * s, y - 2 * s, 2 * s, 2 * s, "#ffd700", y + 2);
60
+ }
61
+
62
+ export function drawPrinter(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
63
+ const s = scale;
64
+ rect(scene, x, y, 16 * s, 10 * s, "#d8d8d8", y);
65
+ rect(scene, x, y - 4 * s, 10 * s, 5 * s, "#f5f5f0", y + 1);
66
+ rect(scene, x, y + 6 * s, 10 * s, 3 * s, "#f5f5f0", y + 1);
67
+ rect(scene, x + 5 * s, y - 1 * s, 2 * s, 2 * s, "#44bb44", y + 2);
68
+ rect(scene, x - 5 * s, y + 2 * s, 3 * s, 2 * s, "#bbbbbb", y + 2);
69
+ }
70
+
71
+ export function drawDoor(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
72
+ const s = scale;
73
+ rect(scene, x, y, 16 * s, 20 * s, "#8b6914", y);
74
+ rect(scene, x, y, 14 * s, 18 * s, "#9a7824", y + 1);
75
+ rect(scene, x + 5 * s, y, 2 * s, 2 * s, "#c8a830", y + 2);
76
+ }
77
+
78
+ export function drawLightSwitch(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
79
+ const s = scale;
80
+ rect(scene, x, y, 4 * s, 6 * s, "#e8e8e0", y);
81
+ rect(scene, x, y - 1 * s, 2 * s, 2 * s, "#d0d0c8", y + 1);
82
+ }
83
+
84
+ export function drawSocket(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
85
+ const s = scale;
86
+ rect(scene, x, y, 5 * s, 5 * s, "#e0e0d8", y);
87
+ rect(scene, x - 1 * s, y, 1 * s, 1 * s, "#888888", y + 1);
88
+ rect(scene, x + 1 * s, y, 1 * s, 1 * s, "#888888", y + 1);
89
+ }
@@ -0,0 +1,182 @@
1
+ import { rect, type TownOfficeSceneLike } from "./town-office-primitives.js";
2
+
3
+ export function drawDesk(scene: TownOfficeSceneLike, x: number, y: number, scale: number, hasMonitor: boolean): void {
4
+ const s = 1.5 * scale;
5
+ rect(scene, x, y, 20 * s, 10 * s, "#8b6914", y);
6
+ rect(scene, x, y - 4 * s, 20 * s, 2 * s, "#a07820", y + 1);
7
+ rect(scene, x - 7 * s, y + 8 * s, 3 * s, 4 * s, "#6b4a10", y + 1);
8
+ rect(scene, x + 7 * s, y + 8 * s, 3 * s, 4 * s, "#6b4a10", y + 1);
9
+ if (hasMonitor) {
10
+ drawMonitor(scene, x, y - 12 * s, scale);
11
+ }
12
+ }
13
+
14
+ export function drawMonitor(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
15
+ const s = 1.5 * scale;
16
+ rect(scene, x, y, 10 * s, 8 * s, "#2a2a30", y);
17
+ rect(scene, x, y, 8 * s, 5 * s, "#4a8abb", y + 1);
18
+ rect(scene, x, y + 5 * s, 4 * s, 2 * s, "#2a2a30", y + 1);
19
+ }
20
+
21
+ export function drawChair(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
22
+ const s = 1.6 * scale;
23
+ rect(scene, x, y, 8 * s, 6 * s, "#3a3a40", y);
24
+ rect(scene, x, y - 4 * s, 6 * s, 3 * s, "#4a4a50", y);
25
+ }
26
+
27
+ export function drawPlant(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
28
+ const s = scale;
29
+ rect(scene, x, y + 7 * s, 8 * s, 8 * s, "#8b5a2b", y);
30
+ rect(scene, x - 5 * s, y - 4 * s, 8 * s, 12 * s, "#2d8b3a", y + 1);
31
+ rect(scene, x + 5 * s, y - 8 * s, 8 * s, 12 * s, "#3d9b4a", y + 1);
32
+ rect(scene, x, y - 10 * s, 10 * s, 14 * s, "#4aad5a", y + 1);
33
+ }
34
+
35
+ export function drawBookshelf(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
36
+ const s = scale;
37
+ rect(scene, x, y, 18 * s, 28 * s, "#6b4a10", y);
38
+ for (let row = 0; row < 3; row++) {
39
+ rect(scene, x, y - 10 * s + row * 9 * s, 16 * s, 2 * s, "#8b6914", y + 1);
40
+ rect(scene, x - 5 * s, y - 8 * s + row * 9 * s, 4 * s, 6 * s, "#c04040", y + 1);
41
+ rect(scene, x, y - 8 * s + row * 9 * s, 4 * s, 6 * s, "#4080c0", y + 1);
42
+ rect(scene, x + 5 * s, y - 8 * s + row * 9 * s, 4 * s, 6 * s, "#40a040", y + 1);
43
+ }
44
+ }
45
+
46
+ export function drawTable(scene: TownOfficeSceneLike, x: number, y: number, width: number, height: number): void {
47
+ rect(scene, x, y, width, height, "#7a5a18", y);
48
+ rect(scene, x, y - height / 2 + 3, width - 4, 4, "#9a7a28", y + 1);
49
+ }
50
+
51
+ export function drawWhiteboard(scene: TownOfficeSceneLike, x: number, y: number, width: number, height: number): void {
52
+ rect(scene, x + width / 2, y + height / 2, width, height, "#fffef0", y);
53
+ rect(scene, x + width / 2, y + 3, width, 6, "#3f6596", y + 1);
54
+ }
55
+
56
+ export function drawSofa(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
57
+ const s = scale;
58
+ rect(scene, x, y, 70 * s, 20 * s, "#665044", y);
59
+ rect(scene, x, y - 12 * s, 64 * s, 18 * s, "#806658", y);
60
+ rect(scene, x - 38 * s, y, 8 * s, 22 * s, "#4f3d34", y + 1);
61
+ rect(scene, x + 38 * s, y, 8 * s, 22 * s, "#4f3d34", y + 1);
62
+ }
63
+
64
+ export function drawLaptop(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
65
+ const s = scale;
66
+ rect(scene, x, y - 5 * s, 20 * s, 12 * s, "#2a2a30", y);
67
+ rect(scene, x, y - 5 * s, 16 * s, 8 * s, "#6aa5c8", y + 1);
68
+ rect(scene, x, y + 4 * s, 24 * s, 4 * s, "#4a4a50", y + 1);
69
+ }
70
+
71
+ export function drawCabinet(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
72
+ const s = scale;
73
+ rect(scene, x, y, 28 * s, 30 * s, "#5b6470", y);
74
+ rect(scene, x, y - 7 * s, 22 * s, 2 * s, "#d4d8dd", y + 1);
75
+ rect(scene, x, y + 6 * s, 22 * s, 2 * s, "#d4d8dd", y + 1);
76
+ }
77
+
78
+ export function drawMachine(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
79
+ const s = scale;
80
+ rect(scene, x, y, 18 * s, 28 * s, "#e8e8e8", y);
81
+ rect(scene, x, y - 12 * s, 14 * s, 8 * s, "#88bbdd", y + 1);
82
+ rect(scene, x - 4 * s, y - 2 * s, 3 * s, 3 * s, "#dd4444", y + 1);
83
+ rect(scene, x + 4 * s, y - 2 * s, 3 * s, 3 * s, "#4488dd", y + 1);
84
+ }
85
+
86
+ export function drawCoffeeMachine(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
87
+ const s = scale;
88
+ rect(scene, x, y, 14 * s, 14 * s, "#2a2a2a", y);
89
+ rect(scene, x, y - 6 * s, 12 * s, 2 * s, "#4a4a4a", y + 1);
90
+ rect(scene, x, y, 8 * s, 6 * s, "#1a1a1a", y + 1);
91
+ rect(scene, x, y, 6 * s, 4 * s, "#332211", y + 2);
92
+ rect(scene, x, y - 10 * s, 4 * s, 5 * s, "#e8e0d8", y + 1);
93
+ }
94
+
95
+ export function drawVendingMachine(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
96
+ const s = scale;
97
+ rect(scene, x, y, 16 * s, 24 * s, "#3a5a8a", y);
98
+ rect(scene, x, y - 10 * s, 14 * s, 2 * s, "#4a6a9a", y + 1);
99
+ rect(scene, x - 3 * s, y - 4 * s, 5 * s, 4 * s, "#ffaa44", y + 1);
100
+ rect(scene, x + 3 * s, y - 4 * s, 5 * s, 4 * s, "#44aa66", y + 1);
101
+ rect(scene, x - 3 * s, y + 2 * s, 5 * s, 4 * s, "#dd5555", y + 1);
102
+ rect(scene, x + 3 * s, y + 2 * s, 5 * s, 4 * s, "#6688cc", y + 1);
103
+ rect(scene, x, y + 8 * s, 11 * s, 3 * s, "#222230", y + 1);
104
+ }
105
+
106
+ export function drawPhone(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
107
+ const s = scale;
108
+ rect(scene, x, y, 12 * s, 6 * s, "#2a2a30", y);
109
+ rect(scene, x, y, 10 * s, 2 * s, "#3a3a40", y + 1);
110
+ rect(scene, x, y - 4 * s, 8 * s, 3 * s, "#1a1a20", y + 1);
111
+ rect(scene, x + 4 * s, y + 2 * s, 2 * s, 1 * s, "#44bb44", y + 1);
112
+ }
113
+
114
+ export function drawScheduleBoard(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
115
+ const s = scale;
116
+ rect(scene, x, y, 26 * s, 20 * s, "#fffef0", y);
117
+ rect(scene, x, y - 8 * s, 26 * s, 4 * s, "#c41e3a", y + 1);
118
+ for (let row = 0; row < 4; row++) {
119
+ rect(scene, x - 8 * s, y - 2 * s + row * 3 * s, 4 * s, 1 * s, ["#3366aa", "#cc4444", "#33aa66", "#aa8833"][row], y + 1);
120
+ rect(scene, x + 5 * s, y - 2 * s + row * 3 * s, 14 * s, 1 * s, "#666666", y + 1);
121
+ }
122
+ }
123
+
124
+ export function drawTrashCan(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
125
+ const s = scale;
126
+ rect(scene, x, y, 10 * s, 12 * s, "#666670", y);
127
+ rect(scene, x, y - 5 * s, 10 * s, 2 * s, "#777780", y + 1);
128
+ rect(scene, x, y - 7 * s, 6 * s, 3 * s, "#555560", y + 1);
129
+ rect(scene, x - 2 * s, y, 1 * s, 6 * s, "#555560", y + 1);
130
+ rect(scene, x + 2 * s, y, 1 * s, 6 * s, "#555560", y + 1);
131
+ }
132
+
133
+ export function drawBench(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
134
+ const s = scale;
135
+ rect(scene, x, y, 28 * s, 4 * s, "#8b6914", y);
136
+ rect(scene, x, y - 6 * s, 28 * s, 2 * s, "#8b6914", y + 1);
137
+ rect(scene, x - 11 * s, y + 5 * s, 3 * s, 6 * s, "#6b4a10", y + 1);
138
+ rect(scene, x + 11 * s, y + 5 * s, 3 * s, 6 * s, "#6b4a10", y + 1);
139
+ }
140
+
141
+ export function drawFlowerPot(scene: TownOfficeSceneLike, x: number, y: number, scale: number, color: string): void {
142
+ const s = scale;
143
+ rect(scene, x, y + 4 * s, 10 * s, 8 * s, "#b06030", y);
144
+ rect(scene, x, y + 1 * s, 10 * s, 2 * s, "#c07040", y + 1);
145
+ rect(scene, x - 2 * s, y - 4 * s, 2 * s, 5 * s, "#3d9b4a", y + 1);
146
+ rect(scene, x + 2 * s, y - 3 * s, 2 * s, 4 * s, "#3d9b4a", y + 1);
147
+ rect(scene, x - 3 * s, y - 7 * s, 3 * s, 3 * s, color, y + 2);
148
+ rect(scene, x + 3 * s, y - 6 * s, 3 * s, 3 * s, color, y + 2);
149
+ }
150
+
151
+ export function drawClock(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
152
+ const s = scale;
153
+ rect(scene, x, y, 10 * s, 10 * s, "#f0eee8", y);
154
+ rect(scene, x, y, 8 * s, 8 * s, "#fffff8", y + 1);
155
+ rect(scene, x, y, 2 * s, 4 * s, "#333333", y + 2);
156
+ rect(scene, x + 2 * s, y - 1 * s, 3 * s, 1 * s, "#333333", y + 2);
157
+ }
158
+
159
+ export function drawBulletinBoard(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
160
+ const s = scale;
161
+ rect(scene, x, y, 24 * s, 18 * s, "#b08840", y);
162
+ rect(scene, x, y, 22 * s, 16 * s, "#c8a858", y + 1);
163
+ rect(scene, x - 6 * s, y - 4 * s, 6 * s, 5 * s, "#ffffcc", y + 2);
164
+ rect(scene, x + 3 * s, y - 5 * s, 6 * s, 5 * s, "#ccffcc", y + 2);
165
+ rect(scene, x - 5 * s, y + 5 * s, 7 * s, 4 * s, "#ffcccc", y + 2);
166
+ rect(scene, x + 5 * s, y + 4 * s, 5 * s, 5 * s, "#ccccff", y + 2);
167
+ }
168
+
169
+ export function drawFireExtinguisher(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
170
+ const s = scale;
171
+ rect(scene, x, y, 6 * s, 12 * s, "#cc2222", y);
172
+ rect(scene, x, y - 7 * s, 4 * s, 3 * s, "#222222", y + 1);
173
+ rect(scene, x, y - 3 * s, 8 * s, 2 * s, "#dd3333", y + 1);
174
+ rect(scene, x, y + 2 * s, 4 * s, 3 * s, "#ffd700", y + 1);
175
+ }
176
+
177
+ export function drawRugMat(scene: TownOfficeSceneLike, x: number, y: number, scale: number): void {
178
+ const s = scale;
179
+ rect(scene, x, y, 30 * s, 6 * s, "#8b4040", y);
180
+ rect(scene, x, y, 26 * s, 3 * s, "#a64f4f", y + 1);
181
+ rect(scene, x, y, 20 * s, 1 * s, "#ffe0a0", y + 2);
182
+ }