@agent-os-lab/agent-game-sdk 0.1.14 → 0.1.15

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/README.md CHANGED
@@ -94,6 +94,12 @@ const view = mountAgentAvatar3D(container, {
94
94
  sceneState: "working",
95
95
  framing: "upperBody",
96
96
  viewAngle: "front",
97
+ camera: {
98
+ fov: 32,
99
+ positionY: 2.1,
100
+ positionZ: 1.35,
101
+ lookAtY: 1.42,
102
+ },
97
103
  });
98
104
 
99
105
  view.update({ sceneState: "thinking", framing: "fullBody", viewAngle: "threeQuarter" });
package/USAGE.md CHANGED
@@ -191,6 +191,12 @@ const view = mountAgentAvatar3D(container, {
191
191
  sceneState: "working",
192
192
  framing: "upperBody",
193
193
  viewAngle: "front",
194
+ camera: {
195
+ fov: 32,
196
+ positionY: 2.1,
197
+ positionZ: 1.35,
198
+ lookAtY: 1.42,
199
+ },
194
200
  });
195
201
 
196
202
  view.update({
@@ -203,6 +209,7 @@ view.destroy();
203
209
  ```
204
210
 
205
211
  `framing` supports `fullBody` and `upperBody`. `viewAngle` supports `front` and `threeQuarter`.
212
+ Use `camera` to fine-tune the portrait crop with `fov`, `positionY`, `positionZ`, and `lookAtY`.
206
213
  Passing the same `agentId` used in the office game gives the standalone 3D view the same appearance as the office game scene. Use `renderIndex` only when you need to override that AgentID-derived appearance.
207
214
 
208
215
  ### Static 3D Thumbnails
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-os-lab/agent-game-sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -17,8 +17,18 @@ import {
17
17
  import { createAgentMesh, type AgentMeshParts } from "../office/renderers/three/agent-mesh";
18
18
  import type { AgentAvatar3DFraming, AgentAvatar3DViewAngle } from "./three-view";
19
19
 
20
+ export type AgentAvatar3DCameraOptions = {
21
+ fov?: number;
22
+ positionY?: number;
23
+ positionZ?: number;
24
+ lookAtY?: number;
25
+ };
26
+
27
+ export type ResolvedAgentAvatar3DCameraOptions = Required<AgentAvatar3DCameraOptions>;
28
+
20
29
  export type AgentAvatar3DSceneOptions = {
21
30
  agent?: Partial<AgentGameOfficeAgent>;
31
+ camera?: AgentAvatar3DCameraOptions;
22
32
  agentId?: string;
23
33
  framing?: AgentAvatar3DFraming;
24
34
  sceneState?: AgentGameOfficeSceneState;
@@ -29,6 +39,7 @@ export type AgentAvatar3DSceneOptions = {
29
39
  };
30
40
 
31
41
  export type ResolvedAgentAvatar3DState = AgentGameOfficeAgent & {
42
+ camera: ResolvedAgentAvatar3DCameraOptions;
32
43
  framing: AgentAvatar3DFraming;
33
44
  renderIndex: number;
34
45
  viewAngle: AgentAvatar3DViewAngle;
@@ -59,7 +70,7 @@ export function createAgentAvatar3DScene(options: AgentAvatar3DSceneOptions): Ag
59
70
  const mesh = createAgentMesh(state, state.renderIndex);
60
71
  mesh.group.position.set(0, 0, 0);
61
72
  applyAvatar3DViewAngle(mesh.group, state.viewAngle);
62
- applyAvatar3DFraming(camera, state.framing);
73
+ applyAvatar3DCamera(camera, state.camera);
63
74
  scene.add(mesh.group);
64
75
  const bodyLayer = createAgentBodyInstancedLayer(scene);
65
76
  const effectLayer = createAgentEffectInstancedLayer(scene);
@@ -76,7 +87,7 @@ export function createAgentAvatar3DScene(options: AgentAvatar3DSceneOptions): Ag
76
87
  setState(nextOptions, preservedRenderIndex) {
77
88
  state = resolveAgentAvatar3DState(nextOptions, preservedRenderIndex);
78
89
  applyAvatar3DViewAngle(mesh.group, state.viewAngle);
79
- applyAvatar3DFraming(camera, state.framing);
90
+ applyAvatar3DCamera(camera, state.camera);
80
91
  return state;
81
92
  },
82
93
  render(renderer, nowMs) {
@@ -106,6 +117,7 @@ export function resolveAgentAvatar3DState(
106
117
  };
107
118
  return {
108
119
  ...agent,
120
+ camera: resolveAgentAvatar3DCamera(options.framing ?? "fullBody", options.camera),
109
121
  framing: options.framing ?? "fullBody",
110
122
  sceneState: options.sceneState ?? agent.sceneState,
111
123
  renderIndex: options.renderIndex ?? preservedRenderIndex ?? resolveAgentAvatarRenderIndex(agent.id),
@@ -113,15 +125,32 @@ export function resolveAgentAvatar3DState(
113
125
  };
114
126
  }
115
127
 
116
- function applyAvatar3DFraming(camera: THREE.PerspectiveCamera, framing: AgentAvatar3DFraming): void {
128
+ function resolveAgentAvatar3DCamera(
129
+ framing: AgentAvatar3DFraming,
130
+ camera?: AgentAvatar3DCameraOptions,
131
+ ): ResolvedAgentAvatar3DCameraOptions {
117
132
  if (framing === "upperBody") {
118
- camera.position.set(0, 2.55, 3.35);
119
- camera.lookAt(0, 1.42, 0);
120
- return;
133
+ return {
134
+ fov: camera?.fov ?? 32,
135
+ positionY: camera?.positionY ?? 2.1,
136
+ positionZ: camera?.positionZ ?? 1.35,
137
+ lookAtY: camera?.lookAtY ?? 1.42,
138
+ };
121
139
  }
122
140
 
123
- camera.position.set(0, 2.1, 5.2);
124
- camera.lookAt(0, 1.05, 0);
141
+ return {
142
+ fov: camera?.fov ?? 38,
143
+ positionY: camera?.positionY ?? 2.1,
144
+ positionZ: camera?.positionZ ?? 5.2,
145
+ lookAtY: camera?.lookAtY ?? 1.05,
146
+ };
147
+ }
148
+
149
+ function applyAvatar3DCamera(camera: THREE.PerspectiveCamera, options: ResolvedAgentAvatar3DCameraOptions): void {
150
+ camera.fov = options.fov;
151
+ camera.position.set(0, options.positionY, options.positionZ);
152
+ camera.lookAt(0, options.lookAtY, 0);
153
+ camera.updateProjectionMatrix();
125
154
  }
126
155
 
127
156
  function applyAvatar3DViewAngle(group: THREE.Group, viewAngle: AgentAvatar3DViewAngle): void {
@@ -47,6 +47,7 @@ export type AgentAvatar3DThumbnailMountOptions = AgentAvatar3DThumbnailOptions &
47
47
  export type AgentAvatar3DThumbnailController = {
48
48
  image: HTMLImageElement;
49
49
  thumbnail: AgentAvatar3DThumbnail;
50
+ update(options: AgentAvatar3DThumbnailOptions): AgentAvatar3DThumbnail;
50
51
  destroy(): void;
51
52
  };
52
53
 
@@ -100,7 +101,8 @@ export function mountAgentAvatar3DThumbnail(
100
101
  container: HTMLElement,
101
102
  options: AgentAvatar3DThumbnailMountOptions,
102
103
  ): AgentAvatar3DThumbnailController {
103
- const thumbnail = renderAgentAvatar3DThumbnail(options);
104
+ const renderer = createAgentAvatar3DThumbnailRenderer(options);
105
+ let thumbnail = renderer.render(options);
104
106
  const image = options.createImage?.() ?? new Image();
105
107
  image.src = thumbnail.dataUrl;
106
108
  image.width = thumbnail.width;
@@ -109,8 +111,21 @@ export function mountAgentAvatar3DThumbnail(
109
111
 
110
112
  return {
111
113
  image,
112
- thumbnail,
114
+ get thumbnail() {
115
+ return thumbnail;
116
+ },
117
+ update(nextOptions) {
118
+ thumbnail = renderer.render({
119
+ ...options,
120
+ ...nextOptions,
121
+ });
122
+ image.src = thumbnail.dataUrl;
123
+ image.width = thumbnail.width;
124
+ image.height = thumbnail.height;
125
+ return thumbnail;
126
+ },
113
127
  destroy() {
128
+ renderer.destroy();
114
129
  image.remove();
115
130
  },
116
131
  };
@@ -4,6 +4,7 @@ import type { AgentGameOfficeAgent, AgentGameOfficeSceneState } from "../office/
4
4
  import { AgentGameError } from "../core/errors";
5
5
  import {
6
6
  createAgentAvatar3DScene,
7
+ type AgentAvatar3DCameraOptions,
7
8
  type ResolvedAgentAvatar3DState,
8
9
  } from "./three-scene";
9
10
 
@@ -20,6 +21,7 @@ export type AgentAvatar3DViewAngle = "front" | "threeQuarter";
20
21
 
21
22
  export type AgentAvatar3DOptions = {
22
23
  agent?: Partial<AgentGameOfficeAgent>;
24
+ camera?: AgentAvatar3DCameraOptions;
23
25
  agentId?: string;
24
26
  framing?: AgentAvatar3DFraming;
25
27
  sceneState?: AgentGameOfficeSceneState;
@@ -36,7 +38,7 @@ export type AgentAvatar3DOptions = {
36
38
 
37
39
  export type AgentAvatar3DUpdateOptions = Partial<Pick<
38
40
  AgentAvatar3DOptions,
39
- "agent" | "agentId" | "framing" | "sceneState" | "renderIndex" | "viewAngle"
41
+ "agent" | "agentId" | "camera" | "framing" | "sceneState" | "renderIndex" | "viewAngle"
40
42
  >>;
41
43
 
42
44
  export type AgentAvatar3DController = {
@@ -47,7 +49,7 @@ export type AgentAvatar3DController = {
47
49
  getState(): ResolvedAgentAvatar3DState;
48
50
  };
49
51
 
50
- export type { ResolvedAgentAvatar3DState } from "./three-scene";
52
+ export type { AgentAvatar3DCameraOptions, ResolvedAgentAvatar3DState } from "./three-scene";
51
53
 
52
54
  export function mountAgentAvatar3D(
53
55
  container: HTMLElement,
@@ -84,10 +86,12 @@ export function mountAgentAvatar3D(
84
86
  throw new AgentGameError("runtime_destroyed", "Agent avatar 3D view has been destroyed");
85
87
  }
86
88
  const agentIdChanged = nextOptions.agentId !== undefined || nextOptions.agent?.id !== undefined;
89
+ const framingChanged = nextOptions.framing !== undefined && nextOptions.framing !== avatarScene.state.framing;
87
90
  const preserveRenderIndex = hasExplicitRenderIndex && nextOptions.renderIndex === undefined && !agentIdChanged;
88
91
  avatarScene.setState({
89
92
  agent: { ...avatarScene.state, ...nextOptions.agent },
90
93
  agentId: nextOptions.agentId,
94
+ camera: nextOptions.camera ?? (framingChanged ? undefined : avatarScene.state.camera),
91
95
  framing: nextOptions.framing ?? avatarScene.state.framing,
92
96
  sceneState: nextOptions.sceneState ?? avatarScene.state.sceneState,
93
97
  renderIndex: nextOptions.renderIndex,