cortico-world-map 0.0.0-stage → 0.1.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 +109 -0
- package/PUBLISHING.md +82 -0
- package/README.md +204 -2
- package/assets/icon.png +0 -0
- package/describe.json +226 -0
- package/dist/webui.js +902 -0
- package/package.json +68 -4
- package/src/ENV_PROMPT.md +31 -0
- package/src/config.js +186 -0
- package/src/definition.js +76 -0
- package/src/index.js +25 -0
- package/src/places.js +303 -0
- package/src/state.js +322 -0
- package/src/world.js +1174 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
市场按 `##` 标题里的版本号切段,显示在「历史版本」里。
|
|
4
|
+
|
|
5
|
+
## 0.1.0
|
|
6
|
+
|
|
7
|
+
**第一个版本。给 Coo 一张「周围的地图」:家在哪、常去哪儿、附近有什么、去远处旅行可以是什么样。**
|
|
8
|
+
|
|
9
|
+
显示名 **「鱼的小世界」**(英文 `Little World`)。改名要同时动三处:`src/config.js` 的 `LABEL`、`package.json` 的 `cortico.displayName` + `locales`、`dist/webui.js` 里 `T.*.title`——`tools/check-name.mjs` 会把不一致当场抓出来。
|
|
10
|
+
|
|
11
|
+
每处地方只有文字——空间、陈设、配色、光线、氛围——外加一句固定的画风锚点,所以同一个地方反复看、反复画都是同一副样子。画面可以**完全靠主人自己上传一张本地图**,装不装别的插件都能用。
|
|
12
|
+
|
|
13
|
+
### 刻意没有的:路线、坐标、距离、导航
|
|
14
|
+
|
|
15
|
+
一处地方就是「它长什么样」,不是「怎么走到它」。日程里写去哪是「鱼的每一天」的事,这里只提供「那个地方是什么样子」——所以「森林里的鱼出去上班」这种割裂从根上不会发生。
|
|
16
|
+
|
|
17
|
+
这条不是「先不做」而是需求红线:`place` 的字段就是 `id / name / aliases / kind / desc / style / cover / scene / funVenue / frequent / terrain` 十一个,没有任何 geo 字段;`normalizePlace` / `normalizeState` 会主动**丢掉**混进来的 `lat` / `lng` / `route` / `distance` / `geo`。
|
|
18
|
+
|
|
19
|
+
三道守门断言钉住它:
|
|
20
|
+
|
|
21
|
+
- `test/places.test.mjs`:place 不含任何 geo 字段(变体表三十多个名字);地形文案里不出现「路线 / 导航 / 坐标 / 公里 / 左转 / 车程」;
|
|
22
|
+
- `tools/check-isolation.mjs`:源代码里不出现 `lat:` / `route:` / `distance:` 这类字段;
|
|
23
|
+
- `test/world.test.mjs`:六个工具的回执里都不出现路线字眼;旅游那套另有一条「不许出现几天 / 行程 / 怎么去」。
|
|
24
|
+
|
|
25
|
+
### 开箱:五套预设地形
|
|
26
|
+
|
|
27
|
+
选一套 → **勾选表**挑要哪几处(默认全选、已有的置灰不可勾、全不选时「加进去」置灰)→ 只加勾上的那几处:
|
|
28
|
+
|
|
29
|
+
| 地形 | 预置地点 |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| 林间 | 家(树洞/小木屋)、老橡树、溪边、蘑菇坡、林间空地 |
|
|
32
|
+
| 小区 | 家、楼下长椅、便利店门口、小花园、单元楼道 |
|
|
33
|
+
| 江边 | 家、江堤台阶、旧码头、芦苇滩、江边石墩 |
|
|
34
|
+
| 山脚 | 家、上山口、山泉、半坡亭、碎石坡 |
|
|
35
|
+
| 旅行 | 海边小镇、雪山客栈、古城老街、温泉旅馆、林间营地 |
|
|
36
|
+
|
|
37
|
+
**换地形只追加,不删已有地点**(id 带地形前缀,`forest-home` / `riverside-home` 不撞)。所以「林间」写好的描写,切到「江边」之后还在。已经有的那几处不会被覆盖(可能是主人重命名过的)。
|
|
38
|
+
|
|
39
|
+
骨架的 `style` / `scene` / `cover` 全是空的——骨架不知道主人喜欢什么画风、也不知道他库里有什么场景,猜一个就是错。
|
|
40
|
+
|
|
41
|
+
### 两种画面来源
|
|
42
|
+
|
|
43
|
+
**A · 本地图片(主人上传),可完全独立。** 面板里每处「传一张图」,落 `<数据目录>/map/covers/<id>.<ext>`,面板走 `ctx.invoke('cover', {id})` 拿 **base64 data URL** 显示。只认 png / jpg / webp / gif,上限 8 MiB,**按文件头魔数校验、不信扩展名**,扩展名也按魔数定。
|
|
44
|
+
|
|
45
|
+
**B · 生图工作室联动,可选。** 「发图时 scene 填 X」那句**只在三条全满足时出现**:`mapImggenOn` 开着 + `worlds.imggen.enabled === true` + 这一处 `scene` 非空。缺任意一条,那句话**整段不出现**,回执里连 `imggen_draw` / `scene` 这个词都没有。
|
|
46
|
+
|
|
47
|
+
### 三个联动,同一条规矩
|
|
48
|
+
|
|
49
|
+
| 联动 | 开关 | 还要读到 | 还要 |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| 生图工作室 | `mapImggenOn` | `worlds.imggen.enabled` | 该处 `scene` 非空 |
|
|
52
|
+
| 鱼的每一天 | `mapFeastOn` | `worlds.feast.enabled` | 有地点 |
|
|
53
|
+
| 娱乐时间 | `mapFunOn` | `worlds.fun.enabled` | 该处 `funVenue` 非空 |
|
|
54
|
+
|
|
55
|
+
只读 `config.json` 的布尔字段——不调对方的工具、不读对方的状态或素材库。三个 8 组真值表钉死(只有全真才提)。
|
|
56
|
+
|
|
57
|
+
### 旅游:只说那儿长什么样,另给一个「最接近的去处」
|
|
58
|
+
|
|
59
|
+
远方地名在娱乐时间的场所库里**不存在**,直接让她 `fun_go` 填「海边小镇」,那边会回「没听说过这处」——正是红线禁的「指向不存在的东西」。所以每处预置**最接近的一处**,回执明说不是同一个地方:
|
|
60
|
+
|
|
61
|
+
| 地点 | 娱乐时间里最接近的 |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| 海边小镇 | 江边 |
|
|
64
|
+
| 雪山客栈 | 爬山 |
|
|
65
|
+
| 古城老街 | 旧货市场 |
|
|
66
|
+
| 温泉旅馆 | 澡堂 |
|
|
67
|
+
| 林间营地 | 公园 |
|
|
68
|
+
|
|
69
|
+
> 这一趟想真去逛逛:`fun_go` 的 `place` 填「江边」——那是娱乐时间里**最接近这处**的一处。
|
|
70
|
+
> (不是同一个地方:别把「江边」说成「海边小镇」。)
|
|
71
|
+
|
|
72
|
+
旅游那套**不带行程**:没有几天、没有怎么去、没有第几天。
|
|
73
|
+
|
|
74
|
+
### 画风固定 = 每处一句 style + 有图就锁死
|
|
75
|
+
|
|
76
|
+
1. 每处一句 `style`,出图提示词里固定带上。
|
|
77
|
+
2. **一旦有 `cover` 就锁死,不自动重生**:改文字改不到图(有测试钉住),也没有任何「重画」函数;要换只能主人手动清空再传。
|
|
78
|
+
3. `mapStyleRef`(整图样式参考)这一版**只留字段不实现**。
|
|
79
|
+
|
|
80
|
+
### 六个工具、零事件
|
|
81
|
+
|
|
82
|
+
`map_places` / `map_look` / `map_add` / `map_edit` / `map_cover` / `map_view`。
|
|
83
|
+
|
|
84
|
+
`describe.events` 是**空数组**、`start()` 里没有定时器:什么时候看地图,由「鱼的每一天」那边的一行顺手一提,或者她自己调 `map_places`。
|
|
85
|
+
|
|
86
|
+
### 配置 5 项
|
|
87
|
+
|
|
88
|
+
`mapOn` / `mapImggenOn` / `mapFeastOn` / `mapFunOn` / `mapStyleRef`(+ 宿主管的 `enabled`)。宿主 `/api/config` 不合并 defaults,插件自己 `#ensureConfigSection` 补齐——`enabled` 跳过、不覆盖已有值、`persist` 抛错也吞掉。
|
|
89
|
+
|
|
90
|
+
### 占用很小(实测)
|
|
91
|
+
|
|
92
|
+
每轮固定成本约 **2.3–3.0k tokens**(`ENV_PROMPT` 585–818 + 六工具 schema 1706–2212),加地点清单后约 2.4–4.2k。清单里每处只带 40 字描写、最多列 20 处,其余「还有 N 处」带过——所以地点再多也不会线性膨胀;完整描写永远由 `map_look` 现给。单次回执:`map_look` 约 0.2k、`map_places`(25 处)约 1.4–2.0k。
|
|
93
|
+
|
|
94
|
+
### 面板:一张地点卡片墙
|
|
95
|
+
|
|
96
|
+
有图的卡显示 base64 缩略图,没图的显示文字描写,没写描写显示「还没写描写」。点卡片展开能改名字 / 描写 / 画风 / 别名 / 归类 / `scene` / `funVenue`,标常去,传图 / 换图 / 清空图,删掉这处。顶部能选地形(出勾选表)、加一处。
|
|
97
|
+
|
|
98
|
+
**界面里没有一个坐标输入框,也没有一根连线**;分组只是展示顺序。渲染出错会把原因显示出来 + 一个「重新载入」,不会停在半截点不动。
|
|
99
|
+
|
|
100
|
+
### 降级
|
|
101
|
+
|
|
102
|
+
没装生图 / 挪走素材库 / 关掉任一联动开关 / `scene` 或 `funVenue` 留空 / 没装「鱼的每一天」/ 状态文件坏 / config 坏 / 图片被删——一律静默降级,绝不报错、绝不卸载任何 World。`envPromptVars()` 全程 try/catch;`create()` 保持纯。
|
|
103
|
+
|
|
104
|
+
### 校验
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
places 19 / state 38 / world 63 / panels 28 = 148 条
|
|
108
|
+
check-name ✓ check-prompt ✓ check-isolation ✓ smoke ✓ make-describe --check ✓
|
|
109
|
+
```
|
package/PUBLISHING.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 发布清单(cortico-world-map)
|
|
2
|
+
|
|
3
|
+
> 这一版 **0.1.0**,还没发。发布由主人自己在 PowerShell 里敲(`npm publish` 要真 TTY + 6 位 OTP,agent 做不了)。
|
|
4
|
+
|
|
5
|
+
## 发之前
|
|
6
|
+
|
|
7
|
+
```powershell
|
|
8
|
+
cd "E:\deep seek\map-world"
|
|
9
|
+
|
|
10
|
+
# 1) 全套测试(逐个跑,不用 node --test——受限沙箱里 spawn 子进程会 EPERM)
|
|
11
|
+
node test/places.test.mjs
|
|
12
|
+
node test/state.test.mjs
|
|
13
|
+
node test/world.test.mjs
|
|
14
|
+
node test/panels.test.mjs
|
|
15
|
+
|
|
16
|
+
# 2) 单独跑的自检
|
|
17
|
+
node tools/check-name.mjs # 显示名三处一致
|
|
18
|
+
node tools/check-prompt.mjs # 占位符对齐 + 不提生图也能读通
|
|
19
|
+
node tools/check-isolation.mjs # 不依赖别的 World + 不带路线
|
|
20
|
+
node tools/smoke.mjs # dry-mount 冒烟
|
|
21
|
+
|
|
22
|
+
# 3) describe.json 必须与代码一致
|
|
23
|
+
node tools/make-describe.mjs --check
|
|
24
|
+
|
|
25
|
+
# 4) install.ps1 的 BOM(前 3 字节必须是 239,187,191)
|
|
26
|
+
node tools/fix-ps1-bom.mjs install.ps1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
或者一条 `npm run verify`(= 补 BOM + 显示名 + 提示词 + 隔离 + 冒烟 + describe 比对)。
|
|
30
|
+
|
|
31
|
+
## 发
|
|
32
|
+
|
|
33
|
+
`npm publish` 需要 **`danger-full-access` + 真 TTY + 6 位 OTP**,必须在主人自己的 PowerShell 里敲:
|
|
34
|
+
|
|
35
|
+
```powershell
|
|
36
|
+
cd "E:\deep seek\map-world"
|
|
37
|
+
npm pack --dry-run # 先看会打进包里哪些文件
|
|
38
|
+
npm publish --otp 123456 # 换成你手机上的码
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`files` 字段只收 `src / dist / assets / describe.json / CHANGELOG.md / README.md / PUBLISHING.md`——`test/` 和 `tools/` 不进包。
|
|
42
|
+
|
|
43
|
+
## 发之后验
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
npm view cortico-world-map version # 应回 0.1.0
|
|
47
|
+
npm view cortico-world-map dist-tags # latest 应是 0.1.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
想让它进市场,开一个 `[同步] cortico-world-map` issue。
|
|
51
|
+
|
|
52
|
+
## 发之前必须确认的两件事
|
|
53
|
+
|
|
54
|
+
1. **显示名已定稿「鱼的小世界」**(英文 `Little World`,2026-11-15 主人拍板)。
|
|
55
|
+
- 以后再改,三处一起改,缺一处界面与包里就对不上:`src/config.js` 的 `LABEL`、`package.json` 的 `cortico.displayName` + `locales.*.displayName`、`dist/webui.js` 里 `T.zh` / `T.en` 的 `title`。
|
|
56
|
+
- `node tools/check-name.mjs` 会把不一致当场抓出来(也已进 `verify` 和 `prepublishOnly`)。
|
|
57
|
+
- **英文名别带撇号**——`Fish's ...` 那次炸过 JS 单引号字符串,`node --check` 直接 `SyntaxError`。
|
|
58
|
+
2. **`mapStyleRef` 要不要真实现**(整图一张样式参考当所有地点出图的风格基准)。现在只有字段,不影响任何回执。
|
|
59
|
+
|
|
60
|
+
**`worlds.map` 段名不能改**:world id 必须是 `map`——「鱼的每一天」那边的 `maplink`(归另一个会话)只读 `worlds.map.enabled` 这一个字段。改了名就断了那条契约。
|
|
61
|
+
|
|
62
|
+
## 版本号
|
|
63
|
+
|
|
64
|
+
**首发定为 `0.1.0`**(2026-11-15 主人拍板):`package.json` 的 `version` 与 `CHANGELOG.md` 的段标题都是 `0.1.0`,
|
|
65
|
+
CHANGELOG 是**单节**(描述这一版是什么样,不含开发过程的修前/修后)。
|
|
66
|
+
|
|
67
|
+
以后改版本号要同时改:
|
|
68
|
+
|
|
69
|
+
- `package.json` 的 `version`
|
|
70
|
+
- `CHANGELOG.md` 加一节(市场按 `##` 标题里的版本号切段)
|
|
71
|
+
|
|
72
|
+
**git 提交、发版仍等主人点头。**
|
|
73
|
+
|
|
74
|
+
## 常见坑
|
|
75
|
+
|
|
76
|
+
| 坑 | 说明 |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| 用 `node --test` | 受限沙箱里 spawn 子进程会 EPERM,必须 `node test/xxx.test.mjs` 逐个跑 |
|
|
79
|
+
| 用 `Set-Content` / `.NET` 静态调用改中文文件 | 会乱码。改中文一律用编辑工具或 Node `fs` |
|
|
80
|
+
| `install.ps1` 丢 BOM | PowerShell 5.1 会按 GBK 读中文,整个脚本乱码。`node tools/fix-ps1-bom.mjs` |
|
|
81
|
+
| 改了 `ENV_PROMPT.md` 忘了重跑 describe | `node tools/make-describe.mjs --check` 会报不一致 |
|
|
82
|
+
| 发之前没跑 `check-isolation` | 它挡的是「偷偷依赖别的 World」和「偷偷加路线」,两条都是认证会查的 |
|
package/README.md
CHANGED
|
@@ -1,3 +1,205 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 鱼的小世界(cortico-world-map)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> 包名 `cortico-world-map`、world id **`map`**、显示名 **「鱼的小世界」**(2026-11-15 定稿,英文 `Little World`)。
|
|
4
|
+
> 需求文档:`MAP-小地图插件-方案.md`。
|
|
5
|
+
|
|
6
|
+
给 Coo(Coopanion)桌宠一张**「周围的地图」**:家在哪、常去哪儿、附近有什么。
|
|
7
|
+
|
|
8
|
+
每一处地方只有**文字**——空间、陈设、配色、光线、氛围——外加一句固定的画风锚点,所以同一个地方反复看、反复画都是同一副样子。画面可以**完全靠主人自己上传一张本地图**:装不装别的插件都能用,零成本、画风全由主人定。
|
|
9
|
+
|
|
10
|
+
## 它刻意没有的东西
|
|
11
|
+
|
|
12
|
+
**没有路线、没有坐标、没有距离、也没有导航。**
|
|
13
|
+
|
|
14
|
+
一处地方就是「它长什么样」,不是「怎么走到它」。日程里写去哪是「鱼的每一天」的事,这里只提供「那个地方是什么样子」——所以「森林里的鱼出去上班」这种割裂从根上不会发生:库里列的是「家 / 溪边 / 老橡树」,她自然不会凭空写「公司 / 地铁」。
|
|
15
|
+
|
|
16
|
+
这条不是「这一版先不做」:`place` 里不许有任何 geo 字段,`test/places.test.mjs` 和 `tools/check-isolation.mjs` 各钉了一道守门断言。
|
|
17
|
+
|
|
18
|
+
## 装
|
|
19
|
+
|
|
20
|
+
先把 Coo **完全退出**,然后:
|
|
21
|
+
|
|
22
|
+
```powershell
|
|
23
|
+
# 预演
|
|
24
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 -CooRoot "E:\Coopanion" -DryRun
|
|
25
|
+
|
|
26
|
+
# 真装
|
|
27
|
+
powershell -ExecutionPolicy Bypass -File .\install.ps1 -CooRoot "E:\Coopanion"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
装完重启 Coo,面板 → 世界 →「鱼的小世界」应为 `active`,配置页 5 项。
|
|
31
|
+
|
|
32
|
+
装上之后 `<数据目录>/../config.json` 里会有 `worlds.map.enabled = true`——**「鱼的每一天」那边的 `maplink` 就靠这一个字段**判断要不要在「自己的时间」里加一行(见下)。
|
|
33
|
+
|
|
34
|
+
## 开箱:五套预设地形
|
|
35
|
+
|
|
36
|
+
装上之后进面板选一套,**展开勾选表挑要哪几处**(默认全选、已有的置灰),主人只改文字、传图:
|
|
37
|
+
|
|
38
|
+
| 地形 | id | 预置地点 |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| 林间 | `forest` | 家(树洞/小木屋)、老橡树、溪边、蘑菇坡、林间空地 |
|
|
41
|
+
| 小区 | `neighborhood` | 家、楼下长椅、便利店门口、小花园、单元楼道 |
|
|
42
|
+
| 江边 | `riverside` | 家、江堤台阶、旧码头、芦苇滩、江边石墩 |
|
|
43
|
+
| 山脚 | `foothill` | 家、上山口、山泉、半坡亭、碎石坡 |
|
|
44
|
+
| 旅行 | `travel` | 海边小镇、雪山客栈、古城老街、温泉旅馆、林间营地 |
|
|
45
|
+
|
|
46
|
+
**选地形不等于全加**:点了地形会先出勾选表,勾上哪几处才加哪几处。已有的那几处置灰、不能重复勾;全不勾时「加进去」是灰的,不会静默什么都不做。
|
|
47
|
+
|
|
48
|
+
**换地形只追加,不删已有地点**——所以「林间」写好的描写,切到「江边」之后还在,两套并存(id 带地形前缀,`forest-home` / `riverside-home`,不撞)。
|
|
49
|
+
|
|
50
|
+
### 旅行那几处
|
|
51
|
+
|
|
52
|
+
远方地名,只说「那儿长什么样」。**没有几天、没有怎么去、没有第几天**——那是她日程的事,不是地图的事。
|
|
53
|
+
|
|
54
|
+
每处预置一个「娱乐时间里最接近的那一处」:
|
|
55
|
+
|
|
56
|
+
| 地点 | 最接近的 |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| 海边小镇 | 江边 |
|
|
59
|
+
| 雪山客栈 | 爬山 |
|
|
60
|
+
| 古城老街 | 旧货市场 |
|
|
61
|
+
| 温泉旅馆 | 澡堂 |
|
|
62
|
+
| 林间营地 | 公园 |
|
|
63
|
+
|
|
64
|
+
为什么不是直接用娱乐时间那二十个正名:它的场所库里**没有**「海边小镇」「雪山」这种词,直接让她 `fun_go` 填这几个字,那边会回「没听说过这处」——正是红线禁的「指向不存在的东西」。所以递的是**最接近的一处**,回执会明说「不是同一个地方,别把『江边』说成『海边小镇』」。
|
|
65
|
+
|
|
66
|
+
## 两种画面来源
|
|
67
|
+
|
|
68
|
+
### 来源 A:本地图片(主人上传)—— 可完全独立
|
|
69
|
+
|
|
70
|
+
面板里每处地方有「传一张图」。图落 `<数据目录>/map/covers/<id>.<ext>`,面板走 `ctx.invoke('cover', {id})` 拿 **base64 data URL** 显示。
|
|
71
|
+
|
|
72
|
+
- 只认 **png / jpg / webp / gif**,上限 **8 MiB**,按**文件头魔数**校验,**不信扩展名**(从别处拖进来一个改名成 `.png` 的文件会被当场拒掉)。
|
|
73
|
+
- 扩展名按魔数定,不听你传的那个。
|
|
74
|
+
- 不装任何别的插件也能完整使用。
|
|
75
|
+
|
|
76
|
+
### 来源 B:生图工作室联动 —— 可选,装了才提
|
|
77
|
+
|
|
78
|
+
**那句「发图时 scene 填 X」只在三条全满足时才出现**:
|
|
79
|
+
|
|
80
|
+
1. 配置 `mapImggenOn` 开着;
|
|
81
|
+
2. 小地图读到 `worlds.imggen.enabled === true`(**只读 config 这一个布尔字段**,不调它的工具、不读它的素材库);
|
|
82
|
+
3. 这一处地方的 `scene` 非空(也就是主人真把库里的正名填进来了)。
|
|
83
|
+
|
|
84
|
+
**缺任意一条,那句话整段不出现**,并且回执里连 `imggen_draw` / `scene` 这个词都不会出现——绝不指向一个不存在的工具或场景名。有测试逐条钉住(`test/world.test.mjs` 的「三道条件」一组)。
|
|
85
|
+
|
|
86
|
+
`scene` 是**字符串,不是读库**:本插件不读 `imggen-library`,只把「该填哪个名字」递到她嘴边,填参数是她自己做的。
|
|
87
|
+
|
|
88
|
+
## 画风固定 = 每处一句 style + 有图就锁死
|
|
89
|
+
|
|
90
|
+
1. **每处地方一句 `style`**:出图提示词里固定带上,同一处地方不同次出图同风格。
|
|
91
|
+
2. **一旦有 `cover` 就锁死,不自动重生**:要换得主人手动点「清空图」,再传一张新的。常去的地方因此永不漂。
|
|
92
|
+
3. `mapStyleRef`(整图样式参考)**这一版只留字段不实现**——空着就是各地点用自己的 `style`。
|
|
93
|
+
|
|
94
|
+
## 六个工具
|
|
95
|
+
|
|
96
|
+
| 工具 | 作用 |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `map_places` | 列出地点(家 / 常去 / 周围 / 旅行),`frequent` 排前;可 `kind` 筛 |
|
|
99
|
+
| `map_look` | 看某一处:文字描写 + `style` + 有没有图;三条全满足才递「发图填哪个 scene」,旅游处还会递「想真去逛去哪」 |
|
|
100
|
+
| `map_add` | 加一处:只填**文字**(name/aliases/kind/desc/style/scene/funVenue),没有坐标可填 |
|
|
101
|
+
| `map_edit` | 改文字 / 置顶「常去」/ 改 `style` / 改 `scene` / 改 `funVenue`;只动传进来的那几项 |
|
|
102
|
+
| `map_cover` | 换本地图或清空;受「锁死」约束 |
|
|
103
|
+
| `map_view` | 整张小地图(按家 / 常去 / 周围 / 旅行分组铺开,纯展示,**不带路线连线、不带行程**) |
|
|
104
|
+
|
|
105
|
+
**这个 World 不推任何事件**(`describe.events` 是空数组、`start()` 里没有定时器)。什么时候看地图,由「鱼的每一天」那边的一行提示顺手一提,或者她自己调 `map_places`。
|
|
106
|
+
|
|
107
|
+
## 配置(5 项,默认都开,热改)
|
|
108
|
+
|
|
109
|
+
| 键 | 默认 | 作用 |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `mapOn` | `true` | 总开关。关掉=不往提示词注入地点清单,工具与面板还在 |
|
|
112
|
+
| `mapImggenOn` | `true` | 可选联动开关。关掉=纯文字+本地图,绝不提 `imggen_draw` |
|
|
113
|
+
| `mapFeastOn` | `true` | 「鱼的每一天」联动。关掉=一个字都不提 `feast_life_plan` / `feast_life_now` |
|
|
114
|
+
| `mapFunOn` | `true` | 「娱乐时间」联动。关掉=不提 `fun_go` / `fun_places` |
|
|
115
|
+
| `mapStyleRef` | 空 | 整图样式参考。**这一版只留字段不实现** |
|
|
116
|
+
|
|
117
|
+
三个联动开关**都是「开关 + 装没装 + 这处有没有名字」三条全满足才提**,缺一条整段不出现:
|
|
118
|
+
|
|
119
|
+
| 联动 | 开关 | 还要读到 | 还要 |
|
|
120
|
+
| --- | --- | --- | --- |
|
|
121
|
+
| 生图 | `mapImggenOn` | `worlds.imggen.enabled === true` | 该处 `scene` 非空 |
|
|
122
|
+
| 鱼的每一天 | `mapFeastOn` | `worlds.feast.enabled === true` | 有地点 |
|
|
123
|
+
| 娱乐时间 | `mapFunOn` | `worlds.fun.enabled === true` | 该处 `funVenue` 非空 |
|
|
124
|
+
|
|
125
|
+
> 宿主的 `/api/config` 读落盘段、**不合并 defaults**,所以插件自己 `#ensureConfigSection` 补齐(照 `fun-world/src/world.js` 那段,`enabled` 跳过、不覆盖已有值),否则界面会显示成 `false`。
|
|
126
|
+
|
|
127
|
+
## 它和别的 World 是怎么联动的
|
|
128
|
+
|
|
129
|
+
**不调别的 World 的工具、不读别人的状态或日程文件**(World 契约的红线)。联动只借两样东西:
|
|
130
|
+
|
|
131
|
+
1. **读 config 一个布尔字段**:`worlds.imggen.enabled`,判断能不能提生图。read 配置文件不算 World 间依赖(和 `feed-world/src/life/funlink.js` 读 `worlds.fun.enabled` 同一套)。
|
|
132
|
+
2. **提示词各写一句指向对方**:本插件 `ENV_PROMPT.md` 里指向 `feast_life_plan` / `feast_life_now`,以及(可选)`imggen_draw`。
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
鱼的小世界 ──「写日程用地点正名」──→ 鱼的每一天(一句提示词,不调工具)
|
|
136
|
+
鱼的每一天 ──「lifeFreeMenu 列 map_*」──→ 鱼的小世界(maplink,归另一个会话)
|
|
137
|
+
鱼的小世界 ──「可选:发图填地点正名」──→ 生图工作室(三条全满足才提)
|
|
138
|
+
鱼的每一天 ──(0.7.1 已有)──────────→ 生图工作室
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 给「鱼的每一天」那个会话的契约(`maplink`,本插件不实现)
|
|
142
|
+
|
|
143
|
+
| 项 | 约定 |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| 新文件 | `feed-world/src/life/maplink.js` |
|
|
146
|
+
| 检测 | `readMapEnabled(dataDir)` 读 `<dataDir>/../config.json` 的 `worlds.map.enabled`(**只读这一个字段**) |
|
|
147
|
+
| 追加行 | `- 看看周围、去个常去的地方:map_places 看有哪些地方 → map_look 看这一处长什么样` |
|
|
148
|
+
| 去重 | 判据「这一行提到 `map_` 开头的工具」;只追加,从不改写 |
|
|
149
|
+
| 开关 | 新配置 `lifeFreeMapOn`(默认 `true`,归「她自己的时间」卡) |
|
|
150
|
+
|
|
151
|
+
本插件这边要做的事只有一件:**包名 `cortico-world-map`、world id `map`,装了启用后 `worlds.map.enabled` 就是 `true`**。已经做到了。
|
|
152
|
+
|
|
153
|
+
## 降级验收
|
|
154
|
+
|
|
155
|
+
| 情况 | 行为 |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| 没装生图工作室 / 挪走素材库 / 关掉 `mapImggenOn` | 文字 + 本地图全在,只是不出图那句提示;**绝不报错、绝不卸载** |
|
|
158
|
+
| `scene` 留空(库里没有这处) | 一个字都不提,绝不编一个场景名 |
|
|
159
|
+
| 没装「鱼的每一天」/ 关掉 `mapFeastOn` | 不提 `feast_life_*`;生图那句改成「按你这会儿真穿的那身填」 |
|
|
160
|
+
| 没装「娱乐时间」/ 关掉 `mapFunOn` / `funVenue` 留空 | 不提 `fun_*`,旅游那处只给文字和图 |
|
|
161
|
+
| 没装「鱼的每一天」 / 没装 `maplink` | 小地图照常完整可用,只是三方不对齐 |
|
|
162
|
+
| 状态文件坏 / config 坏 / 图被删 | 静默降级:回空库、回「没图」,不抛错 |
|
|
163
|
+
| 图片超过 8 MiB / 不是那四种 | 面板当场拒掉并说清楚,不影响别的 |
|
|
164
|
+
|
|
165
|
+
`envPromptVars()` 全程 `try/catch` 永不抛错(抛错会把 World 卸载);`create()` 保持纯(有测试钉住「create 之后目录还是空的」)。
|
|
166
|
+
|
|
167
|
+
## 面板
|
|
168
|
+
|
|
169
|
+
装好启用在 Coo 的世界页签里能看到一张**地点卡片墙**:
|
|
170
|
+
|
|
171
|
+
- 有图的卡显示缩略图(base64 data URL),没图的显示那段文字描写;没写描写显示「还没写描写」。
|
|
172
|
+
- 点卡片展开:改名字 / 描写 / 画风 / 别名 / 归类 / `scene`,标「常去」,传图 / 换图 / 清空图,删掉这处。
|
|
173
|
+
- 顶上是统计、地形下拉(选中即追加)、「加一处」。
|
|
174
|
+
- **没有坐标输入框、没有路线、不按远近排序**——分组只是展示顺序,界面里没有一根连线。
|
|
175
|
+
|
|
176
|
+
## 校验怎么跑
|
|
177
|
+
|
|
178
|
+
```powershell
|
|
179
|
+
cd "E:\deep seek\map-world"
|
|
180
|
+
node test/places.test.mjs # 五套地形 / geo 守门 / id 安全 / hasScene / hasFunVenue
|
|
181
|
+
node test/state.test.mjs # 加改删传图 / 勾选式追加 / 换地形只追加 / cover 锁死
|
|
182
|
+
node test/world.test.mjs # 六工具 / 三个 8 组真值表 / 静默降级 / 图片守门
|
|
183
|
+
node test/panels.test.mjs # 卡片墙 / 勾选表 / base64 缩略图 / 无坐标输入框
|
|
184
|
+
node tools/check-name.mjs # 显示名三处一致(config / package.json / 面板产物)
|
|
185
|
+
node tools/check-prompt.mjs # 占位符对齐 + 空块时不许出现任何外部工具名
|
|
186
|
+
node tools/check-isolation.mjs # 不依赖别的 World / 不带路线
|
|
187
|
+
node tools/smoke.mjs # dry-mount 冒烟
|
|
188
|
+
node tools/make-describe.mjs --check
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`npm run verify` = 补 BOM + 显示名 + 提示词自检 + 隔离审计 + 冒烟 + describe 比对。
|
|
192
|
+
|
|
193
|
+
## 还没定的事
|
|
194
|
+
|
|
195
|
+
- **`mapStyleRef` 要不要真实现**(整图一张样式参考当所有地点出图的风格基准)。现在只有字段,不影响任何回执。
|
|
196
|
+
- **要不要发 npm**(见 `PUBLISHING.md`)。
|
|
197
|
+
- 显示名已定稿「鱼的小世界」。以后要改,得同时动三处,缺一处界面与包里就对不上:`src/config.js` 的 `LABEL`、`package.json` 的 `cortico.displayName` + `locales.*.displayName`、`dist/webui.js` 里 `T.zh` / `T.en` 的 `title`。`node tools/check-name.mjs` 会当场抓到不一致。
|
|
198
|
+
- **英文名不带撇号**:`Fish's ...` 那次炸过 JS 单引号字符串,`node --check` 直接 `SyntaxError`。`check-name.mjs` 里也钉了这一条。
|
|
199
|
+
|
|
200
|
+
## 相关文档
|
|
201
|
+
|
|
202
|
+
- `MAP-小地图插件-方案.md` —— 本插件的定稿方案(§3 数据模型 / §4 画面来源 / §6 工具与配置 / §7 maplink 契约 / §10 红线)
|
|
203
|
+
- `FUN-联动方案.md` —— 联动骨架模板(方案 A / C / D 的出处)
|
|
204
|
+
- `IMGGEN-联动方案.md` —— 素材库结构、`entry.json` 字段、红线出处
|
|
205
|
+
- `HANDOFF-2026-11-15-0.7.4-改名与联动.md` —— 0.7.4 现状、`funlink.js` 的来历
|
package/assets/icon.png
ADDED
|
Binary file
|
package/describe.json
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tools": [
|
|
3
|
+
{
|
|
4
|
+
"name": "map_places",
|
|
5
|
+
"description": "看看周围有哪些地方:家、常去的、附近的、去远处旅行的。每处给一句文字描写、有没有图、是不是常去。默认按「常去 > 家 > 周围 > 旅行」排;想只看一类就填 kind。没有路线、没有远近,也没有「怎么走」。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"kind": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "只看某一类:家 / 常去的 / 周围 / 旅行(英文 home / frequent / around / travel 也认)。不填就全列。"
|
|
12
|
+
},
|
|
13
|
+
"all": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"description": "填 true 就列全部,否则也只列全部(这里没有截断,留着这个参数是为了和别的工具一致)。"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"additionalProperties": false
|
|
19
|
+
},
|
|
20
|
+
"tags": [
|
|
21
|
+
"read",
|
|
22
|
+
"snapshot"
|
|
23
|
+
],
|
|
24
|
+
"summary": {
|
|
25
|
+
"zh": "看周围有哪些地方:家、常去的、附近的、旅行的,按常去排前;可只看某一类。",
|
|
26
|
+
"en": "See the places around her: home, the ones she often goes to, nearby and travel places; can filter by kind."
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "map_look",
|
|
31
|
+
"description": "看某一处长什么样:回执给这一处的文字描写、画风锚点、有没有图。写日程说「此刻在哪」、或者想发图之前用它。这处还空着的时候会明说空着——别替主人编一段描写。",
|
|
32
|
+
"parameters": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"place": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "哪一处,填正名(家 / 溪边 / 老橡树…),别名也认。"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"required": [
|
|
41
|
+
"place"
|
|
42
|
+
],
|
|
43
|
+
"additionalProperties": false
|
|
44
|
+
},
|
|
45
|
+
"tags": [
|
|
46
|
+
"read",
|
|
47
|
+
"snapshot"
|
|
48
|
+
],
|
|
49
|
+
"summary": {
|
|
50
|
+
"zh": "看某一处长什么样:文字描写、画风锚点、有没有图;装了生图且这处有场景名才递发图该填哪个 scene,旅游处还会提娱乐时间里最接近那处。",
|
|
51
|
+
"en": "Look at one place: its written description, style line and whether it has a photo; names the image scene only when that place really has one, and for travel places the nearest venue in Fun time."
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "map_add",
|
|
56
|
+
"description": "加一处地方。只填文字:名字、别名、属于哪一类(家 / 常去的 / 周围 / 旅行)、一句描写、一句画风锚点。**不填坐标、不填路线、不填多远**——这个插件没有这些。",
|
|
57
|
+
"parameters": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"properties": {
|
|
60
|
+
"name": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "这处叫什么,例如「溪边」「楼下长椅」。"
|
|
63
|
+
},
|
|
64
|
+
"aliases": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"items": {
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
69
|
+
"description": "别名,最多 8 个,例如「小溪」「溪水」。"
|
|
70
|
+
},
|
|
71
|
+
"kind": {
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "家 / 常去的 / 周围 / 旅行。不填算「周围」。"
|
|
74
|
+
},
|
|
75
|
+
"desc": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "一句话文字描写:只写空间、陈设、配色、光线、氛围——不写姿势表情、不写她在干什么、不写「从这里走十分钟到哪」。"
|
|
78
|
+
},
|
|
79
|
+
"style": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"description": "一句画风锚点,以后每次出图都带上,越稳定越好。"
|
|
82
|
+
},
|
|
83
|
+
"scene": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "生图素材库里的场景正名,**主人知道库里有什么才填**;拿不准就别填,留空不影响任何事。"
|
|
86
|
+
},
|
|
87
|
+
"funVenue": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "娱乐时间里**最接近这处**的那个场所正名(例如「江边」「爬山」);填了才可能提「想真去逛去哪」,拿不准就别填。"
|
|
90
|
+
},
|
|
91
|
+
"frequent": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"description": "是不是常去(置顶)。"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"required": [
|
|
97
|
+
"name"
|
|
98
|
+
],
|
|
99
|
+
"additionalProperties": false
|
|
100
|
+
},
|
|
101
|
+
"tags": [
|
|
102
|
+
"write"
|
|
103
|
+
],
|
|
104
|
+
"summary": {
|
|
105
|
+
"zh": "加一处地方:只填文字(名字、别名、归类、描写、画风),没有坐标也没有远近。",
|
|
106
|
+
"en": "Add a place: words only (name, aliases, kind, description, style); no coordinates, no distances."
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "map_edit",
|
|
111
|
+
"description": "改某一处的文字:描写、画风锚点、别名、归类、是否常去、scene 正名、娱乐时间那处。只改传进来的那几项,没传的一个字都不动。要换图用 map_cover。",
|
|
112
|
+
"parameters": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"properties": {
|
|
115
|
+
"place": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"description": "改哪一处,填正名或 id。"
|
|
118
|
+
},
|
|
119
|
+
"name": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"description": "改成这个正名。"
|
|
122
|
+
},
|
|
123
|
+
"aliases": {
|
|
124
|
+
"type": "array",
|
|
125
|
+
"items": {
|
|
126
|
+
"type": "string"
|
|
127
|
+
},
|
|
128
|
+
"description": "整套别名(不是追加)。"
|
|
129
|
+
},
|
|
130
|
+
"kind": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"description": "家 / 常去的 / 周围 / 旅行。"
|
|
133
|
+
},
|
|
134
|
+
"desc": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"description": "换成这段文字描写。"
|
|
137
|
+
},
|
|
138
|
+
"style": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"description": "换成这句画风锚点。"
|
|
141
|
+
},
|
|
142
|
+
"scene": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"description": "换成这个 scene 正名;传空串就是清掉(以后不再提发图填什么)。"
|
|
145
|
+
},
|
|
146
|
+
"funVenue": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"description": "换成娱乐时间里最接近这处的那一处正名;传空串就是清掉(以后不再提去那儿逛)。"
|
|
149
|
+
},
|
|
150
|
+
"frequent": {
|
|
151
|
+
"type": "boolean",
|
|
152
|
+
"description": "标成 / 取消「常去」。"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"required": [
|
|
156
|
+
"place"
|
|
157
|
+
],
|
|
158
|
+
"additionalProperties": false
|
|
159
|
+
},
|
|
160
|
+
"tags": [
|
|
161
|
+
"write"
|
|
162
|
+
],
|
|
163
|
+
"summary": {
|
|
164
|
+
"zh": "改某一处的文字、画风、归类、是否常去、scene 正名、娱乐时间那处;只动传进来的那几项。",
|
|
165
|
+
"en": "Edit one place: words, style, kind, frequent flag, scene name, nearest Fun time venue; only the fields passed in."
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "map_cover",
|
|
170
|
+
"description": "这处地方的图:换成本地的一张、或者清空。**图是主人从面板上传的**,不是这里画的;你来这里只做两件事——把主人放好的那张挂上去,或者清空。清空之后主人才可以再放一张新的(有图的时候它锁死,不会自己变)。",
|
|
171
|
+
"parameters": {
|
|
172
|
+
"type": "object",
|
|
173
|
+
"properties": {
|
|
174
|
+
"place": {
|
|
175
|
+
"type": "string",
|
|
176
|
+
"description": "哪一处,填正名或 id。"
|
|
177
|
+
},
|
|
178
|
+
"file": {
|
|
179
|
+
"type": "string",
|
|
180
|
+
"description": "要挂的图片文件名(主人已经放进这处目录的那张)。不填就看现在挂着什么。"
|
|
181
|
+
},
|
|
182
|
+
"clear": {
|
|
183
|
+
"type": "boolean",
|
|
184
|
+
"description": "填 true 就清空这处的图。"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"required": [
|
|
188
|
+
"place"
|
|
189
|
+
],
|
|
190
|
+
"additionalProperties": false
|
|
191
|
+
},
|
|
192
|
+
"tags": [
|
|
193
|
+
"write"
|
|
194
|
+
],
|
|
195
|
+
"summary": {
|
|
196
|
+
"zh": "换这处地方的本地图或清空;有图就锁着不自动变,清空之后主人才可以再放一张。",
|
|
197
|
+
"en": "Swap or clear the local photo of one place; a photo stays put once set, and only the owner puts a new one."
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "map_view",
|
|
202
|
+
"description": "整张小地图:按「家 / 常去的 / 周围 / 旅行」分组把每一处铺开,带文字描写和有没有图。纯展示——**没有连线、没有路线、没有远近、也没有行程**。",
|
|
203
|
+
"parameters": {
|
|
204
|
+
"type": "object",
|
|
205
|
+
"properties": {}
|
|
206
|
+
},
|
|
207
|
+
"tags": [
|
|
208
|
+
"read",
|
|
209
|
+
"snapshot"
|
|
210
|
+
],
|
|
211
|
+
"summary": {
|
|
212
|
+
"zh": "整张小地图:按家 / 常去 / 周围 / 旅行分组铺开,纯展示,没有连线、没有路线、也没有行程。",
|
|
213
|
+
"en": "The whole little map: grouped as home / frequent / around / travel, display only, no lines, no routes and no itinerary."
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"events": [],
|
|
218
|
+
"prompts": [
|
|
219
|
+
{
|
|
220
|
+
"key": "worlds.map.env",
|
|
221
|
+
"title": "鱼的小世界",
|
|
222
|
+
"role": "envPrompt",
|
|
223
|
+
"content": "## 小地图\n\n你周围有哪些地方——家在哪、常去哪儿、附近有什么、去远处旅行可以是什么样。每一处只有**文字**:空间、陈设、配色、光线、氛围,加一句固定的画风锚点;有主人放的图就照着那张看。\n\n**这里没有路线、没有坐标、没有距离、也没有导航。** 一处地方就是「它长什么样」,不是「怎么走到它」。所以不要从这儿推「走十分钟到 X」「先出小区再左转」——这种话不该出现在你说的地方上。\n\n- 想看有哪些地方:`map_places`。默认按「常去 > 家 > 周围 > 旅行」排,`kind` 能只看一类(家 / 常去的 / 周围 / 旅行)。\n- 想看某一处具体长什么样:`map_look`(`place` 填正名,别名也认)。回执给那句描写、画风锚点、有没有图。\n- 这处还空着、没写描写时,回执会明说「还没写描写」——**那就说不知道,别替主人编一段**。那是他的地方,不是你的。\n- 主人加地方、改描写、传图都在面板里做,或者让你用 `map_add` / `map_edit` / `map_cover`。加地方**只填文字**:名字、别名、归类、一句描写、一句画风锚点,没有坐标可填。\n- 一处地方一旦有了图就**锁着**,不会自己变;要换得主人先清空再放一张新的。所以看到有图的那处,就照着那张说,别另画一张。\n\n{{map_places_block}}\n\n## 旅行那几处\n\n「旅行」这一类的几处地方是**远方**:海边小镇、雪山客栈、古城老街、温泉旅馆、林间营地那种。\n\n- 它只回答「那儿长什么样」。**几天、怎么去、先去哪后去哪、行程怎么排,都不在这里**——那是你自己日程该管的事,别从小地图里推行程。\n- 真想去的时候,回执会告诉你娱乐时间里**最接近这处的一处**是哪个。那是「最接近的一处」,不是同一个地方:别把「江边」说成「海边小镇」,也别把「澡堂」说成「温泉旅馆」。\n- 只是想想、说说那儿是什么样,也完全可以——不去也是一种说法。\n\n{{map_feast_block}}\n\n{{map_imggen_block}}\n\n## 不用你操心的事\n\n- 你不必为了「地图上有这处」才去某处;不去也照样是这处地方。\n- 主人没写描写的地方就是空的,空着不是待办,不用催他填。\n- 地点会一直是这些,改的是文字和画面,不是路线和远近。\n"
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
}
|