@adatechnology/game-devtools 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/LICENSE +21 -0
- package/MIGRATION.md +209 -0
- package/README.md +121 -2
- package/dist/index.d.ts +270 -0
- package/dist/index.global.js +572 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +547 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/locale.ts","../src/marks.ts","../src/scenarios.ts","../src/devtools.ts"],"sourcesContent":["/** Locales shipped with the package. Unknown locales fall back to `en`. */\nexport type DevtoolsLocale = 'en' | 'pt-BR'\n\n/** Every user-facing default string. Override any of them with the `strings` option. */\nexport interface DevtoolsStrings {\n /** Eight compass headings starting at north, clockwise (N, NE, E, SE, S, SW, W, NW). */\n compass: [string, string, string, string, string, string, string, string]\n /** Label of the default team. */\n defaultTeam: string\n /** Default file name of the downloaded marks file. */\n fileName: string\n /** aria-label of the \"mark this place\" form. */\n markFormLabel: string\n /** aria-label and title of the main panel. */\n panelTitle: string\n markHereTitle: string\n /** Word before the heading in position lines (\"looking N 12\"). */\n lookingAt: string\n teamLabel: string\n notePlaceholder: string\n saveButton: string\n cancelButton: string\n yes: string\n no: string\n placesTitle: string\n marksTitle: (count: number) => string\n savedOnServer: string\n savedInBrowser: string\n noNote: string\n goButton: string\n deleteButton: string\n noMarks: string\n copyAll: string\n downloadFile: string\n closeButton: string\n copied: string\n copySelected: string\n savedServerMsg: string\n serverFailMsg: string\n savedBrowserMsg: string\n hudLook: string\n hudFlight: (speed: string) => string\n hudMarks: (count: number) => string\n}\n\nexport const locales: Record<DevtoolsLocale, DevtoolsStrings> = {\n en: {\n compass: ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'],\n defaultTeam: 'General',\n fileName: 'marks.txt',\n markFormLabel: 'Mark adjustment',\n panelTitle: 'Free mode',\n markHereTitle: 'Mark this place',\n lookingAt: 'looking',\n teamLabel: 'Team',\n notePlaceholder: 'What should be adjusted here?',\n saveButton: 'Save (Enter)',\n cancelButton: 'Cancel (Esc)',\n yes: 'yes',\n no: 'no',\n placesTitle: 'Test places',\n marksTitle: (n) => `Marks (${n})`,\n savedOnServer: \"Saved on this page's server: Claude reads them directly, no need to copy.\",\n savedInBrowser: 'Saved in this browser. To send them: Copy all and paste in the chat, or Download file.',\n noNote: '(no note)',\n goButton: 'Go',\n deleteButton: 'Delete',\n noMarks: 'No marks yet.',\n copyAll: 'Copy all',\n downloadFile: 'Download file',\n closeButton: 'Close (Esc)',\n copied: 'Copied',\n copySelected: 'Selected: Ctrl+C',\n savedServerMsg: 'Mark saved. Claude can already read it',\n serverFailMsg: \"Could not save to the server, it stayed in this browser\",\n savedBrowserMsg: 'Mark saved in this browser. Open the panel to copy',\n hudLook: 'look',\n hudFlight: (speed) => `fly ${speed} m/s`,\n hudMarks: (n) => `${n} ${n === 1 ? 'mark' : 'marks'}`,\n },\n 'pt-BR': {\n compass: ['N', 'NE', 'L', 'SE', 'S', 'SO', 'O', 'NO'],\n defaultTeam: 'Geral',\n fileName: 'marcas.txt',\n markFormLabel: 'Marcar ajuste',\n panelTitle: 'Modo livre',\n markHereTitle: 'Marcar este lugar',\n lookingAt: 'olhando',\n teamLabel: 'Equipe',\n notePlaceholder: 'O que ajustar aqui?',\n saveButton: 'Salvar (Enter)',\n cancelButton: 'Cancelar (Esc)',\n yes: 'sim',\n no: 'não',\n placesTitle: 'Lugares de teste',\n marksTitle: (n) => `Marcas (${n})`,\n savedOnServer: 'Salvas no servidor desta página: Claude lê direto, não precisa copiar.',\n savedInBrowser: 'Salvas neste navegador. Para mandar: Copiar tudo e colar no chat, ou Baixar arquivo.',\n noNote: '(sem nota)',\n goButton: 'Ir',\n deleteButton: 'Apagar',\n noMarks: 'Nenhuma marca ainda.',\n copyAll: 'Copiar tudo',\n downloadFile: 'Baixar arquivo',\n closeButton: 'Fechar (Esc)',\n copied: 'Copiado',\n copySelected: 'Selecionado: Ctrl+C',\n savedServerMsg: 'Marca salva. Claude já consegue ler',\n serverFailMsg: 'Não deu para salvar no servidor, ficou neste navegador',\n savedBrowserMsg: 'Marca salva neste navegador. Abra o painel para copiar',\n hudLook: 'olhar',\n hudFlight: (speed) => `voo ${speed} m/s`,\n hudMarks: (n) => `${n} marcas`,\n },\n}\n\nexport const resolveStrings = (locale?: string, overrides?: Partial<DevtoolsStrings>): DevtoolsStrings => ({\n ...(locales[locale as DevtoolsLocale] ?? locales.en),\n ...overrides,\n})\n","import type { DevtoolsStrings } from './locale'\nimport type { Mark, Team } from './types'\n\n/** Escapes text for use inside HTML. */\nexport const escapeHtml = (s: unknown): string =>\n String(s ?? '').replace(/[&<>\"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"' })[c as '&' | '<' | '>' | '\"']!)\n\n/** Compass heading and degrees for a yaw (yaw 0 looks toward -z, i.e. north). */\nexport function compass(yaw: number, headings: DevtoolsStrings['compass']): [string, number] {\n const g = ((((-yaw * 180) / Math.PI) % 360) + 360) % 360\n return [headings[Math.round(g / 45) % 8], Math.round(g)]\n}\n\ntype LineMark = Pick<Mark, 'team' | 'area' | 'x' | 'y' | 'z' | 'heading' | 'degrees' | 'time'> & { text?: string }\n\n/** One-line text for a mark: `[Team] Area · x 1 y 2 z 3 · looking N 0° · 12:00 · note`. */\nexport function formatMarkLine(m: LineMark, teams: Team[], strings: Pick<DevtoolsStrings, 'lookingAt'>): string {\n const team = (teams.find((e) => e[0] === m.team) || [0, m.team])[1]\n return `[${team}] ${m.area} · x ${m.x} y ${m.y} z ${m.z} · ${strings.lookingAt} ${m.heading} ${m.degrees}° · ${m.time}${m.text ? ' · ' + m.text : ''}`\n}\n\n/** Newest first, without mutating the input. */\nexport const sortMarks = (marks: Mark[]): Mark[] => [...marks].sort((a, b) => b.at - a.at)\n\n/**\n * Serialises marks for copy and download.\n * `text` is one line per mark (newest first); `file` is that text, a blank line, and the raw JSON array\n * (the content of the downloaded file, which Claude or a script can parse back).\n */\nexport function serializeMarks(marks: Mark[], teams: Team[], strings: Pick<DevtoolsStrings, 'lookingAt'>): { text: string; file: string } {\n const text = sortMarks(marks)\n .map((m) => formatMarkLine(m, teams, strings))\n .join('\\n')\n return { text, file: text + '\\n\\n' + JSON.stringify(marks) }\n}\n","import type { Scenario, ScenarioResult } from './types'\n\nexport interface ScenarioRunner<S extends Scenario = Scenario> {\n /** Registers the scenarios, how to apply one and how to check it. */\n set(list: S[], apply: (scenario: S) => void, check: (scenario: S) => ScenarioResult): void\n readonly list: S[]\n readonly active: S | null\n /** Applies a scenario and makes it the active one; false if the id is unknown. */\n run(id: string): boolean\n /** Checks the scenario with that id, or the active one when the id is unknown; `{}` when there is none. */\n check(id?: string): ScenarioResult\n}\n\n/** Pure scenario bookkeeping (no DOM): `{ id, ... }` scenarios, `apply(s)` and `check(s) -> { criterion: { ok, note } }`. */\nexport function createScenarioRunner<S extends Scenario = Scenario>(): ScenarioRunner<S> {\n let list: S[] = []\n let applyFn: (s: S) => void = () => {}\n let checkFn: (s: S) => ScenarioResult = () => ({})\n let active: S | null = null\n return {\n set(l, a, c) {\n list = l\n applyFn = a\n checkFn = c\n },\n get list() {\n return list\n },\n get active() {\n return active\n },\n run(id) {\n const s = list.find((c) => c.id === id)\n if (!s) return false\n applyFn(s)\n active = s\n return true\n },\n check(id) {\n const s = list.find((c) => c.id === id) || active\n return s ? checkFn(s) : {}\n },\n }\n}\n","import { resolveStrings } from './locale'\nimport { compass, escapeHtml as esc, formatMarkLine, serializeMarks, sortMarks } from './marks'\nimport { createScenarioRunner } from './scenarios'\nimport type {\n Bounds,\n Devtools,\n DevtoolsOptions,\n EntityLabel,\n HereInfo,\n Mark,\n PlaceGroup,\n PlayerPosition,\n ProjectionCamera,\n Team,\n ThreeLib,\n} from './types'\n\n/** Minimal shape of the optional `window.claude` runtime that provides a shared database. */\ninterface ClaudeRuntime {\n use(name: 'db' | 'user'): Promise<any>\n}\ndeclare global {\n interface Window {\n claude?: ClaudeRuntime\n __scenario?: Devtools['scenario']\n __scenarioCheck?: Devtools['check']\n __scenarioList?: unknown\n __devtools?: Devtools\n }\n}\n\nconst noop = () => {}\n\nconst CSS = `\n.gd-pos{position:fixed;left:50%;top:calc(14px + env(safe-area-inset-top,0px));transform:translateX(-50%);background:var(--panel,rgba(12,14,14,.72));color:var(--ink,#e6e3d6);border:1px solid var(--line,rgba(230,227,214,.18));padding:5px 10px;font:12px var(--f-mono,ui-monospace,monospace);font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none;z-index:3;max-width:calc(100vw - 32px);overflow:hidden;text-overflow:ellipsis}\n.gd-pos b{color:var(--accent,#e3c341);font-weight:600} .gd-pos.flying{border-color:var(--accent,#e3c341)}\n.gd-panel{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:min(520px,calc(100vw - 32px));max-height:calc(100% - 48px);overflow:auto;background:rgba(14,16,16,.96);color:var(--ink,#e6e3d6);border:1px solid var(--accent,#e3c341);padding:16px;display:grid;gap:10px;z-index:9;font:13px var(--f-mono,ui-monospace,monospace)}\n.gd-panel h2{font-family:var(--f-display,inherit);font-weight:800;font-size:26px;margin:0;letter-spacing:.02em}\n.gd-panel textarea,.gd-panel select{font:13px var(--f-mono,ui-monospace,monospace);background:#0b0d0d;color:inherit;border:1px solid var(--line,#444);padding:8px;width:100%}\n.gd-panel textarea{min-height:84px;resize:vertical} .gd-panel select{width:auto;padding:6px}\n.gd-panel button{font:600 13px var(--f-mono,ui-monospace,monospace);padding:7px 12px;cursor:pointer}\n.gd-row{display:flex;gap:6px;flex-wrap:wrap} .gd-sub{color:var(--muted,#9a9a8c);font-size:12px;margin:0}\n.gd-mark{display:grid;grid-template-columns:1fr auto;gap:4px 10px;border-top:1px dashed var(--line,#444);padding-top:8px}\n.gd-mark .t{white-space:pre-wrap;overflow-wrap:anywhere} .gd-mark .w{color:var(--muted,#9a9a8c);font-size:11px} .gd-mark .b{grid-row:1/3;grid-column:2;display:flex;gap:6px;align-items:start}\n.gd-panel .gd-copy{min-height:90px;font-size:11px}\n.gd-labels{position:fixed;inset:0;pointer-events:none;z-index:2;overflow:hidden}\n.gd-labels div{position:absolute;left:0;top:0;transform:translate(-50%,-100%);font:11px var(--f-mono,ui-monospace,monospace);white-space:nowrap;background:rgba(10,12,12,.72);padding:1px 5px;border-left:2px solid;display:none}`\n\n/**\n * Creates the devtools: free-fly, position HUD, marks with notes, control panel, scenarios and entity labels.\n * The game plugs everything in through the options and the registration methods; see the README.\n */\nexport function create(THREE: ThreeLib, options: DevtoolsOptions = {}): Devtools {\n const S = resolveStrings(options.locale, options.strings)\n const C = {\n marksStorageKey: 'game-devtools-marks',\n collection: 'marks',\n fileName: S.fileName,\n teams: [['general', S.defaultTeam]] as Team[],\n area: (() => '') as (x: number, z: number) => string,\n time: (() => '') as () => string,\n notify: noop as (text: string, seconds?: number) => void,\n pause: noop as (paused: boolean) => void,\n position: (() => ({ x: 0, y: 0, z: 0, yaw: 0, pitch: 0 })) as () => PlayerPosition,\n bounds: { x: [-1e4, 1e4], y: [0.4, 400], z: [-1e4, 1e4] } as Bounds,\n speed: 14,\n labelsMax: 48,\n labelsDistance: 45,\n ...stripUndefined(options),\n }\n\n const dt0 = {\n toggles: [] as Array<{ id: string; label: string; get: () => boolean; set: (on: boolean) => boolean | void }>,\n actions: [] as Array<{ id: string; label: string | (() => string); fn: () => boolean | void }>,\n times: [] as Array<[string, unknown]>,\n setTime: undefined as ((value: unknown) => void) | undefined,\n placeGroups: (() => []) as () => PlaceGroup[],\n labelsFn: (() => []) as (camera: ProjectionCamera) => EntityLabel[],\n }\n const runner = createScenarioRunner()\n\n // ---- interface ----\n const css = document.createElement('style')\n css.textContent = CSS\n document.head.appendChild(css)\n const el = <K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string, parent: HTMLElement = document.body): HTMLElementTagNameMap[K] => {\n const e = document.createElement(tag)\n if (cls) e.className = cls\n parent.appendChild(e)\n return e\n }\n const posEl = el('div', 'gd-pos')\n posEl.id = 'gd-pos'\n const form = el('section', 'gd-panel')\n form.hidden = true\n form.id = 'gd-form'\n form.setAttribute('aria-label', S.markFormLabel)\n const list = el('section', 'gd-panel')\n list.hidden = true\n list.id = 'gd-list'\n list.setAttribute('aria-label', S.panelTitle)\n const labelBox = el('div', 'gd-labels')\n labelBox.id = 'gd-labels'\n const LABELS: HTMLDivElement[] = []\n for (let k = 0; k < C.labelsMax; k++) LABELS.push(el('div', '', labelBox))\n\n const dev = {\n flying: false,\n x: 0,\n y: 0,\n z: 0,\n speed: C.speed,\n hud: true,\n openPanel: null as Devtools['openPanel'],\n showLabels: false,\n db: null as any,\n marks: [] as Mark[],\n goTo: null as Devtools['goTo'],\n extras: (() => '') as () => string,\n openGroups: [0],\n } as unknown as Devtools & { openGroups: number[] }\n\n Object.defineProperties(dev, {\n scenarioList: { get: () => runner.list, enumerable: true },\n activeScenario: { get: () => runner.active, enumerable: true },\n })\n\n // ---- position ----\n dev.compass = (yaw) => compass(yaw, S.compass) // yaw 0 looks toward -z (north)\n dev.here = (): HereInfo => {\n const p = C.position()\n const [heading, degrees] = dev.compass(p.yaw)\n return {\n x: +p.x.toFixed(1),\n y: +p.y.toFixed(1),\n z: +p.z.toFixed(1),\n yaw: +p.yaw.toFixed(3),\n pitch: +p.pitch.toFixed(3),\n area: C.area(p.x, p.z),\n heading,\n degrees,\n look: Math.round((-p.pitch * 180) / Math.PI),\n time: C.time(),\n flying: dev.flying,\n }\n }\n dev.line = (m) => formatMarkLine(m, C.teams, S)\n\n // ---- free-fly: keys = { forward, strafe, up, fast } (-1..1); positive pitch looks down ----\n dev.fly = (dt, yaw, pitch, k) => {\n const sp = dev.speed * (k.fast ? 4 : 1) * dt\n const cy = Math.cos(pitch)\n const sy = Math.sin(pitch)\n const fx = -Math.sin(yaw)\n const fz = -Math.cos(yaw)\n const L = C.bounds\n dev.x += (fx * cy * k.forward - fz * k.strafe) * sp\n dev.z += (fz * cy * k.forward + fx * k.strafe) * sp\n dev.y += (-sy * k.forward + k.up) * sp\n dev.x = Math.min(L.x[1], Math.max(L.x[0], dev.x))\n dev.y = Math.min(L.y[1], Math.max(L.y[0], dev.y))\n dev.z = Math.min(L.z[1], Math.max(L.z[0], dev.z))\n }\n dev.flyCamera = (cam, yaw, pitch) => {\n const cy = Math.cos(pitch)\n cam.position.set(dev.x, dev.y, dev.z)\n cam.lookAt(dev.x - Math.sin(yaw) * cy, dev.y - Math.sin(pitch), dev.z - Math.cos(yaw) * cy)\n }\n const onWheel = (e: WheelEvent) => {\n if (dev.flying && !dev.openPanel) dev.speed = Math.min(120, Math.max(2, dev.speed * (e.deltaY > 0 ? 0.8 : 1.25)))\n }\n window.addEventListener('wheel', onWheel, { passive: true })\n\n // ---- what the game offers in the panel ----\n dev.toggle = (id, label, get, set) => {\n dt0.toggles.push({ id, label, get, set })\n return dev\n }\n dev.action = (id, label, fn) => {\n dt0.actions.push({ id, label, fn })\n return dev\n }\n dev.timesOfDay = (l, set) => {\n dt0.times = l\n dt0.setTime = set\n return dev\n } // l: [[label, value]]\n dev.places = (fn) => {\n dt0.placeGroups = fn\n return dev\n } // fn() -> [[group, [[name, go()]]]]\n dev.labelsFor = (fn) => {\n dt0.labelsFn = fn\n return dev\n } // fn(camera) -> [{x,y,z,text,color}] already sorted by proximity\n\n // ---- test scenarios: { id, ... } + apply(s) + check(s) -> { criterion: { ok, note } } ----\n dev.scenarios = (l, apply, check) => {\n runner.set(l, apply as never, check as never)\n return dev\n }\n dev.scenario = (id) => runner.run(id)\n dev.check = (id) => runner.check(id)\n\n // ---- marks: the artifact database when there is one (Claude reads it), otherwise the browser ----\n const lsRead = (): Mark[] => {\n try {\n return JSON.parse(localStorage.getItem(C.marksStorageKey) || '[]')\n } catch (e) {\n return []\n }\n }\n const lsWrite = (a: Mark[]) => {\n try {\n localStorage.setItem(C.marksStorageKey, JSON.stringify(a))\n } catch (e) {}\n }\n dev.marks = lsRead()\n ;(async () => {\n try {\n if (!window.claude || !window.claude.use) return\n const db = await window.claude.use('db')\n if (!db) return\n dev.db = db\n db.collection(C.collection).onSnapshot(\n (s: any) => {\n dev.marks = s.docs.map((d: any) => ({ id: d.id, ...d.data() }))\n if (dev.openPanel === 'list') render()\n },\n () => {},\n )\n } catch (e) {}\n })()\n async function saveMark(m: Mark) {\n if (dev.db) {\n try {\n const u = await window.claude!.use('user')\n if (u) m.by = await u.id()\n } catch (e) {}\n try {\n await dev.db.collection(C.collection).add(m)\n C.notify(S.savedServerMsg, 2)\n return\n } catch (e) {\n C.notify(S.serverFailMsg, 3)\n }\n }\n m.id = 'm' + m.at\n const a = lsRead()\n a.push(m)\n lsWrite(a)\n dev.marks = a\n C.notify(S.savedBrowserMsg, 2.5)\n }\n async function deleteMark(id: string) {\n if (dev.db && !id.startsWith('m')) {\n try {\n await dev.db.collection(C.collection).doc(id).delete()\n } catch (e) {}\n return\n }\n const a = lsRead().filter((m) => m.id !== id)\n lsWrite(a)\n dev.marks = a\n render()\n }\n dev.goTo = null // the game sets it: (x, y, z, yaw, pitch) => void\n\n // ---- panels ----\n let here0: HereInfo | null = null\n dev.open = (which) => {\n if (dev.openPanel) return\n dev.openPanel = which\n C.pause(true)\n if (which === 'form') {\n here0 = dev.here()\n form.innerHTML = `<h2>${esc(S.markHereTitle)}</h2><p class=\"gd-sub\">${esc(`${here0.area} · x ${here0.x} y ${here0.y} z ${here0.z} · ${S.lookingAt} ${here0.heading} · ${here0.time}`)}</p>\n<label class=\"gd-sub\">${esc(S.teamLabel)} <select id=\"gd-team\">${C.teams.map(([k, n]) => `<option value=\"${esc(k)}\">${esc(n)}</option>`).join('')}</select></label>\n<textarea id=\"gd-note\" placeholder=\"${esc(S.notePlaceholder)}\"></textarea>\n<div class=\"gd-row\"><button type=\"button\" data-f=\"save\">${esc(S.saveButton)}</button><button type=\"button\" class=\"ghost\" data-f=\"close\">${esc(S.cancelButton)}</button></div>`\n form.hidden = false\n setTimeout(() => form.querySelector('textarea')!.focus(), 30)\n } else {\n render()\n list.hidden = false\n }\n }\n dev.close = () => {\n if (!dev.openPanel) return\n dev.openPanel = null\n form.hidden = list.hidden = true\n C.pause(false)\n }\n form.addEventListener('keydown', (e) => {\n e.stopPropagation()\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n form.querySelector<HTMLButtonElement>('[data-f=\"save\"]')!.click()\n }\n if (e.key === 'Escape') {\n e.preventDefault()\n dev.close()\n }\n })\n form.addEventListener('click', (e) => {\n const b = (e.target as Element).closest('button')\n if (!b) return\n if (b.dataset.f === 'save')\n saveMark({\n ...here0!,\n team: form.querySelector<HTMLSelectElement>('#gd-team')!.value,\n text: form.querySelector<HTMLTextAreaElement>('#gd-note')!.value.trim(),\n at: Date.now(),\n } as Mark)\n dev.close()\n })\n let places: PlaceGroup[] = []\n function render() {\n const ms = sortMarks(dev.marks)\n places = dt0.placeGroups()\n const toggleBtn = (c: (typeof dt0.toggles)[number]) => {\n const on = !!c.get()\n return `<button type=\"button\" class=\"${on ? '' : 'ghost'}\" data-toggle=\"${esc(c.id)}\">${esc(c.label)}: ${on ? S.yes : S.no}</button>`\n }\n list.innerHTML = `<h2>${esc(S.panelTitle)}</h2>\n<div class=\"gd-row\">${dt0.toggles.map(toggleBtn).join('')}</div>\n${dt0.actions.length ? `<div class=\"gd-row\">${dt0.actions.map((a) => `<button type=\"button\" class=\"ghost\" data-action=\"${esc(a.id)}\">${esc(typeof a.label === 'function' ? a.label() : a.label)}</button>`).join('')}</div>` : ''}\n<h2>${esc(S.placesTitle)}</h2>\n${dt0.times.length ? `<div class=\"gd-row\">${dt0.times.map((h, i) => `<button type=\"button\" class=\"ghost\" data-time=\"${i}\">${esc(h[0])}</button>`).join('')}</div>` : ''}\n${places.map(([n, ps], i) => `<details data-g=\"${i}\"${dev.openGroups.includes(i) ? ' open' : ''}><summary class=\"gd-sub\">${esc(n)} (${ps.length})</summary><div class=\"gd-row\" style=\"margin-top:6px\">${ps.map((p, j) => `<button type=\"button\" class=\"ghost\" data-place=\"${i}:${j}\">${esc(p[0])}</button>`).join('')}</div></details>`).join('')}\n<h2>${esc(S.marksTitle(ms.length))}</h2>\n<p class=\"gd-sub\">${dev.db ? S.savedOnServer : S.savedInBrowser}</p>\n${ms.map((m) => `<div class=\"gd-mark\"><div class=\"t\">${esc(m.text || S.noNote)}</div><div class=\"w\">${esc(dev.line({ ...m, text: '' }))}</div><div class=\"b\"><button type=\"button\" data-goto=\"${esc(m.id)}\">${esc(S.goButton)}</button><button type=\"button\" class=\"ghost\" data-delete=\"${esc(m.id)}\">${esc(S.deleteButton)}</button></div></div>`).join('') || `<p class=\"gd-sub\">${esc(S.noMarks)}</p>`}\n<textarea class=\"gd-copy\" id=\"gd-copy\" readonly>${esc(ms.map(dev.line).join('\\n'))}</textarea>\n<div class=\"gd-row\"><button type=\"button\" data-f=\"copy\">${esc(S.copyAll)}</button>${dev.db ? '' : `<button type=\"button\" class=\"ghost\" data-f=\"download\" id=\"gd-download\">${esc(S.downloadFile)}</button>`}<button type=\"button\" class=\"ghost\" data-f=\"close\">${esc(S.closeButton)}</button></div>`\n }\n dev.render = render\n list.addEventListener(\n 'toggle',\n (e) => {\n const d = (e.target as Element).closest('details')\n if (!d) return\n const i = +d.dataset.g!\n const a = new Set(dev.openGroups)\n if (d.open) a.add(i)\n else a.delete(i)\n dev.openGroups = [...a]\n },\n true,\n )\n list.addEventListener('click', async (e) => {\n const b = (e.target as Element).closest('button')\n if (!b) return\n const d = b.dataset\n if (d.f === 'close') return dev.close()\n if (d.f === 'download') {\n const a = document.createElement('a')\n a.href = URL.createObjectURL(new Blob([serializeMarks(dev.marks, C.teams, S).file], { type: 'text/plain' }))\n a.download = C.fileName\n document.body.appendChild(a)\n a.click()\n a.remove()\n return\n }\n if (d.f === 'copy') {\n const t = list.querySelector<HTMLTextAreaElement>('#gd-copy')!\n try {\n await navigator.clipboard.writeText(t.value)\n b.textContent = S.copied\n } catch (err) {\n t.select()\n b.textContent = S.copySelected\n }\n return\n }\n if (d.place) {\n const [i, j] = d.place.split(':').map(Number)\n dev.close()\n places[i][1][j][1]()\n return\n }\n if (d.toggle) {\n const c = dt0.toggles.find((c) => c.id === d.toggle)!\n const close = c.set(!c.get())\n return close ? dev.close() : render()\n }\n if (d.action) {\n const a = dt0.actions.find((a) => a.id === d.action)!\n const keep = a.fn()\n return keep ? render() : dev.close()\n }\n if (d.time) {\n dt0.setTime!(dt0.times[+d.time][1])\n return render()\n }\n if (d.goto) {\n const m = dev.marks.find((m) => m.id === d.goto)\n if (m && dev.goTo) {\n dev.close()\n dev.goTo(m.x, m.y, m.z, m.yaw, m.pitch)\n }\n return\n }\n if (d.delete) deleteMark(d.delete)\n })\n const onKeydown = (e: KeyboardEvent) => {\n if (dev.openPanel === 'list' && e.key === 'Escape' && !e.defaultPrevented) dev.close()\n }\n window.addEventListener('keydown', onKeydown)\n\n // ---- every frame: position (10 times per second) and labels ----\n let acc = 0\n const _v = new THREE.Vector3()\n dev.extras = () => '' // the game may append text to the position line\n dev.update = (dt, cam, visible = true) => {\n // labels\n let k = 0\n if (dev.showLabels && visible) {\n const W = innerWidth\n const H = innerHeight\n for (const t of dt0.labelsFn(cam)) {\n if (k >= LABELS.length) break\n _v.set(t.x, t.y, t.z).project(cam)\n if (_v.z > 1 || _v.x < -1.05 || _v.x > 1.05 || _v.y < -1.05 || _v.y > 1.05) continue\n const d = LABELS[k++]\n if (d.textContent !== t.text) d.textContent = t.text\n d.style.borderColor = d.style.color = t.color || '#9fd0ff'\n d.style.left = (((_v.x + 1) / 2) * W).toFixed(0) + 'px'\n d.style.top = (((1 - _v.y) / 2) * H).toFixed(0) + 'px'\n d.style.display = ''\n }\n }\n for (; k < LABELS.length; k++) if (LABELS[k].style.display !== 'none') LABELS[k].style.display = 'none'\n posEl.hidden = !dev.hud || !visible\n posEl.classList.toggle('flying', dev.flying)\n if ((acc += Math.max(0, dt || 0)) < 0.1) return // the first frame may come with a negative dt\n acc = 0\n const a = dev.here()\n posEl.innerHTML = `<b>${esc(a.area)}</b> · x ${a.x} · y ${a.y} · z ${a.z} · ${a.heading} ${a.degrees}° · ${S.hudLook} ${a.look}° · ${esc(a.time)}${dev.flying ? ` · <b>${S.hudFlight(dev.speed.toFixed(0))}</b>` : ''}${dev.extras()} · ${S.hudMarks(dev.marks.length)}`\n }\n // for automated browser tests (Playwright): window.__scenario(id), __scenarioCheck(id), __scenarioList, __devtools\n dev.expose = () => {\n window.__scenario = dev.scenario\n window.__scenarioCheck = dev.check\n window.__scenarioList = runner.list\n window.__devtools = dev\n }\n dev.dispose = () => {\n window.removeEventListener('wheel', onWheel)\n window.removeEventListener('keydown', onKeydown)\n css.remove()\n posEl.remove()\n form.remove()\n list.remove()\n labelBox.remove()\n }\n return dev\n}\n\n// `{ ...defaults, ...options }` must not let an explicit `undefined` erase a default\nfunction stripUndefined<T extends object>(o: T): Partial<T> {\n return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined)) as Partial<T>\n}\n"],"mappings":"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","names":["c","a","m"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adatechnology/game-devtools",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "In-game test tooling for three.js games: free-fly mode, position HUD, notes and marks, control panel, scenario runner and entity labels. Knows nothing about any game.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"three",
|
|
8
|
+
"threejs",
|
|
9
|
+
"game",
|
|
10
|
+
"devtools",
|
|
11
|
+
"debug",
|
|
12
|
+
"free-fly",
|
|
13
|
+
"playtest"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/Andersonfrfilho/adatechnology-game-kit.git",
|
|
18
|
+
"directory": "packages/game-devtools"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"module": "dist/index.js",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"unpkg": "dist/index.global.js",
|
|
28
|
+
"jsdelivr": "dist/index.global.js",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./global": "./dist/index.global.js"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"MIGRATION.md"
|
|
40
|
+
],
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"three": "^0.160.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.7",
|
|
46
|
+
"@types/three": "^0.160.0",
|
|
47
|
+
"happy-dom": "^17.4.4",
|
|
48
|
+
"three": "^0.160.1",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
50
|
+
"typescript": "^5.7.3",
|
|
51
|
+
"vitest": "^3.2.4"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
56
|
+
"test": "vitest run"
|
|
57
|
+
}
|
|
6
58
|
}
|