@blkc-code/render-canvas 0.6.0 → 0.7.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/dist/draw.d.ts.map +1 -1
- package/dist/draw.js +9 -1
- package/dist/draw.js.map +1 -1
- package/dist/office.d.ts.map +1 -1
- package/dist/office.js +5 -3
- package/dist/office.js.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.txt +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/world.d.ts +3 -2
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +14 -8
- package/dist/world.js.map +1 -1
- package/dist/worlds/office-data.d.ts.map +1 -1
- package/dist/worlds/office-data.js +1 -0
- package/dist/worlds/office-data.js.map +1 -1
- package/dist/worlds/office-paint.d.ts.map +1 -1
- package/dist/worlds/office-paint.js +8 -0
- package/dist/worlds/office-paint.js.map +1 -1
- package/package.json +1 -1
- package/src/draw.ts +8 -1
- package/src/office.ts +5 -3
- package/src/types.ts +1 -1
- package/src/world.ts +15 -9
- package/src/worlds/office-data.ts +1 -0
- package/src/worlds/office-paint.ts +8 -0
package/package.json
CHANGED
package/src/draw.ts
CHANGED
|
@@ -351,6 +351,13 @@ function drawWalls(c: Ctx, world: World, palette: Palette, daylight: Daylight):
|
|
|
351
351
|
function drawLabels(c: Ctx, world: World): void {
|
|
352
352
|
c.font = LABEL_FONT;
|
|
353
353
|
c.textBaseline = "top";
|
|
354
|
+
for (const item of world.furniture) {
|
|
355
|
+
if (!item.label) continue;
|
|
356
|
+
const width = Math.ceil(c.measureText(item.label).width) + 4;
|
|
357
|
+
rect(c, "#f4ecd8", item.x * TILE + 17, item.y * TILE + 3, width, 10);
|
|
358
|
+
c.fillStyle = "#1c1408";
|
|
359
|
+
c.fillText(item.label, item.x * TILE + 19, item.y * TILE + 4.5);
|
|
360
|
+
}
|
|
354
361
|
for (const room of world.rooms) {
|
|
355
362
|
if (!room.name) continue;
|
|
356
363
|
const label = room.name.toUpperCase();
|
|
@@ -369,7 +376,7 @@ export function drawBuilding(c: Ctx, world: World, palette: Palette, daylight: D
|
|
|
369
376
|
rect(c, WALL_TOP, 0, 0, world.cols * TILE, world.rows * TILE);
|
|
370
377
|
for (const room of world.rooms) drawFloor(c, room);
|
|
371
378
|
drawWalls(c, world, palette, daylight);
|
|
372
|
-
for (const item of world.furniture) if (item.type === "rug") painterFor(world).furniture(c, item, world, 0, palette);
|
|
379
|
+
for (const item of world.furniture) if (item.type === "rug" || item.type === "pile") painterFor(world).furniture(c, item, world, 0, palette);
|
|
373
380
|
for (const item of world.furniture) if (specOf(world, item).wall) painterFor(world).furniture(c, item, world, 0, palette);
|
|
374
381
|
// Light from the windows falling across the floor.
|
|
375
382
|
if (daylight.sun !== "rgba(0,0,0,0)") {
|
package/src/office.ts
CHANGED
|
@@ -76,8 +76,10 @@ export function createOffice(canvas: HTMLCanvasElement, scene: OfficeScene = {},
|
|
|
76
76
|
const width = (): number => world.cols * TILE;
|
|
77
77
|
const height = (): number => world.rows * TILE;
|
|
78
78
|
|
|
79
|
+
// A big map starts small on screen, so it can be zoomed further: as far as 4x true size.
|
|
80
|
+
const zoomLimit = (): number => Math.max(MAX_ZOOM, scale > 0 ? 4 / scale : MAX_ZOOM);
|
|
79
81
|
const clampView = (): void => {
|
|
80
|
-
view.zoom = Math.min(
|
|
82
|
+
view.zoom = Math.min(zoomLimit(), Math.max(1, view.zoom));
|
|
81
83
|
view.x = Math.min(width() - width() / view.zoom, Math.max(0, view.x));
|
|
82
84
|
view.y = Math.min(height() - height() / view.zoom, Math.max(0, view.y));
|
|
83
85
|
};
|
|
@@ -192,7 +194,7 @@ export function createOffice(canvas: HTMLCanvasElement, scene: OfficeScene = {},
|
|
|
192
194
|
return;
|
|
193
195
|
}
|
|
194
196
|
const before = event ? tileAt(event) : { x: view.x / TILE + width() / view.zoom / TILE / 2, y: view.y / TILE + height() / view.zoom / TILE / 2 };
|
|
195
|
-
view.zoom = Math.min(
|
|
197
|
+
view.zoom = Math.min(zoomLimit(), Math.max(1, view.zoom * factor));
|
|
196
198
|
if (event) {
|
|
197
199
|
const after = tileAt(event);
|
|
198
200
|
view.x += (before.x - after.x) * TILE;
|
|
@@ -233,7 +235,7 @@ export function createOffice(canvas: HTMLCanvasElement, scene: OfficeScene = {},
|
|
|
233
235
|
setLayout(layout) {
|
|
234
236
|
applyLayout(world, layout);
|
|
235
237
|
buildingDirty = true;
|
|
236
|
-
view.zoom = Math.min(view.zoom,
|
|
238
|
+
view.zoom = Math.min(view.zoom, zoomLimit());
|
|
237
239
|
clampView();
|
|
238
240
|
scale = 0;
|
|
239
241
|
resize();
|
package/src/types.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface OfficeRoom {
|
|
|
22
22
|
paths?: string[];
|
|
23
23
|
}
|
|
24
24
|
export interface OfficeDoor { x: number; y: number }
|
|
25
|
-
export interface OfficeFurniture { type: FurnitureType; x: number; y: number }
|
|
25
|
+
export interface OfficeFurniture { type: FurnitureType; x: number; y: number; label?: string }
|
|
26
26
|
export interface OfficeAgent {
|
|
27
27
|
id: string;
|
|
28
28
|
name?: string;
|
package/src/world.ts
CHANGED
|
@@ -8,10 +8,13 @@ import { OFFICE, OFFICE_ITEMS, OFFICE_LAYOUT } from "./worlds/office-data.js";
|
|
|
8
8
|
import type { LinkRoute } from "./links.js";
|
|
9
9
|
import type { AgentState, FloorStyle, FurnitureType, OfficeAgent, OfficeDoor, OfficeFurniture, OfficeLayout, OfficeRoom, OfficeScene, OfficeTask, TaskState } from "./types.js";
|
|
10
10
|
|
|
11
|
-
export const MAX_COLS =
|
|
12
|
-
export const MAX_ROWS =
|
|
11
|
+
export const MAX_COLS = 1024;
|
|
12
|
+
export const MAX_ROWS = 1024;
|
|
13
13
|
const MAX_AGENTS = 40;
|
|
14
|
-
const MAX_FURNITURE =
|
|
14
|
+
const MAX_FURNITURE = 60000;
|
|
15
|
+
const MAX_ROOMS = 8000;
|
|
16
|
+
const MAX_DOORS = 16000;
|
|
17
|
+
const MAX_LINKS = 4000;
|
|
15
18
|
const MAX_TASKS = 60;
|
|
16
19
|
export const WALK_SPEED = 4.5; // tiles a second
|
|
17
20
|
|
|
@@ -29,7 +32,7 @@ const str = (value: unknown, max = 120): string => (typeof value === "string" ?
|
|
|
29
32
|
const list = <T>(value: unknown, max: number): T[] => (Array.isArray(value) ? (value.slice(0, max) as T[]) : []);
|
|
30
33
|
|
|
31
34
|
export interface Room { id: string; name: string; x: number; y: number; w: number; h: number; floor: FloorStyle; paths: string[] }
|
|
32
|
-
export interface Item { type: FurnitureType; x: number; y: number }
|
|
35
|
+
export interface Item { type: FurnitureType; x: number; y: number; label?: string }
|
|
33
36
|
export interface Task { title: string; state: TaskState; agent: string }
|
|
34
37
|
|
|
35
38
|
export interface Agent {
|
|
@@ -165,8 +168,8 @@ function buildLayout(scene: OfficeLayout, pack: WorldData): Pick<World, "links"
|
|
|
165
168
|
const custom = Array.isArray(scene?.rooms) && scene.rooms.length > 0;
|
|
166
169
|
const cols = Math.min(Math.max(int(scene?.cols, custom ? 20 : pack.layout.cols), 6), MAX_COLS);
|
|
167
170
|
const rows = Math.min(Math.max(int(scene?.rows, custom ? 14 : pack.layout.rows), 6), MAX_ROWS);
|
|
168
|
-
const rawRooms = custom ? list<OfficeRoom>(scene.rooms,
|
|
169
|
-
const rawDoors = custom ? list<OfficeDoor>(scene.doors,
|
|
171
|
+
const rawRooms = custom ? list<OfficeRoom>(scene.rooms, MAX_ROOMS) : pack.layout.rooms;
|
|
172
|
+
const rawDoors = custom ? list<OfficeDoor>(scene.doors, MAX_DOORS) : pack.layout.doors;
|
|
170
173
|
const rawItems = Array.isArray(scene?.furniture) ? list<OfficeFurniture>(scene.furniture, MAX_FURNITURE) : custom ? [] : pack.layout.furniture;
|
|
171
174
|
|
|
172
175
|
// Clamped to the grid: everything later loops over these, so a huge room must not hang the page.
|
|
@@ -175,7 +178,7 @@ function buildLayout(scene: OfficeLayout, pack: WorldData): Pick<World, "links"
|
|
|
175
178
|
const y = Math.min(Math.max(int(room?.y, 0), 0), rows);
|
|
176
179
|
return {
|
|
177
180
|
id: str(room?.id, 60) || `room-${index + 1}`,
|
|
178
|
-
name: str(room?.name,
|
|
181
|
+
name: str(room?.name, 60),
|
|
179
182
|
x, y,
|
|
180
183
|
w: Math.min(Math.max(int(room?.w, 0), 0), cols - x),
|
|
181
184
|
h: Math.min(Math.max(int(room?.h, 0), 0), rows - y),
|
|
@@ -195,7 +198,10 @@ function buildLayout(scene: OfficeLayout, pack: WorldData): Pick<World, "links"
|
|
|
195
198
|
|
|
196
199
|
const furniture: Item[] = rawItems
|
|
197
200
|
.filter((item) => item && Object.hasOwn(pack.items, item.type))
|
|
198
|
-
.map((item) =>
|
|
201
|
+
.map((item) => {
|
|
202
|
+
const label = str(item.label, 40);
|
|
203
|
+
return { type: item.type, x: int(item.x, -99), y: int(item.y, -99), ...(label ? { label } : {}) };
|
|
204
|
+
});
|
|
199
205
|
for (const item of furniture) {
|
|
200
206
|
const spec = pack.items[item.type] as ItemSpec;
|
|
201
207
|
if (spec.solid === false) continue;
|
|
@@ -218,7 +224,7 @@ function buildLayout(scene: OfficeLayout, pack: WorldData): Pick<World, "links"
|
|
|
218
224
|
if (use === "lounge") spots.lounge.push(point);
|
|
219
225
|
if (use === "board") spots.board.push(point);
|
|
220
226
|
}
|
|
221
|
-
const links = list<{ from: string; to: string }>(scene?.links,
|
|
227
|
+
const links = list<{ from: string; to: string }>(scene?.links, MAX_LINKS)
|
|
222
228
|
.map((link) => ({ from: str(link?.from, 60), to: str(link?.to, 60) }))
|
|
223
229
|
.filter((link) => link.from && link.to);
|
|
224
230
|
return { cols, rows, rooms, doors, furniture, walkable, seats, spots, links };
|
|
@@ -17,6 +17,7 @@ export const OFFICE_ITEMS: WorldData["items"] = {
|
|
|
17
17
|
server: { w: 1, h: 1 },
|
|
18
18
|
table: { w: 3, h: 2, spot: { x: 1, y: 2 }, use: "board" },
|
|
19
19
|
rug: { w: 4, h: 3, solid: false },
|
|
20
|
+
pile: { w: 1, h: 1, solid: false },
|
|
20
21
|
arcade: { w: 1, h: 1, spot: { x: 0, y: 1 }, use: "lounge" },
|
|
21
22
|
fridge: { w: 1, h: 1, spot: { x: 0, y: 1 }, use: "lounge" },
|
|
22
23
|
printer: { w: 1, h: 1, spot: { x: 0, y: 1 } },
|
|
@@ -167,6 +167,14 @@ function drawFurniture(c: Ctx, item: Item, world: World, time: number, palette:
|
|
|
167
167
|
rect(c, "#1f2937", x + 12, y + 8, 4, 1);
|
|
168
168
|
rect(c, "#3b82f6", x + 30, y + 10, 4, 1);
|
|
169
169
|
break;
|
|
170
|
+
case "pile":
|
|
171
|
+
// A stack of boxes, for a group of loose files.
|
|
172
|
+
rect(c, "#14141f", x + 1, y + 5, 14, 10);
|
|
173
|
+
rect(c, "#b98b55", x + 2, y + 6, 12, 8);
|
|
174
|
+
rect(c, "#d3a874", x + 2, y + 6, 12, 2);
|
|
175
|
+
rect(c, "#14141f", x + 4, y + 1, 8, 5);
|
|
176
|
+
rect(c, "#d3a874", x + 5, y + 2, 6, 3);
|
|
177
|
+
break;
|
|
170
178
|
case "rug":
|
|
171
179
|
rect(c, palette.primary, x, y, 64, 48);
|
|
172
180
|
c.fillStyle = "rgba(0,0,0,0.42)";
|