gamekit777 0.1.6 → 0.1.7

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.
Files changed (47) hide show
  1. package/create-game/scaffold.ts +72 -15
  2. package/create-game/template/base/game.meta.json +9 -0
  3. package/create-game/template/{game.ts.tmpl → base/game.ts} +15 -11
  4. package/create-game/template/{package.json.tmpl → base/package.json} +7 -3
  5. package/create-game/template/{src/components/App.svelte.tmpl → base/src/components/App.svelte} +8 -3
  6. package/create-game/template/{src/context.svelte.ts.tmpl → base/src/context.svelte.ts} +5 -5
  7. package/create-game/template/{src → base/src}/rules/const.ts +2 -1
  8. package/create-game/template/{src/rules/restore.ts.tmpl → base/src/rules/restore.ts} +7 -5
  9. package/create-game/template/{src/rules/schema.ts.tmpl → base/src/rules/schema.ts} +2 -2
  10. package/create-game/template/{src/rules/simulate.ts.tmpl → base/src/rules/simulate.ts} +2 -2
  11. package/create-game/template/{src/rules/types.ts.tmpl → base/src/rules/types.ts} +2 -2
  12. package/create-game/template/{src/state/game.svelte.ts.tmpl → base/src/state/game.svelte.ts} +14 -7
  13. package/create-game/template/{src/view/mount.svelte.ts.tmpl → base/src/view/mount.svelte.ts} +6 -4
  14. package/create-game/template/{src/view/present.ts.tmpl → base/src/view/present.ts} +2 -2
  15. package/create-game/template/{test/e2e.test.ts.tmpl → base/test/e2e.test.ts} +4 -1
  16. package/create-game/template/base/tsconfig.json +8 -0
  17. package/create-game/template/{CLAUDE.md.tmpl → overlay/CLAUDE.md.tmpl} +13 -3
  18. package/dev-host/DevShell.svelte +237 -73
  19. package/dev-host/index.ts +1 -0
  20. package/dev-host/layout.ts +80 -0
  21. package/dev-host/platform.svelte.ts +23 -4
  22. package/dev-host/run.ts +8 -1
  23. package/dev-host/theme.css +142 -10
  24. package/package.json +1 -1
  25. package/runtime/index.ts +1 -0
  26. package/runtime/meter.ts +72 -0
  27. package/runtime/registry.ts +5 -1
  28. package/sdk/host.ts +8 -0
  29. package/sdk/stage.ts +97 -11
  30. package/studio/app/App.svelte +92 -10
  31. package/studio/app/panels/PreviewPanel.svelte +4 -0
  32. package/studio/preview/entry.ts +10 -1
  33. package/studio/src/engine.ts +5 -1
  34. package/studio/src/mcp.ts +4 -2
  35. package/studio/src/studio-plugin.ts +29 -13
  36. package/create-game/template/game.meta.json.tmpl +0 -8
  37. package/create-game/template/tsconfig.json +0 -22
  38. /package/create-game/template/{scripts/verify.ts.tmpl → base/scripts/verify.ts} +0 -0
  39. /package/create-game/template/{src → base/src}/assets/critical/.gitkeep +0 -0
  40. /package/create-game/template/{src → base/src}/assets/lazy/.gitkeep +0 -0
  41. /package/create-game/template/{src/index.ts.tmpl → base/src/index.ts} +0 -0
  42. /package/create-game/template/{src → base/src}/styles/animations.css +0 -0
  43. /package/create-game/template/{src → base/src}/styles/global.css +0 -0
  44. /package/create-game/template/{src → base/src}/view/bridge.svelte.ts +0 -0
  45. /package/create-game/template/{vite.config.ts → base/vite.config.ts} +0 -0
  46. /package/create-game/template/{vitest.config.ts → base/vitest.config.ts} +0 -0
  47. /package/create-game/template/{_gitignore → overlay/_gitignore} +0 -0
@@ -5,6 +5,7 @@
5
5
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
6
6
  import { join, relative } from 'node:path';
7
7
  import { Sha256 } from 'gamekit777/sdk/hash';
8
+ import type { StageInfo, StageLayout } from 'gamekit777/sdk';
8
9
  import type { Segment } from 'gamekit777/weights';
9
10
  import { Bus } from './bus.ts';
10
11
  import { buildMode, groupsSummary, listArtifacts, readArtifactBytes, sampleMode, type Artifact, type BuildModeOptions } from './build.ts';
@@ -31,6 +32,9 @@ export interface PreviewState {
31
32
  lastError: string | null;
32
33
  recent: unknown[];
33
34
  consoleErrors: string[];
35
+ /** 机台布局与交给游戏的舞台(含安全区)。页面的切换按钮和 MCP 的 preview_set 都以这里为准 */
36
+ layout: StageLayout | null;
37
+ stage: StageInfo | null;
34
38
  updatedAt: number;
35
39
  }
36
40
 
@@ -85,7 +89,7 @@ export class Engine {
85
89
  readonly assets: AssetStore;
86
90
  preview: PreviewState = {
87
91
  connected: false, config: null, mode: null, bet: null, balance: null,
88
- status: null, lastError: null, recent: [], consoleErrors: [], updatedAt: 0,
92
+ status: null, lastError: null, recent: [], consoleErrors: [], layout: null, stage: null, updatedAt: 0,
89
93
  };
90
94
  #publish = new Map<string, PublishRequest>();
91
95
  #lastFingerprint: string;
package/studio/src/mcp.ts CHANGED
@@ -282,25 +282,27 @@ export function createMcpServer(engine: Engine): McpServer {
282
282
  });
283
283
 
284
284
  s.registerTool('preview_state', {
285
- description: '预览页的当前状态:连没连、当前 config / mode / 注额 / 余额、已加载的表、最近几局、控制台报错。',
285
+ description: '预览页的当前状态:连没连、当前 config / mode / 注额 / 余额、已加载的表、最近几局、控制台报错、机台布局(desktop/mobile)与交给游戏的舞台尺寸和安全区。',
286
286
  inputSchema: {},
287
287
  }, async () => {
288
288
  engine.touch();
289
289
  const p = engine.preview;
290
290
  if (!engine.bus.previewConnected) return out(`预览页没连着。请在浏览器打开 ${engine.urls.studio}`, { connected: false });
291
291
  return out([`## 预览(本地表模型)`, `- mode ${p.mode},注额 ${p.bet},余额 ${p.balance}`, `- config ${JSON.stringify(p.config)}`,
292
+ ...(p.stage ? [`- 布局 ${p.layout},舞台 ${p.stage.width}×${p.stage.height},安全区 上 ${p.stage.safe.top} 下 ${p.stage.safe.bottom}`] : []),
292
293
  `- 最近 ${p.recent.length} 局`, ...(p.lastError ? [`- ⚠️ 最近错误:${p.lastError}`] : []),
293
294
  ...(p.consoleErrors.length ? ['', '### 控制台报错', ...p.consoleErrors.slice(-5).map((e) => `- ${e}`)] : [])].join('\n'), p);
294
295
  });
295
296
 
296
297
  s.registerTool('preview_set', {
297
- description: '改预览的设置:config、注额、客户端种子、造型、极速。局中/自动中会被平台否决,rejected 里会说。',
298
+ description: '改预览的设置:config、注额、客户端种子、造型、极速、机台布局(desktop 桌面 / mobile 手机竖屏全屏)。局中/自动中会被平台否决,rejected 里会说。',
298
299
  inputSchema: {
299
300
  config: z.record(z.string(), z.unknown()).optional(),
300
301
  bet: z.number().int().optional().describe('最小货币单位(分)'),
301
302
  clientSeed: z.string().optional(),
302
303
  skin: z.string().optional(),
303
304
  turbo: z.boolean().optional(),
305
+ layout: z.enum(['desktop', 'mobile']).optional().describe('切机台布局。游戏不重挂,收到 host.stage 后自己重排'),
304
306
  },
305
307
  }, async (a) => {
306
308
  try {
@@ -5,9 +5,7 @@
5
5
  *
6
6
  * 不往游戏目录写任何文件:两个 html 从内存吐,入口用 /@fs 指回 studio 包。
7
7
  * 不依赖游戏目录里有 index.html:脚手架出来的项目没有它,`bun run dev` 就是起 studio。 */
8
- import { readFileSync } from 'node:fs';
9
- import type { Plugin } from 'vite';
10
- import { compile } from 'svelte/compiler';
8
+ import type { DevEnvironment, Plugin, Rollup } from 'vite';
11
9
  import { API_PREFIX, createApi } from './api.ts';
12
10
  import type { Engine } from './engine.ts';
13
11
 
@@ -55,18 +53,36 @@ export function studioPlugin(o: StudioPluginOptions): Plugin {
55
53
  return null;
56
54
  },
57
55
 
58
- /* 资源库组件的 <style> 兜底。vite-plugin-svelte 把组件 CSS 存在模块信息里,样式虚拟模块
59
- (…svelte?svelte&type=style&lang.css)从那里取;组件还没编译过就先来要样式(重连、刷新、缓存未命中)时
60
- 它拿不到,退回读文件——整份 .svelte 源码被当 CSS 交给下游,namespace-css 直接炸页。
61
- 库组件在游戏根之外、内容自足,这里自己编一遍只取 CSS:scoped class 的哈希只由样式文本决定,和组件那次编译一致 */
62
- load(id) {
56
+ /* svelte 组件 <style> 的兜底。
57
+ vite-plugin-svelte 把编译出的 CSS 挂在组件模块的 meta 上,样式虚拟模块(…svelte?svelte&type=style&lang.css)
58
+ 用 getModuleInfo(不带 query 的文件名) 去取。两种情况取不到,它就放弃,vite 退回读文件——
59
+ 整份 .svelte 源码被当 CSS 交给下游:模板里的 `{#if}` 变成一条条空规则,`<style>` 里的选择器没有 hash,页面整个走样。
60
+ 1. 装成 npm 包后 gamekit777 在游戏的 node_modules 里,vite 给这类模块 id 加 ?v=<hash>,文件名对不上 id。
61
+ 仓库内是符号链接到 packages/,走 /@fs 路径没有 ?v=,所以只有创作者机器上才坏。
62
+ 2. 组件还没编译过就先来要样式(资源库现场编译、重连、刷新)。
63
+ 这里按文件名在模块图里找那次编译留下的 CSS;没有就先把组件本身 transform 一遍再找——
64
+ 不能自己 compile 一遍只取 CSS:dev 下 vite-plugin-svelte 用文件名算 scope hash(s-xxx),
65
+ 默认的按内容算(svelte-xxx),两边对不上,等于没修。 */
66
+ async load(id) {
63
67
  const m = /^([^?]+\.svelte)\?(?:.*&)?svelte(?:&.*)?&type=style(?:&|$)/.exec(id) ?? /^([^?]+\.svelte)\?(?:.*&)?type=style(?:&|$)/.exec(id);
64
68
  const file = m?.[1];
65
- if (!file || !file.startsWith(o.engine.assets.dir)) return null;
66
- try {
67
- const src = readFileSync(file, 'utf8');
68
- return { code: compile(src, { filename: file, generate: 'client', css: 'external' }).css?.code ?? '' };
69
- } catch { return null; }
69
+ if (!file) return null;
70
+ const env = this.environment;
71
+ if (env.mode !== 'dev') return null;
72
+ const dev = env as DevEnvironment;
73
+ const pick = (): { code: string; map: Rollup.SourceMapInput | undefined; moduleType: 'css' } | null => {
74
+ for (const mod of dev.moduleGraph.getModulesByFile(file) ?? []) {
75
+ // 插件写的 meta 落在 info.meta 上(vite 的 ModuleInfo 代理),mod.meta 是另一份、可能是空的
76
+ const meta = (mod.info?.meta ?? mod.meta) as { svelte?: { css?: { code?: string; map?: Rollup.SourceMapInput } } } | undefined;
77
+ const css = meta?.svelte?.css;
78
+ if (typeof css?.code === 'string') return { code: css.code, map: css.map, moduleType: 'css' };
79
+ }
80
+ return null;
81
+ };
82
+ const hit = pick();
83
+ if (hit) return hit;
84
+ try { await dev.transformRequest(`/@fs${file}`); } catch { return null; }
85
+ return pick();
70
86
  },
71
87
 
72
88
  configureServer(server) {
@@ -1,8 +0,0 @@
1
- {
2
- "id": "__ID__",
3
- "title": "__TITLE__",
4
- "version": "1.0.0",
5
- "aspect": "16:9",
6
- "orientation": "any",
7
- "fonts": []
8
- }
@@ -1,22 +0,0 @@
1
- {
2
- "extends": "@tsconfig/svelte/tsconfig.json",
3
- "compilerOptions": {
4
- "target": "ES2022",
5
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
- "module": "ESNext",
7
- "moduleResolution": "bundler",
8
- "strict": true,
9
- "noUnusedLocals": true,
10
- "noUnusedParameters": true,
11
- "noImplicitOverride": true,
12
- "noFallthroughCasesInSwitch": true,
13
- "noEmit": true,
14
- "isolatedModules": true,
15
- "verbatimModuleSyntax": true,
16
- "skipLibCheck": true,
17
- "forceConsistentCasingInFileNames": true,
18
- "allowImportingTsExtensions": true,
19
- "types": ["vite/client"]
20
- },
21
- "include": ["src", "test", "scripts", "*.ts"]
22
- }