@iniesta8888/agent-live-pi-adapter 0.3.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/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/adapter.js +2375 -0
- package/package.json +23 -0
- package/web/app.d.ts +1 -0
- package/web/app.js +1317 -0
- package/web/index.html +45 -0
- package/web/office.js +350 -0
- package/web/sprites.js +185 -0
- package/web/style.css +288 -0
- package/web/v2/bootstrap.js +276 -0
- package/web/v2/content/README.md +17 -0
- package/web/v2/content/agent-skins/studio-team.json +33 -0
- package/web/v2/content/agent-skins/tiny-developers.json +33 -0
- package/web/v2/content/atmospheres/default.json +13 -0
- package/web/v2/content/atmospheres/rainy-night.json +37 -0
- package/web/v2/content/catalog.json +14 -0
- package/web/v2/content/component-library/activity-implementations.json +873 -0
- package/web/v2/content/component-library/activity-recipes.json +25 -0
- package/web/v2/content/component-library/agent-profile-templates.json +18 -0
- package/web/v2/content/component-library/catalog.json +38 -0
- package/web/v2/content/component-library/npc-templates.json +42 -0
- package/web/v2/content/component-library/props.json +41 -0
- package/web/v2/content/environments/local-office.json +31 -0
- package/web/v2/content/environments/rainy-night.json +28 -0
- package/web/v2/content/environments/static-office.json +27 -0
- package/web/v2/content/layouts/boardroom-office.json +122 -0
- package/web/v2/content/layouts/demo-office.json +88 -0
- package/web/v2/content/layouts/lively-office.json +96 -0
- package/web/v2/content/layouts/old-school-office.json +154 -0
- package/web/v2/content/layouts/tech-open-office.json +132 -0
- package/web/v2/content/life-activities/boardroom-routines.json +67 -0
- package/web/v2/content/life-activities/none.json +10 -0
- package/web/v2/content/life-activities/office-basics.json +39 -0
- package/web/v2/content/life-activities/old-school-routines.json +74 -0
- package/web/v2/content/life-activities/tech-office-routines.json +148 -0
- package/web/v2/content/npcs/boardroom-staff.json +54 -0
- package/web/v2/content/npcs/none.json +10 -0
- package/web/v2/content/npcs/office-staff.json +25 -0
- package/web/v2/content/npcs/old-school-staff.json +39 -0
- package/web/v2/content/npcs/tech-office-staff.json +40 -0
- package/web/v2/content/official-offices/boardroom-office.json +25 -0
- package/web/v2/content/official-offices/old-school-office.json +25 -0
- package/web/v2/content/official-offices/tech-open-office.json +25 -0
- package/web/v2/content/presets/boardroom-office.json +21 -0
- package/web/v2/content/presets/cozy-studio.json +19 -0
- package/web/v2/content/presets/demo-office.json +19 -0
- package/web/v2/content/presets/lively-office.json +19 -0
- package/web/v2/content/presets/night-shift.json +19 -0
- package/web/v2/content/presets/old-school-office.json +20 -0
- package/web/v2/content/presets/refined-demo.json +20 -0
- package/web/v2/content/presets/tech-open-office.json +21 -0
- package/web/v2/content/props/default-office.json +23 -0
- package/web/v2/content/props/extended-office.json +39 -0
- package/web/v2/content/props/tech-office.json +28 -0
- package/web/v2/content/styles/pixel-classic.json +160 -0
- package/web/v2/content/styles/warm-studio.json +150 -0
- package/web/v2/environment-runtime.d.ts +1 -0
- package/web/v2/environment-runtime.js +138 -0
- package/web/v2/graph-validator.d.ts +55 -0
- package/web/v2/graph-validator.js +225 -0
- package/web/v2/i18n.js +54 -0
- package/web/v2/locales/en.json +209 -0
- package/web/v2/locales/zh-CN.json +52 -0
- package/web/v2/office-engine.d.ts +1 -0
- package/web/v2/office-engine.js +145 -0
- package/web/v2/office-renderer.d.ts +1 -0
- package/web/v2/office-renderer.js +843 -0
- package/web/v2/parity.html +10 -0
- package/web/v2/parity.js +82 -0
- package/web/v2/sprite-renderer.d.ts +1 -0
- package/web/v2/sprite-renderer.js +242 -0
- package/web/v2/static-content.js +48 -0
- package/web/v2/style.css +140 -0
- package/web/v2.html +68 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral office world model.
|
|
3
|
+
*
|
|
4
|
+
* Owns spatial navigation, work-station selection and environment queries.
|
|
5
|
+
* It contains no DOM or Canvas operations; renderers consume this API.
|
|
6
|
+
*/
|
|
7
|
+
export function createOfficeEngine(content, environment = null) {
|
|
8
|
+
const layout = content.layout;
|
|
9
|
+
const ambientEffects = new Set(content.atmosphere.ambientEffects ?? []);
|
|
10
|
+
const targets = Object.fromEntries(Object.entries(layout.targets).map(([key, value]) => [key, { ...value }]));
|
|
11
|
+
const seats = layout.seats.map((seat) => ({
|
|
12
|
+
index: seat.index,
|
|
13
|
+
cx: seat.cx,
|
|
14
|
+
renderer: seat.renderer ?? "workstation",
|
|
15
|
+
deskX: seat.desk.x,
|
|
16
|
+
deskY: seat.desk.y,
|
|
17
|
+
deskW: seat.desk.width,
|
|
18
|
+
deskH: seat.desk.height,
|
|
19
|
+
anchor: { ...seat.anchor },
|
|
20
|
+
}));
|
|
21
|
+
const lanes = [...layout.navigation.lanes];
|
|
22
|
+
const connectors = [...layout.navigation.connectors];
|
|
23
|
+
const perimeter = layout.navigation.perimeter ?? null;
|
|
24
|
+
|
|
25
|
+
function currentEnvironment() {
|
|
26
|
+
if (environment?.snapshot) return environment.snapshot();
|
|
27
|
+
const now = new Date();
|
|
28
|
+
const hour = now.getHours();
|
|
29
|
+
const phase = hour >= 6 && hour < 11 ? "morning" : hour >= 11 && hour < 17 ? "noon" : hour >= 17 && hour < 20 ? "evening" : "night";
|
|
30
|
+
return { now, hour, minute: now.getMinutes(), phase, weather: ambientEffects.has("rain-window") ? "rain" : "clear", dynamicTime: false, dynamicWeather: ambientEffects.size > 0, lightingOn: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function seatAnchor(index) {
|
|
34
|
+
return seats[(index ?? 0) % seats.length].anchor;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function standingAnchor(key = 0) {
|
|
38
|
+
const slots = layout.standingAnchors;
|
|
39
|
+
if (!Array.isArray(slots) || slots.length === 0) return targets.entry;
|
|
40
|
+
return slots[Math.abs(Number(key) || 0) % slots.length];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function npcHomeTarget(entry, roleIndex = 0) {
|
|
44
|
+
// Seat 0 belongs to the real Agent. Ordinary colleagues occupy the
|
|
45
|
+
// remaining desks; their configured spawn remains only their entrance or
|
|
46
|
+
// role fallback, not the place they return to after every activity.
|
|
47
|
+
if (entry?.role === "colleague" && seats.length > 1) {
|
|
48
|
+
return seatAnchor(1 + Math.max(0, roleIndex) % (seats.length - 1));
|
|
49
|
+
}
|
|
50
|
+
return targets[entry?.spawn] ?? targets.entry;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function anchorFor(action, seatIndex, fallbackKey = 0) {
|
|
54
|
+
const capability = layout.legacyActions[action ?? "type"] ?? "create";
|
|
55
|
+
const station = layout.stations[capability];
|
|
56
|
+
if (!station || station.kind === "seat") return seatIndex == null ? standingAnchor(fallbackKey) : seatAnchor(seatIndex);
|
|
57
|
+
return targets[station.target] ?? (seatIndex == null ? standingAnchor(fallbackKey) : seatAnchor(seatIndex));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function perimeterPath(from, target) {
|
|
61
|
+
const { leftX, rightX, topY, bottomY } = perimeter;
|
|
62
|
+
const zoneFor = (point) => point.zone ?? [
|
|
63
|
+
["left", Math.abs(point.x - leftX)], ["right", Math.abs(point.x - rightX)],
|
|
64
|
+
["top", Math.abs(point.y - topY)], ["bottom", Math.abs(point.y - bottomY)],
|
|
65
|
+
].reduce((best, item) => item[1] < best[1] ? item : best)[0];
|
|
66
|
+
const portalFor = (point, zone) => {
|
|
67
|
+
if (zone === "left") return { x: leftX, y: point.y, zone };
|
|
68
|
+
if (zone === "right") return { x: rightX, y: point.y, zone };
|
|
69
|
+
if (zone === "bottom") return { x: point.x, y: bottomY, zone };
|
|
70
|
+
return { x: point.x, y: topY, zone: "top" };
|
|
71
|
+
};
|
|
72
|
+
const fromZone = zoneFor(from);
|
|
73
|
+
const toZone = zoneFor(target);
|
|
74
|
+
const start = portalFor(from, fromZone);
|
|
75
|
+
const end = portalFor(target, toZone);
|
|
76
|
+
const nodes = [
|
|
77
|
+
start,
|
|
78
|
+
end,
|
|
79
|
+
{ x: leftX, y: topY, zone: "top" },
|
|
80
|
+
{ x: rightX, y: topY, zone: "top" },
|
|
81
|
+
{ x: rightX, y: bottomY, zone: "bottom" },
|
|
82
|
+
{ x: leftX, y: bottomY, zone: "bottom" },
|
|
83
|
+
];
|
|
84
|
+
const connected = (a, b) => (a.x === b.x && (a.x === leftX || a.x === rightX)) || (a.y === b.y && (a.y === topY || a.y === bottomY));
|
|
85
|
+
const distance = nodes.map(() => Infinity);
|
|
86
|
+
const previous = nodes.map(() => -1);
|
|
87
|
+
const visited = new Set();
|
|
88
|
+
distance[0] = 0;
|
|
89
|
+
while (visited.size < nodes.length) {
|
|
90
|
+
let current = -1;
|
|
91
|
+
for (let index = 0; index < nodes.length; index += 1) if (!visited.has(index) && (current < 0 || distance[index] < distance[current])) current = index;
|
|
92
|
+
if (current < 0 || distance[current] === Infinity) break;
|
|
93
|
+
visited.add(current);
|
|
94
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
95
|
+
if (visited.has(index) || !connected(nodes[current], nodes[index])) continue;
|
|
96
|
+
const candidate = distance[current] + Math.abs(nodes[current].x - nodes[index].x) + Math.abs(nodes[current].y - nodes[index].y);
|
|
97
|
+
if (candidate < distance[index]) { distance[index] = candidate; previous[index] = current; }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const route = [];
|
|
101
|
+
for (let index = 1; index >= 0; index = previous[index]) route.unshift(nodes[index]);
|
|
102
|
+
const points = [];
|
|
103
|
+
const push = (point) => {
|
|
104
|
+
const last = points.at(-1);
|
|
105
|
+
if (!last || last.x !== point.x || last.y !== point.y) points.push(point);
|
|
106
|
+
};
|
|
107
|
+
push(start);
|
|
108
|
+
for (const point of route.slice(1)) push(point);
|
|
109
|
+
push({ ...target, zone: toZone });
|
|
110
|
+
return points;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function path(from, target) {
|
|
114
|
+
if (Math.abs(from.x - target.x) < 0.5 && Math.abs(from.y - target.y) < 0.5) return [];
|
|
115
|
+
if (perimeter) return perimeterPath(from, target);
|
|
116
|
+
const fromLane = from.lane ?? 1;
|
|
117
|
+
const toLane = target.lane ?? 1;
|
|
118
|
+
const points = [];
|
|
119
|
+
const laneY = lanes[fromLane];
|
|
120
|
+
if (Math.abs(from.y - laneY) > 0.5) points.push({ x: from.x, y: laneY });
|
|
121
|
+
if (fromLane !== toLane) {
|
|
122
|
+
const x = connectors.reduce((best, candidate) => Math.abs(candidate - from.x) + Math.abs(candidate - target.x) < Math.abs(best - from.x) + Math.abs(best - target.x) ? candidate : best);
|
|
123
|
+
points.push({ x, y: laneY }, { x, y: lanes[toLane] });
|
|
124
|
+
}
|
|
125
|
+
points.push({ x: target.x, y: lanes[toLane] }, { x: target.x, y: target.y });
|
|
126
|
+
return points;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function stationKey(action, seatIndex) {
|
|
130
|
+
const capability = layout.legacyActions[action ?? "type"] ?? "create";
|
|
131
|
+
const station = layout.stations[capability];
|
|
132
|
+
return !station || station.kind === "seat" ? `desk${seatIndex ?? 0}` : station.target;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
W: layout.canvas.width, H: layout.canvas.height, WALL_H: layout.wallHeight,
|
|
137
|
+
LANES: lanes, SEATS: seats, TARGETS: targets, AMBIENT_EFFECTS: ambientEffects,
|
|
138
|
+
interactions: Object.freeze({ ...(layout.interactions ?? {}) }),
|
|
139
|
+
currentEnvironment, anchorFor, seatAnchor, standingAnchor, npcHomeTarget, path, stationKey,
|
|
140
|
+
startDayPreview: (durationMs = 24000) => environment?.startPreview?.(durationMs) ?? false,
|
|
141
|
+
getOfficeTime: currentEnvironment,
|
|
142
|
+
isNpcOnDuty: (role, shift, identity) => environment?.isNpcOnDuty?.(role, shift, identity) ?? true,
|
|
143
|
+
npcShiftLabel: (kind) => environment?.shiftLabel?.(kind) ?? (kind === "arrival" ? "上班啦" : "下班啦"),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function createOfficeRenderer(content: unknown, environmentRuntime: unknown): unknown;
|