@runmu.sh/ext-scene 1.1.0 → 1.2.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/CHANGELOG.md +7 -0
- package/README.md +6 -3
- package/dist/index.js +37 -3
- package/package.json +14 -5
- package/src/types.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
- Alt+R (*Go to scene*) is now the extension's own command, `focus.scene`, in Settings → Keys under Scene: Focus. On μClient with extension API 1.14 it focuses the Scene panel when it is open; a rebinding you made keeps working. On an older μClient the client's own Alt+R stays in place.
|
|
6
|
+
- The context menus on exits and room items use the kinds `scene.exit` (`data: { exit }`) and `scene.item` (`data: { item }`), which the extension registers with a schema. On a μClient before API 1.14 it keeps publishing `scene-exit` and `scene-item`.
|
|
7
|
+
- `src/types.ts` types the two kinds for other extensions (`ContextKinds`, `SceneItemData`, `SceneExitData`), and the module exports `ITEM_KIND`, `EXIT_KIND` and `KIND_SCHEMAS`.
|
|
8
|
+
- Built against SDK 1.14. Still needs extension API 1.12 or later.
|
|
9
|
+
|
|
3
10
|
## 1.1.0
|
|
4
11
|
|
|
5
12
|
- Present now comes before Exits, and a room with no exits shows no Exits heading at all, as on Underspire.
|
package/README.md
CHANGED
|
@@ -22,13 +22,13 @@ Package names are case-insensitive. Entering a new room clears Present. The room
|
|
|
22
22
|
## What it looks like
|
|
23
23
|
On `--bg-elev`: the title in uppercase `--accent-bright` with a glow and a `--border-bright` rule under it, the area in small faint capitals, the atmosphere in italic `--fg-dim`, the description, and the pose line in italic with a 2px left rule. Then `┤PRESENT├` over a `▸` list of the people and room items present (a hostile item carries a small `hostile` tag in `--alert`; nobody reads `none`), and, when the room has exits, `┤EXITS├` over a `▸` list. Each exit is a button: clicking it sends the direction as if typed. Before any room arrives the panel says NO ROOM YET (an upright, uppercase, tracked faint label).
|
|
24
24
|
|
|
25
|
-
The panel is the region `scene
|
|
25
|
+
The panel is the region `scene`. **Alt+R** (*Go to scene*, command `focus.scene`) focuses it; rebind it in Settings → Keys. From 1.2.0 the extension registers the command itself (μClient with extension API 1.14); on an older μClient the client's own Alt+R does the same.
|
|
26
26
|
|
|
27
27
|
## Behaviour
|
|
28
28
|
- Panel `scene`, singleton, default position right top, Views order 10 (after Terminal, before Channels).
|
|
29
29
|
- **Show panel: auto** (per world, on the extension's settings page: off / auto / on). On auto the Scene joins Views and adds itself the first time a session knows its room, whatever the room came from (GMCP, MSDP, another extension); once per world on this device, so a Scene you closed stays closed.
|
|
30
30
|
- A redraw in the same room (someone arrives, an item drops) keeps your scroll position; moving to another room scrolls back to the top. When the game sends no room id, every update counts as a move.
|
|
31
|
-
- Right-click (or long-press) an exit or a room item for the menus other extensions add to them (`scene-exit` and `scene-item` targets
|
|
31
|
+
- Right-click (or long-press) an exit or a room item for the menus other extensions add to them. The extension registers the context kinds `scene.exit` (title *Exit*, `data: { exit }`) and `scene.item` (title *Scene item*, `data: { item: { id, name, hostile? } }`), each with a schema the host checks. On a μClient before API 1.14 it publishes the 1.12 kinds `scene-exit` and `scene-item` instead; on 1.14 an entry written for the old kinds still receives the new targets in the old shape.
|
|
32
32
|
- It sends nothing to the game except the exits you click, and reads no GMCP itself: the room adapters fill the scene.
|
|
33
33
|
|
|
34
34
|
## Contract
|
|
@@ -42,9 +42,12 @@ No `ctx.exports` API. The module exports, for tests and other renderers:
|
|
|
42
42
|
| `renderScene(scene, go, opts?)` | The panel's children for one `SceneView` (`null` or `known: false` → NO ROOM YET). `go(dir)` is called on an exit click. `opts.css` passes the host classes (`mu.ui.css`), `opts.target(el, what)` is called for each exit button and present row (to mark context targets). The 1.0 two-argument form still works. |
|
|
43
43
|
| `presentOf(scene)` | People first, then room items, each name once: `{ name, hostile? }[]`. |
|
|
44
44
|
| `COPY`, `SCENE_CSS` | The drawn copy and the stylesheet (every rule under `.ext-panel[data-ext="scene"] .mu-scene`). |
|
|
45
|
+
| `ITEM_KIND`, `EXIT_KIND`, `KIND_SCHEMAS` | `'scene.item'`, `'scene.exit'` and their `data` schemas. |
|
|
46
|
+
|
|
47
|
+
`src/types.ts` augments the SDK's `ContextKinds` with `scene.item` (`SceneItemData`) and `scene.exit` (`SceneExitData`), so an extension that imports it gets `t.data` typed in `mu.menus.context({ target: 'scene.exit', … })`.
|
|
45
48
|
|
|
46
49
|
## SDK
|
|
47
|
-
SDK 1.12: `mu.panels.register` with `show: 'auto'`, `mu.panels.touch`, `mu.sessions.each`, `mu.scene.watch` (and `SceneView.id`), `mu.sessions.send(dir, { sid })`, `mu.menus.target`, `h` and `mu.ui.css`, `mu.ui.style`.
|
|
50
|
+
`api` `^1.12`. SDK 1.12: `mu.panels.register` with `show: 'auto'`, `mu.panels.touch`, `mu.sessions.each`, `mu.scene.watch` (and `SceneView.id`), `mu.sessions.send(dir, { sid })`, `mu.menus.target`, `h` and `mu.ui.css`, `mu.ui.style`. SDK 1.14, used when the host has them: `mu.menus.kind` (with `JsonSchema` and `ContextKinds`), `mu.panels.focus` with `mu.commands.register`. The manifest declares `focus.scene` in `contributes.commands`, so Alt+R is listed and bound before the extension activates.
|
|
48
51
|
|
|
49
52
|
## Develop
|
|
50
53
|
Made with `npm create @runmu.sh/extension` ([the quickstart](https://runmu.sh/docs/extensions/quickstart)).
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { defineExtension, h } from "@muclient/sdk";
|
|
3
|
+
|
|
4
|
+
// src/types.ts
|
|
5
|
+
var ITEM_KIND = "scene.item";
|
|
6
|
+
var EXIT_KIND = "scene.exit";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
3
9
|
var COPY = {
|
|
4
10
|
title: "Scene",
|
|
5
11
|
awaiting: "No room yet",
|
|
@@ -7,7 +13,18 @@ var COPY = {
|
|
|
7
13
|
exits: "Exits",
|
|
8
14
|
none: "none",
|
|
9
15
|
hostile: "hostile",
|
|
10
|
-
go: (dir) => `go ${dir}
|
|
16
|
+
go: (dir) => `go ${dir}`,
|
|
17
|
+
focus: "Go to scene",
|
|
18
|
+
itemKind: "Scene item",
|
|
19
|
+
exitKind: "Exit"
|
|
20
|
+
};
|
|
21
|
+
var KIND_SCHEMAS = {
|
|
22
|
+
[ITEM_KIND]: {
|
|
23
|
+
type: "object",
|
|
24
|
+
required: ["item"],
|
|
25
|
+
properties: { item: { type: "object", required: ["id", "name"], properties: { id: { type: "string" }, name: { type: "string" }, hostile: { type: "boolean" } } } }
|
|
26
|
+
},
|
|
27
|
+
[EXIT_KIND]: { type: "object", required: ["exit"], properties: { exit: { type: "string" } } }
|
|
11
28
|
};
|
|
12
29
|
var R = '.ext-panel[data-ext="scene"] .mu-scene';
|
|
13
30
|
var SCENE_CSS = `
|
|
@@ -85,6 +102,15 @@ var index_default = defineExtension({
|
|
|
85
102
|
const mu = ctx.mu;
|
|
86
103
|
mu.ui.style(SCENE_CSS);
|
|
87
104
|
const css = { secHead: mu.ui.css.secHead, secClose: mu.ui.css.secClose, empty: mu.ui.css.empty, glow: mu.ui.css.glow };
|
|
105
|
+
const kinds = typeof mu.menus.kind === "function";
|
|
106
|
+
if (kinds) {
|
|
107
|
+
ctx.subscriptions.push(
|
|
108
|
+
mu.menus.kind({ id: ITEM_KIND, title: COPY.itemKind, schema: KIND_SCHEMAS[ITEM_KIND] }),
|
|
109
|
+
mu.menus.kind({ id: EXIT_KIND, title: COPY.exitKind, schema: KIND_SCHEMAS[EXIT_KIND] })
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
const exitTarget = (sid, exit) => kinds ? { kind: EXIT_KIND, sid, data: { exit } } : { kind: "scene-exit", sid, exit };
|
|
113
|
+
const itemTarget = (sid, item) => kinds ? { kind: ITEM_KIND, sid, data: { item } } : { kind: "scene-item", sid, item };
|
|
88
114
|
const mount = (host, pc) => {
|
|
89
115
|
const root = h("section", { class: "mu-scene", "aria-label": COPY.title, "data-focus-region": "scene", tabindex: "-1", "data-testid": "scene" });
|
|
90
116
|
host.append(root);
|
|
@@ -103,8 +129,8 @@ var index_default = defineExtension({
|
|
|
103
129
|
targets = [];
|
|
104
130
|
};
|
|
105
131
|
const target = (el, what) => {
|
|
106
|
-
if ("exit" in what) targets.push(mu.menus.target(el,
|
|
107
|
-
else if ("item" in what) targets.push(mu.menus.target(el,
|
|
132
|
+
if ("exit" in what) targets.push(mu.menus.target(el, exitTarget(sid, what.exit)));
|
|
133
|
+
else if ("item" in what) targets.push(mu.menus.target(el, itemTarget(sid, what.item)));
|
|
108
134
|
};
|
|
109
135
|
let room = null;
|
|
110
136
|
const off = mu.scene.watch((s) => {
|
|
@@ -122,6 +148,11 @@ var index_default = defineExtension({
|
|
|
122
148
|
};
|
|
123
149
|
};
|
|
124
150
|
mu.panels.register({ id: "scene", title: COPY.title, singleton: true, defaultPosition: "right-top", order: 10, show: "auto", mount });
|
|
151
|
+
if (typeof mu.panels.focus === "function") {
|
|
152
|
+
mu.commands.register({ id: "focus.scene", title: COPY.focus, keys: ["Alt+R"], group: "Focus", when: "session", run: () => {
|
|
153
|
+
mu.panels.focus?.("scene");
|
|
154
|
+
} });
|
|
155
|
+
}
|
|
125
156
|
ctx.subscriptions.push(mu.sessions.each((s) => {
|
|
126
157
|
let done = false;
|
|
127
158
|
return mu.scene.watch((v) => {
|
|
@@ -135,6 +166,9 @@ var index_default = defineExtension({
|
|
|
135
166
|
});
|
|
136
167
|
export {
|
|
137
168
|
COPY,
|
|
169
|
+
EXIT_KIND,
|
|
170
|
+
ITEM_KIND,
|
|
171
|
+
KIND_SCHEMAS,
|
|
138
172
|
SCENE_CSS,
|
|
139
173
|
index_default as default,
|
|
140
174
|
presentOf,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runmu.sh/ext-scene",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "The Scene panel: the room you are in (title, area, atmosphere, description, pose), who is present and its exits as buttons, from GMCP Room.*, Char.Items.*, MSDP or another extension.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"scene",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"test": "node --test test/*.test.mjs"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@muclient/sdk": "npm:@runmu.sh/sdk@^1.
|
|
39
|
-
"@runmu.sh/dev": "^0.
|
|
38
|
+
"@muclient/sdk": "npm:@runmu.sh/sdk@^1.14.0",
|
|
39
|
+
"@runmu.sh/dev": "^0.3.0",
|
|
40
40
|
"esbuild": "^0.28.2",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"happy-dom": "^20.0.0",
|
|
42
|
+
"typescript": "^5.9.0"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20"
|
|
@@ -63,6 +63,15 @@
|
|
|
63
63
|
"defaultPosition": "right-top",
|
|
64
64
|
"singleton": true
|
|
65
65
|
}
|
|
66
|
+
],
|
|
67
|
+
"commands": [
|
|
68
|
+
{
|
|
69
|
+
"id": "focus.scene",
|
|
70
|
+
"title": "Go to scene",
|
|
71
|
+
"keys": [
|
|
72
|
+
"Alt+R"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
66
75
|
]
|
|
67
76
|
},
|
|
68
77
|
"capabilities": [
|
package/src/types.ts
CHANGED
|
@@ -42,4 +42,30 @@ export interface SceneCopy {
|
|
|
42
42
|
none: string;
|
|
43
43
|
hostile: string;
|
|
44
44
|
go(dir: string): string;
|
|
45
|
+
/** The `focus.scene` command's title. @since 1.2.0 */
|
|
46
|
+
focus: string;
|
|
47
|
+
/** The context kinds' titles (the menu's accessible label). @since 1.2.0 */
|
|
48
|
+
itemKind: string;
|
|
49
|
+
exitKind: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The context kind of a room item in ┤PRESENT├ (SDK 1.14). @since 1.2.0 */
|
|
53
|
+
export const ITEM_KIND = 'scene.item';
|
|
54
|
+
/** The context kind of an exit button (SDK 1.14). @since 1.2.0 */
|
|
55
|
+
export const EXIT_KIND = 'scene.exit';
|
|
56
|
+
|
|
57
|
+
/** `data` of a `scene.item` target. @since 1.2.0 */
|
|
58
|
+
export interface SceneItemData { item: SceneView['items'][number] }
|
|
59
|
+
/** `data` of a `scene.exit` target. @since 1.2.0 */
|
|
60
|
+
export interface SceneExitData { exit: string }
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Types `t.data` in another extension's `mu.menus.context({ target: 'scene.item' | 'scene.exit', … })` once it
|
|
64
|
+
* imports this file. @since 1.2.0
|
|
65
|
+
*/
|
|
66
|
+
declare module '@muclient/sdk' {
|
|
67
|
+
interface ContextKinds {
|
|
68
|
+
'scene.item': SceneItemData;
|
|
69
|
+
'scene.exit': SceneExitData;
|
|
70
|
+
}
|
|
45
71
|
}
|