{"_id":"@astralume/keyboard","name":"@astralume/keyboard","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@astralume/keyboard","version":"0.1.0","publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"description":"A scalable Vue 3 visual keyboard component with themes, key states, holding hints and animation APIs.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./style.css":"./dist/style.css"},"sideEffects":["*.css","dist/style.css"],"keywords":["vue","vue3","keyboard","visual-keyboard","virtual-keyboard"],"scripts":{"dev":"vite","build":"pnpm type-check && pnpm build:lib && pnpm build:types","build:lib":"vite build","build:types":"vue-tsc -p tsconfig.lib.json","build:demo":"vue-tsc --noEmit -p tsconfig.app.json && vite build --config vite.demo.config.ts","type-check":"vue-tsc --noEmit -p tsconfig.app.json","lint":"eslint .","format":"prettier . --write","format:check":"prettier . --check","preview":"vite preview --outDir dist-demo","prepublishOnly":"pnpm lint && pnpm format:check && pnpm build"},"peerDependencies":{"vue":"^3.5.32"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^25.6.0","@vitejs/plugin-vue":"^6.0.6","eslint":"^10.2.1","eslint-config-prettier":"^10.1.8","eslint-plugin-vue":"^10.9.0","globals":"^17.5.0","prettier":"^3.8.3","typescript":"^6.0.3","typescript-eslint":"^8.59.1","vite":"^8.0.10","vue-eslint-parser":"^10.4.0","vue":"^3.5.32","vue-tsc":"^3.2.7"},"_id":"@astralume/keyboard@0.1.0","gitHead":"1e5541b30b501f76fa790318194890d51a91cfa1","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-YRUoOl5TfJKZ5HL3SU5hMJ4d3Bk29n5RlDAkKBuuffyjJ3kUYjsh8eTuzM1tadj9VJnlPB58wJUieMwfC6OWpQ==","shasum":"917a046c2793f90857e74ef93fba7588bdd7532b","tarball":"https://registry.npmjs.org/@astralume/keyboard/-/keyboard-0.1.0.tgz","fileCount":33,"unpackedSize":189411,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH3CeaZJH47wgBtViJct2n6AAdJKGZDHtdO0AiHRb3pgAiEA9EZHLb2Hg4KLXtejSt+RZrmRCIGrCzPI5ew9ZLxMzik="}]},"_npmUser":{"name":"astralume","email":"cxxxdsm314@qq.com"},"directories":{},"maintainers":[{"name":"astralume","email":"cxxxdsm314@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/keyboard_0.1.0_1777559096777_0.0994620838968372"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-30T14:24:56.657Z","0.1.0":"2026-04-30T14:24:56.921Z","modified":"2026-04-30T14:24:57.174Z"},"maintainers":[{"name":"astralume","email":"cxxxdsm314@qq.com"}],"description":"A scalable Vue 3 visual keyboard component with themes, key states, holding hints and animation APIs.","keywords":["vue","vue3","keyboard","visual-keyboard","virtual-keyboard"],"readme":"# @astralume/keyboard\n\n> English documentation is available in the second half of this README.\n\n`@astralume/keyboard` 是一个 Vue 3 可视化键盘组件。它可以展示高保真键盘布局，监听真实键盘和鼠标输入，显示按下、成功、失败、教学提示、锁定按下、时间轴动画和波纹动画等状态。\n\n组件源码位于 `src/lib`。本仓库的演示页面位于 `src/demo`，不会进入 npm 包。npm 包只发布 `dist` 内的组件产物。\n\n## 功能特性\n\n- Vue 3 组件，支持 TypeScript 类型。\n- 支持紧凑键盘、合并全键盘、分区全键盘三种布局。\n- 支持整体缩放，通过 `width`、`keySize`、`gapX`、`gapY` 控制比例。\n- 支持真实键盘输入、鼠标/触摸输入和按键事件抛出。\n- 支持普通全面接管和增强接管。增强接管会尝试使用 Fullscreen API 与 Keyboard Lock API。\n- 支持 holding、locked、success、error、自定义状态。\n- 支持 timeline 脚本动画、蛇形波纹动画、typed-array 高频帧渲染。\n- 支持主题、CSS 变量、自定义 class、自定义单键样式。\n\n## 安装\n\n```bash\npnpm add @astralume/keyboard\n```\n\n也可以使用 npm 或 yarn：\n\n```bash\nnpm install @astralume/keyboard\nyarn add @astralume/keyboard\n```\n\n## 快速开始\n\n```vue\n<script setup lang=\"ts\">\nimport VisualKeyboard from '@astralume/keyboard'\nimport '@astralume/keyboard/style.css'\n</script>\n\n<template>\n  <VisualKeyboard />\n</template>\n```\n\n## 推荐用法\n\n大多数情况下，只需要传入少量 `options`。组件会把缺失项与默认配置合并。\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport VisualKeyboard, { type PartialDeep, type KeyboardOptions } from '@astralume/keyboard'\nimport '@astralume/keyboard/style.css'\n\nconst keyboardOptions = computed<PartialDeep<KeyboardOptions>>(() => ({\n  layout: {\n    mode: 'compact',\n    width: 960,\n    keySize: 56,\n    gapX: 4,\n    gapY: 4,\n  },\n  appearance: {\n    theme: 'demo2',\n  },\n  behavior: {\n    defaultPressState: 'success',\n    pointerBehavior: 'press',\n  },\n}))\n</script>\n\n<template>\n  <VisualKeyboard :options=\"keyboardOptions\" />\n</template>\n```\n\n## 完整示例\n\n```vue\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport VisualKeyboard, {\n  type KeyEventPayload,\n  type KeyboardOptions,\n  type StateDefinitionMap,\n  type TimelineItem,\n} from '@astralume/keyboard'\nimport '@astralume/keyboard/style.css'\n\nconst keyboardRef = ref<InstanceType<typeof VisualKeyboard> | null>(null)\n\nconst options: KeyboardOptions = {\n  layout: {\n    mode: 'compact',\n    width: 960,\n    keySize: 56,\n    gapX: 4,\n    gapY: 4,\n    blockGapScale: 4,\n    paddingScale: 2.5,\n    topRowHeight: 'compact',\n    splitRatios: [0.5, 0.44, 0.4],\n  },\n  appearance: {\n    theme: 'demo2',\n    keyRadiusPercent: 25,\n    topKeyRadiusPercent: 25,\n    boardClass: '',\n    keyClass: '',\n    boardStyleVars: {},\n    keyStyleVars: {},\n    keyClassMap: {},\n    keyStyleVarsMap: {},\n  },\n  behavior: {\n    captureAllKeys: false,\n    enhancedCapture: false,\n    pointerBehavior: 'press',\n    defaultPressState: 'success',\n    renderMode: 'vue',\n  },\n  states: {\n    holdingState: 'holding',\n    lockedState: 'default',\n  },\n}\n\nconst stateDefinitions: StateDefinitionMap = {\n  teaching: {\n    styleVars: {\n      '--vk-key-bg': '#e9ddff',\n      '--vk-key-color': '#4c2c85',\n    },\n  },\n}\n\nconst timeline: TimelineItem[] = [\n  { keyId: 'KeyH', at: 0, duration: 120, visualState: 'success', pressed: true },\n  { keyId: 'KeyI', at: 150, duration: 120, visualState: 'success', pressed: true },\n]\n\nfunction handleKeyEvent(payload: KeyEventPayload) {\n  console.log(payload.keyId, payload.phase)\n}\n\nfunction playWave() {\n  keyboardRef.value?.playWave({\n    tailLength: 7,\n    speed: 1,\n    maxActiveWaves: 8,\n  })\n}\n</script>\n\n<template>\n  <VisualKeyboard\n    ref=\"keyboardRef\"\n    :options=\"options\"\n    :holding-keys=\"['KeyA', 'KeyS']\"\n    :locked-keys=\"['Escape']\"\n    :state-definitions=\"stateDefinitions\"\n    :timeline=\"timeline\"\n    :timeline-playing=\"false\"\n    @key-event=\"handleKeyEvent\"\n  />\n\n  <button type=\"button\" @click=\"playWave\">播放波纹</button>\n</template>\n```\n\n## Props\n\n| Prop               | 类型                            | 默认值  | 说明                                                                        |\n| ------------------ | ------------------------------- | ------- | --------------------------------------------------------------------------- |\n| `options`          | `PartialDeep<KeyboardOptions>`  | `{}`    | 键盘配置。可以只传局部配置，组件会与默认配置合并。                          |\n| `holdingKeys`      | `string[]`                      | `[]`    | 教学提示按键。可以传 `keyId`，例如 `KeyA`，也可以传部分显示文本，例如 `A`。 |\n| `lockedKeys`       | `string[]`                      | `[]`    | 持续按下的按键。适合展示“某个键保持按下”的状态。                            |\n| `keyStateMap`      | `Record<string, KeyStateInput>` | `{}`    | 外部直接指定某些按键的状态。key 可以是 `keyId` 或显示文本。                 |\n| `stateDefinitions` | `StateDefinitionMap`            | `{}`    | 自定义状态定义。用于把状态名映射成 class、CSS 变量和 pressed 覆盖。         |\n| `resolveKeyView`   | `(payload) => KeyStateInput`    | `null`  | 渲染前的状态解析钩子。适合把业务判断映射成状态。                            |\n| `plugins`          | `VisualKeyboardPlugin[]`        | `[]`    | 插件列表。插件可以处理输入事件或参与状态解析。                              |\n| `timeline`         | `TimelineItem[]`                | `[]`    | 声明式时间轴动画。                                                          |\n| `timelinePlaying`  | `boolean`                       | `false` | 是否播放 `timeline`。                                                       |\n\n## KeyboardOptions\n\n`KeyboardOptions` 分为四组：`layout`、`appearance`、`behavior`、`states`。\n\n### layout\n\n| 字段            | 类型                                 | 默认值             | 作用                                                                                                        |\n| --------------- | ------------------------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------- |\n| `mode`          | `'compact' \\| 'full' \\| 'separated'` | `'compact'`        | 布局模式。`compact` 是主键盘，`full` 是主键盘加右侧合并区域，`separated` 是主键盘、导航区和数字区分离显示。 |\n| `width`         | `number`                             | `960`              | 键盘最终显示宽度，单位 px。组件会按这个宽度整体缩放。                                                       |\n| `keySize`       | `number`                             | `56`               | 标准按键边长，单位 px。布局内部以它作为基准计算。                                                           |\n| `gapX`          | `number`                             | `4`                | 按键横向间隙，单位 px。                                                                                     |\n| `gapY`          | `number`                             | `4`                | 按键纵向间隙，单位 px。                                                                                     |\n| `blockGapScale` | `number`                             | `4`                | 全键盘模式下，不同键盘区之间的横向间距倍数。实际间距为 `gapX * blockGapScale`。                             |\n| `paddingScale`  | `number`                             | `2.5`              | 键盘背景内边距倍数。实际内边距为 `gapX/gapY * paddingScale`。                                               |\n| `topRowHeight`  | `'compact' \\| 'full'`                | `'compact'`        | 顶部功能键高度。`compact` 约为标准键高的三分之二，`full` 等于标准键高。                                     |\n| `splitRatios`   | `[number, number, number]`           | `[0.5, 0.44, 0.4]` | 动态宽度按键比例。依次控制 `Tab/反斜杠`、`Caps/Enter`、`左 Shift/右 Shift`。值会限制在 0 到 1。             |\n\n### appearance\n\n| 字段                  | 类型                                     | 默认值    | 作用                                                                  |\n| --------------------- | ---------------------------------------- | --------- | --------------------------------------------------------------------- |\n| `theme`               | `string`                                 | `'demo2'` | 主题名称。内置主题包括 `demo1`、`demo2`、`demo1-dark`、`demo2-dark`。 |\n| `keyRadiusPercent`    | `number`                                 | `25`      | 普通按键圆角百分比。0 表示直角，50 表示最大圆角。                     |\n| `topKeyRadiusPercent` | `number`                                 | `25`      | 顶部功能键圆角百分比。                                                |\n| `boardClass`          | `string`                                 | `''`      | 追加到键盘背景上的 class。                                            |\n| `keyClass`            | `string`                                 | `''`      | 追加到所有按键上的 class。                                            |\n| `boardStyleVars`      | `Record<string, string>`                 | `{}`      | 写到键盘背景上的 CSS 变量或样式。                                     |\n| `keyStyleVars`        | `Record<string, string>`                 | `{}`      | 写到所有按键上的 CSS 变量或样式。                                     |\n| `keyClassMap`         | `Record<string, string \\| string[]>`     | `{}`      | 给单个按键追加 class。key 可以是 `keyId` 或显示文本。                 |\n| `keyStyleVarsMap`     | `Record<string, Record<string, string>>` | `{}`      | 给单个按键追加 CSS 变量或样式。key 可以是 `keyId` 或显示文本。        |\n\n### behavior\n\n| 字段                | 类型                                                                      | 默认值      | 作用                                                                                                                                     |\n| ------------------- | ------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- |\n| `captureAllKeys`    | `boolean`                                                                 | `false`     | 是否阻止可捕获键盘事件的默认行为和传播。浏览器保留快捷键不一定能被普通页面拦截。                                                         |\n| `enhancedCapture`   | `boolean`                                                                 | `false`     | 是否启用增强接管。开启后会在用户输入时尝试 Fullscreen API 和 Keyboard Lock API。                                                         |\n| `pointerBehavior`   | `'press' \\| 'emit' \\| 'none' \\| 'toggle' \\| 'lock' \\| 'custom' \\| string` | `'press'`   | 鼠标/触摸行为。`press` 临时按下，`emit` 只抛事件，`none` 忽略状态，`toggle` 点击切换，`lock` 点击后保持按下，`custom` 留给外部逻辑处理。 |\n| `defaultPressState` | `string`                                                                  | `'success'` | 真实键盘或鼠标按下时默认触发的视觉状态。可设为 `none` 表示不显示状态色，设为 `default` 表示只显示主题原本按下态。                        |\n| `renderMode`        | `'vue' \\| 'hybrid' \\| 'frame'`                                            | `'vue'`     | 渲染模式。`vue` 适合普通使用，`hybrid` 和 `frame` 适合更高频动画。                                                                       |\n\n### states\n\n| 字段           | 类型     | 默认值      | 作用                             |\n| -------------- | -------- | ----------- | -------------------------------- |\n| `holdingState` | `string` | `'holding'` | `holdingKeys` 使用的视觉状态名。 |\n| `lockedState`  | `string` | `'default'` | `lockedKeys` 使用的视觉状态名。  |\n\n## 状态系统\n\n状态可以是字符串，也可以是对象。\n\n```ts\ntype KeyStateInput = string | KeyLayerState | null | undefined\n```\n\n`KeyLayerState` 字段：\n\n| 字段          | 类型                     | 说明                                                                |\n| ------------- | ------------------------ | ------------------------------------------------------------------- |\n| `pressed`     | `boolean`                | 是否显示按下形态。                                                  |\n| `visualState` | `string`                 | 视觉状态名，例如 `success`、`error`、`holding`、`wave`。            |\n| `priority`    | `number`                 | 状态优先级。数值越大越晚合成，越容易覆盖低优先级状态。              |\n| `className`   | `string \\| string[]`     | 附加 class。                                                        |\n| `styleVars`   | `Record<string, string>` | 附加 CSS 变量或样式。它会略高于同层默认状态定义，适合逐键动画颜色。 |\n\n### 内置状态\n\n| 状态名    | 说明                                 |\n| --------- | ------------------------------------ |\n| `success` | 成功状态，默认是绿色系。             |\n| `error`   | 失败状态，默认是红色系。             |\n| `holding` | 教学提示状态。                       |\n| `wave`    | 波纹动画状态。                       |\n| `default` | 不追加视觉状态，但可以保留按下形态。 |\n| `none`    | 不渲染视觉状态。                     |\n\n### 自定义状态\n\n```ts\nconst stateDefinitions = {\n  warning: {\n    styleVars: {\n      '--vk-key-bg': '#fff1b8',\n      '--vk-key-color': '#705600',\n    },\n  },\n  pressedBlue: {\n    pressed: true,\n    styleVars: {\n      '--vk-key-bg': '#dbeafe',\n      '--vk-key-color': '#1d4ed8',\n    },\n  },\n}\n```\n\n## 事件\n\n组件会抛出 `key-event`。\n\n```vue\n<VisualKeyboard @key-event=\"handleKeyEvent\" />\n```\n\n`KeyEventPayload` 字段：\n\n| 字段          | 类型            | 说明                                          |\n| ------------- | --------------- | --------------------------------------------- |\n| `keyId`       | `string`        | 标准按键 id，例如 `KeyA`、`Escape`、`Space`。 |\n| `label`       | `string`        | 按键显示文本。                                |\n| `codes`       | `number[]`      | 兼容旧 `keyCode` 的数字列表。                 |\n| `source`      | `string`        | 输入来源，例如 `physical` 或 `pointer`。      |\n| `phase`       | `string`        | 输入阶段，例如 `down`、`up`、`cancel`。       |\n| `nativeEvent` | `Event \\| null` | 原生事件。                                    |\n| `repeat`      | `boolean`       | 是否是键盘 repeat。                           |\n| `timestamp`   | `number`        | 事件时间戳。                                  |\n\n## 命令式 API\n\n通过 `ref` 获取组件实例：\n\n```ts\nconst keyboardRef = ref<InstanceType<typeof VisualKeyboard> | null>(null)\n\nkeyboardRef.value?.playWave()\n```\n\n| 方法                                      | 说明                                       |\n| ----------------------------------------- | ------------------------------------------ |\n| `requestEnhancedCapture()`                | 手动请求增强接管。浏览器通常需要用户手势。 |\n| `releaseEnhancedCapture()`                | 释放 Keyboard Lock 等增强接管状态。        |\n| `getVisibleKeys()`                        | 获取当前可见交互键列表。                   |\n| `setLayerState(layerName, keyRef, state)` | 设置某一层中的单个按键状态。               |\n| `setLayerStates(layerName, changes)`      | 批量设置某一层中的按键状态。               |\n| `clearLayer(layerName?)`                  | 清理指定状态层；不传时清空所有状态层。     |\n| `playTimeline(items, options?)`           | 播放脚本化时间轴。                         |\n| `pauseTimeline(target?)`                  | 暂停时间轴。                               |\n| `resumeTimeline(target?)`                 | 恢复时间轴。                               |\n| `seekTimeline(time, target?)`             | 跳转时间轴到指定毫秒。                     |\n| `stopTimeline(target?, options?)`         | 停止时间轴。                               |\n| `playWave(options?)`                      | 播放蛇形波纹动画。                         |\n| `startFrameRenderer(source, options?)`    | 启动 typed-array 高频帧渲染器。            |\n| `stopFrameRenderer(clearFrameLayer?)`     | 停止 typed-array 高频帧渲染器。            |\n| `clearTransientActiveKeys()`              | 清理临时按下态，适合页面失焦后手动兜底。   |\n\n## 时间轴动画\n\n```ts\nkeyboardRef.value?.playTimeline(\n  [\n    { keyId: 'KeyH', at: 0, duration: 120, visualState: 'success', pressed: true },\n    { keyId: 'KeyI', at: 150, duration: 120, visualState: 'success', pressed: true },\n  ],\n  {\n    layerName: 'typing',\n    autoClear: true,\n    loop: false,\n  },\n)\n```\n\n`TimelineItem` 字段：\n\n| 字段          | 类型                      | 说明                             |\n| ------------- | ------------------------- | -------------------------------- |\n| `keyId`       | `string`                  | 目标按键 id。                    |\n| `key`         | `string`                  | `keyId` 的兼容别名。             |\n| `at`          | `number`                  | 事件开始时间，单位毫秒。         |\n| `start`       | `number`                  | `at` 的兼容别名。                |\n| `action`      | `string`                  | `set` 或 `clear`。默认是 `set`。 |\n| `state`       | `string \\| KeyLayerState` | 要写入的状态。                   |\n| `pressed`     | `boolean`                 | 是否显示按下形态。               |\n| `visualState` | `string`                  | 视觉状态名。                     |\n| `priority`    | `number`                  | 事件优先级。                     |\n| `className`   | `string \\| string[]`      | 附加 class。                     |\n| `styleVars`   | `Record<string, string>`  | 附加 CSS 变量或样式。            |\n| `duration`    | `number`                  | 持续时间，结束后会自动 clear。   |\n\n## 波纹动画\n\n`playWave` 默认按视觉行蛇形播放：第一行从左到右，第二行从右到左，依次交替。蛇头颜色较深，尾巴逐渐变浅。\n\n```ts\nkeyboardRef.value?.playWave({\n  speed: 1,\n  tailLength: 7,\n  maxActiveWaves: 8,\n  headColor: '#0a2644',\n  tailColor: '#f4faff',\n})\n```\n\n`WaveOptions` 常用字段：\n\n| 字段             | 类型                              | 默认值    | 说明                                         |\n| ---------------- | --------------------------------- | --------- | -------------------------------------------- |\n| `speed`          | `number`                          | `1`       | 播放速度倍率。越大越快。                     |\n| `step`           | `number`                          | `34`      | 每步间隔，单位毫秒，会受 `speed` 影响。      |\n| `tailLength`     | `number`                          | `7`       | 蛇身长度，也就是同一时间最多显示的尾巴段数。 |\n| `headColor`      | `string`                          | `#0a2644` | 蛇头背景色。                                 |\n| `tailColor`      | `string`                          | `#f4faff` | 尾巴末端背景色。                             |\n| `headTextColor`  | `string`                          | `#f6fbff` | 蛇头文字色。                                 |\n| `tailTextColor`  | `string`                          | `#1d4a70` | 尾巴文字色。                                 |\n| `maxActiveWaves` | `number`                          | `6`       | 最大并发波数量。重复点击时会复用波纹层。     |\n| `loop`           | `boolean \\| 'infinite' \\| number` | `false`   | 是否循环播放。                               |\n| `repeatDelay`    | `number`                          | `0`       | 每轮循环之间的延迟。                         |\n\n## 高频帧渲染\n\n如果你需要播放非常长、非常密集的动画，可以使用 `startFrameRenderer`。它使用 typed array 存储每一帧状态，并只提交发生变化的按键。\n\n```ts\nconst startedAt = performance.now()\n\nkeyboardRef.value?.startFrameRenderer((frame, now) => {\n  const elapsed = now - startedAt\n  if (elapsed > 3000) {\n    return false\n  }\n\n  frame.setKey('KeyA', {\n    pressed: true,\n    stateId: 1,\n    intensity: 1,\n  })\n})\n```\n\n## 主题与样式扩展\n\n必须引入组件样式：\n\n```ts\nimport '@astralume/keyboard/style.css'\n```\n\n内置主题：\n\n- `demo1` 亮色立体主题。\n- `demo2` 亮色简洁主题。\n- `demo1-dark` 暗色立体主题。\n- `demo2-dark` 暗色简洁主题。\n\n可以通过 CSS 变量覆盖主题：\n\n```vue\n<VisualKeyboard\n  :options=\"{\n    appearance: {\n      boardClass: 'my-keyboard',\n      keyStyleVars: {\n        '--vk-key-bg': '#111827',\n        '--vk-key-color': '#f9fafb',\n      },\n    },\n  }\"\n/>\n```\n\n```css\n.my-keyboard {\n  --vk-board-bg: #f8fafc;\n}\n```\n\n## 全面接管与增强接管\n\n`captureAllKeys` 会尽可能阻止页面内可捕获键盘事件的默认行为和传播。\n\n```ts\nconst options = {\n  behavior: {\n    captureAllKeys: true,\n  },\n}\n```\n\n`enhancedCapture` 会尝试使用 Fullscreen API 和 Keyboard Lock API。\n\n```ts\nconst options = {\n  behavior: {\n    enhancedCapture: true,\n  },\n}\n```\n\n浏览器仍可能保留系统级快捷键或部分浏览器快捷键，例如某些关闭标签、切换应用、系统截图快捷键。这不是组件可以完全绕过的限制。\n\n## 发布包边界\n\n组件代码：\n\n- `src/lib` 用于 npm 包构建。\n- `src/lib/index.ts` 是包入口。\n\n演示代码：\n\n- `src/demo` 只用于本仓库调试和展示。\n- `dist-demo` 是演示页构建产物，不会发布到 npm。\n\nnpm 包内容通过 `files` 限制，只发布：\n\n- `dist/index.js`\n- `dist/index.cjs`\n- `dist/index.d.ts`\n- `dist/style.css`\n- 相关类型声明文件\n\n## 本地开发\n\n```bash\npnpm install\npnpm dev\n```\n\n## 构建\n\n```bash\npnpm build\n```\n\n`pnpm build` 会生成库模式产物：\n\n- `dist/index.js` 是 ESM 入口。\n- `dist/index.cjs` 是 CommonJS 入口。\n- `dist/index.d.ts` 是类型入口。\n- `dist/style.css` 是组件样式。\n\n演示页单独构建：\n\n```bash\npnpm build:demo\n```\n\n## 发布前检查\n\n```bash\npnpm lint\npnpm format:check\npnpm build\npnpm pack --dry-run\n```\n\n正式发布：\n\n```bash\nnpm publish --access public\n```\n\n---\n\n# @astralume/keyboard\n\n`@astralume/keyboard` is a Vue 3 visual keyboard component. It renders a high-fidelity keyboard, listens to physical keyboard and pointer input, and supports pressed states, success/error states, teaching hints, locked keys, timeline animations, wave animations, and high-frequency frame rendering.\n\nThe component source lives in `src/lib`. The demo app lives in `src/demo` and is not published to npm. The npm package only publishes compiled files from `dist`.\n\n## Features\n\n- Vue 3 component with TypeScript types.\n- Compact keyboard, merged full keyboard, and separated full keyboard layouts.\n- Scalable layout controlled by `width`, `keySize`, `gapX`, and `gapY`.\n- Physical keyboard input, pointer input, and normalized key events.\n- Basic key capture and optional enhanced capture with Fullscreen API and Keyboard Lock API.\n- Built-in and custom visual states.\n- Timeline animation, snake-like wave animation, and typed-array frame rendering.\n- Theme presets, CSS variables, custom classes, and per-key style overrides.\n\n## Installation\n\n```bash\npnpm add @astralume/keyboard\n```\n\nOr:\n\n```bash\nnpm install @astralume/keyboard\nyarn add @astralume/keyboard\n```\n\n## Quick Start\n\n```vue\n<script setup lang=\"ts\">\nimport VisualKeyboard from '@astralume/keyboard'\nimport '@astralume/keyboard/style.css'\n</script>\n\n<template>\n  <VisualKeyboard />\n</template>\n```\n\n## Recommended Usage\n\nYou can pass only the options you need. Missing fields are merged with the default options.\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport VisualKeyboard, { type PartialDeep, type KeyboardOptions } from '@astralume/keyboard'\nimport '@astralume/keyboard/style.css'\n\nconst keyboardOptions = computed<PartialDeep<KeyboardOptions>>(() => ({\n  layout: {\n    mode: 'compact',\n    width: 960,\n    keySize: 56,\n    gapX: 4,\n    gapY: 4,\n  },\n  appearance: {\n    theme: 'demo2',\n  },\n  behavior: {\n    defaultPressState: 'success',\n    pointerBehavior: 'press',\n  },\n}))\n</script>\n\n<template>\n  <VisualKeyboard :options=\"keyboardOptions\" />\n</template>\n```\n\n## Props\n\n| Prop               | Type                            | Default | Description                                                                                     |\n| ------------------ | ------------------------------- | ------- | ----------------------------------------------------------------------------------------------- |\n| `options`          | `PartialDeep<KeyboardOptions>`  | `{}`    | Keyboard layout, appearance, behavior, and state options.                                       |\n| `holdingKeys`      | `string[]`                      | `[]`    | Keys highlighted as teaching hints. Values can be key ids such as `KeyA` or labels such as `A`. |\n| `lockedKeys`       | `string[]`                      | `[]`    | Keys that should stay visually pressed.                                                         |\n| `keyStateMap`      | `Record<string, KeyStateInput>` | `{}`    | External per-key state map. Keys can be key ids or labels.                                      |\n| `stateDefinitions` | `StateDefinitionMap`            | `{}`    | Custom state definitions.                                                                       |\n| `resolveKeyView`   | `(payload) => KeyStateInput`    | `null`  | Hook for resolving per-key visual state before rendering.                                       |\n| `plugins`          | `VisualKeyboardPlugin[]`        | `[]`    | Plugin list for input and rendering extensions.                                                 |\n| `timeline`         | `TimelineItem[]`                | `[]`    | Declarative timeline animation.                                                                 |\n| `timelinePlaying`  | `boolean`                       | `false` | Whether to play the declarative `timeline`.                                                     |\n\n## KeyboardOptions\n\n### layout\n\n| Field           | Type                                 | Default            | Description                                                               |\n| --------------- | ------------------------------------ | ------------------ | ------------------------------------------------------------------------- |\n| `mode`          | `'compact' \\| 'full' \\| 'separated'` | `'compact'`        | Layout mode.                                                              |\n| `width`         | `number`                             | `960`              | Final rendered keyboard width in pixels.                                  |\n| `keySize`       | `number`                             | `56`               | Base key size in pixels.                                                  |\n| `gapX`          | `number`                             | `4`                | Horizontal gap between keys.                                              |\n| `gapY`          | `number`                             | `4`                | Vertical gap between rows.                                                |\n| `blockGapScale` | `number`                             | `4`                | Gap multiplier between keyboard blocks.                                   |\n| `paddingScale`  | `number`                             | `2.5`              | Board padding multiplier.                                                 |\n| `topRowHeight`  | `'compact' \\| 'full'`                | `'compact'`        | Function-key row height mode.                                             |\n| `splitRatios`   | `[number, number, number]`           | `[0.5, 0.44, 0.4]` | Dynamic split ratios for Tab/Backslash, Caps/Enter, and left/right Shift. |\n\n### appearance\n\n| Field                 | Type                                     | Default   | Description                                                                |\n| --------------------- | ---------------------------------------- | --------- | -------------------------------------------------------------------------- |\n| `theme`               | `string`                                 | `'demo2'` | Theme name. Built-in themes: `demo1`, `demo2`, `demo1-dark`, `demo2-dark`. |\n| `keyRadiusPercent`    | `number`                                 | `25`      | Regular key radius percentage.                                             |\n| `topKeyRadiusPercent` | `number`                                 | `25`      | Top-row key radius percentage.                                             |\n| `boardClass`          | `string`                                 | `''`      | Extra class added to the keyboard board.                                   |\n| `keyClass`            | `string`                                 | `''`      | Extra class added to all keys.                                             |\n| `boardStyleVars`      | `Record<string, string>`                 | `{}`      | Inline CSS variables or styles for the board.                              |\n| `keyStyleVars`        | `Record<string, string>`                 | `{}`      | Inline CSS variables or styles for all keys.                               |\n| `keyClassMap`         | `Record<string, string \\| string[]>`     | `{}`      | Extra classes for specific keys.                                           |\n| `keyStyleVarsMap`     | `Record<string, Record<string, string>>` | `{}`      | Inline CSS variables or styles for specific keys.                          |\n\n### behavior\n\n| Field               | Type                                                                      | Default     | Description                                                                                   |\n| ------------------- | ------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- |\n| `captureAllKeys`    | `boolean`                                                                 | `false`     | Prevent default behavior and propagation for capturable keyboard events.                      |\n| `enhancedCapture`   | `boolean`                                                                 | `false`     | Try to use Fullscreen API and Keyboard Lock API.                                              |\n| `pointerBehavior`   | `'press' \\| 'emit' \\| 'none' \\| 'toggle' \\| 'lock' \\| 'custom' \\| string` | `'press'`   | Pointer input behavior.                                                                       |\n| `defaultPressState` | `string`                                                                  | `'success'` | Visual state used when a key is pressed.                                                      |\n| `renderMode`        | `'vue' \\| 'hybrid' \\| 'frame'`                                            | `'vue'`     | Rendering mode. Use `vue` for normal usage and `hybrid`/`frame` for high-frequency animation. |\n\n### states\n\n| Field          | Type     | Default     | Description                         |\n| -------------- | -------- | ----------- | ----------------------------------- |\n| `holdingState` | `string` | `'holding'` | Visual state used by `holdingKeys`. |\n| `lockedState`  | `string` | `'default'` | Visual state used by `lockedKeys`.  |\n\n## Imperative API\n\n| Method                                    | Description                                            |\n| ----------------------------------------- | ------------------------------------------------------ |\n| `requestEnhancedCapture()`                | Request enhanced keyboard capture.                     |\n| `releaseEnhancedCapture()`                | Release enhanced keyboard capture.                     |\n| `getVisibleKeys()`                        | Get currently visible interactive keys.                |\n| `setLayerState(layerName, keyRef, state)` | Set one key state in a layer.                          |\n| `setLayerStates(layerName, changes)`      | Set multiple key states in a layer.                    |\n| `clearLayer(layerName?)`                  | Clear a state layer, or clear all layers when omitted. |\n| `playTimeline(items, options?)`           | Play a scripted timeline.                              |\n| `pauseTimeline(target?)`                  | Pause timelines.                                       |\n| `resumeTimeline(target?)`                 | Resume timelines.                                      |\n| `seekTimeline(time, target?)`             | Seek a timeline to a specific time.                    |\n| `stopTimeline(target?, options?)`         | Stop timelines.                                        |\n| `playWave(options?)`                      | Play the snake-like wave animation.                    |\n| `startFrameRenderer(source, options?)`    | Start the typed-array frame renderer.                  |\n| `stopFrameRenderer(clearFrameLayer?)`     | Stop the typed-array frame renderer.                   |\n| `clearTransientActiveKeys()`              | Clear temporary pressed states.                        |\n\n## Wave Animation\n\n`playWave` moves in a snake-like path: first row left to right, second row right to left, and so on. The head is darker and the tail fades to a lighter color.\n\n```ts\nkeyboardRef.value?.playWave({\n  speed: 1,\n  tailLength: 7,\n  maxActiveWaves: 8,\n  headColor: '#0a2644',\n  tailColor: '#f4faff',\n})\n```\n\n## Local Development\n\n```bash\npnpm install\npnpm dev\n```\n\n## Build\n\n```bash\npnpm build\n```\n\nDemo build:\n\n```bash\npnpm build:demo\n```\n\n## Prepublish Checklist\n\n```bash\npnpm lint\npnpm format:check\npnpm build\npnpm pack --dry-run\n```\n\nPublish:\n\n```bash\nnpm publish --access public\n```\n","readmeFilename":"README.md","_rev":"1-e6af66d574563732dd8983533fa0e9d7"}