Skip to main content
Glama
Edint386

glasscast

by Edint386

glasscast

把电脑屏幕投到千问 AI 眼镜 S1,用语音开始和停止。适合瞄一眼终端、构建进度或文档,不适合看视频、玩游戏。

非官方个人项目,与阿里巴巴、千问团队和千问 AI 硬件开放平台没有任何关联。

它怎么工作

眼镜没有给第三方开放视频流,所以 glasscast 用连续换图来代替视频。一次投屏分三段:

  1. 电脑截屏。 glasscast serve 不停截屏,按推荐配置缩到 480×218,压成约 2.6 KB 的灰度 JPEG。它只保留最新一帧,放在你自己的公网 HTTPS 域名下。

  2. 眼镜取图。 眼镜上的页面不停换图片地址,比如 …/screen.jpg/0101120000_1.jpg、…/0101120000_2.jpg。地址一变,手机 App 就下载一次,拿到的总是最新一帧,再经蓝牙传给眼镜解码显示。

  3. 语音控制。 你对眼镜说「开始投屏」,千问平台的大模型调用 glasscast 的 MCP 工具,再打开投屏页面。MCP 只管开始、停止和查询,不参与逐帧刷新。

一张图从手机下载到眼镜显示,固定要约 0.65 秒,和图片是 2.5 KB 还是 4 KB 关系不大。这决定了这条链路的速度上限。

Related MCP server: openowl

实际效果

下面是在 S1 真机上测到的结果:

普通模式(默认)

流畅模式

速度

约每秒 1 帧

最高约每秒 1.5 帧

眼镜页面

cast-image

cast-emit

特点

最稳

稍快,档位太高时会卡住

  • 普通模式延迟约 1~2 秒,流畅模式没有单独测过。

  • 单色绿屏,没有声音,也不能在眼镜上操作电脑。

  • 画面在视野左上角,页面里改不了。整屏缩小后小字看不清,看代码时建议只投一块区域(GLASSCAST_REGION)。

  • 只在 macOS 上测过。

流畅模式的实现思路

流畅模式要同时做到两件事:换图比每秒一次快,并且每张图都来得及显示。

普通模式为什么快不起来

普通模式用 <tick> 换图。页面里所有 tick 共用一个 1 秒定时器,所以最快每秒 1 帧。我们也试过用 <frame-set> 帧合集当定时器,模拟器里能跑,但平台保存时的校验(URI-001)不放行,放不到真机上。

用事件倒数当定时器

页面可以给自己发 emit:// 事件。emit 是异步的,事件要等下一轮消息循环才送达,真机上每一步约 13 毫秒。收到事件后再发一个,页面就有了一个比 tick 快得多的节拍。

难点在于节拍不能写进 data。每写一次 data 就刷新一次绑定,而绑定一刷新,还没加载完的 <image> 就要从头加载。早期版本每一圈都连写两三次 data,真机上每张图被请求 3~6 次,最后只显示出一张图。

所以计数放在事件参数里,只有换图时才写 data。页面的核心就是下面这些(完整代码见 pages/cast-emit/template.xml):

<data s="0" g="0" m="75"/>

<!-- 打开页面:写入每轮的步数 m,开始倒数 -->
<lifecycle-event a:if="{{hops != 0}}" on-load="data://update?m={{hops * 3}}" on-new-intent="data://update?m={{hops * 3}}"/>
<lifecycle-event on-load="emit://event/d10?n=10"/>

<!-- 倒数:d1 到 d9 共九条规则,动作相同,都是把 n 减一再发出去 -->
<event match="event://d1" action="emit://event/d{{e:n - 1}}?n={{e:n - 1}}"/>
<event match="event://d9" action="emit://event/d{{e:n - 1}}?n={{e:n - 1}}"/>

<!-- 倒到 0:写一次换图编号 g,再从 m 开始下一轮 -->
<event match="event://d0?" action="data://update?g={{d:g + 1}}"/>
<event match="event://d0?" action="emit://event/d{{d:m}}?n={{d:m}}"/>

<image a:if="{{d:s != 0}}" src="{{url}}{{structuredContent.url}}/{{d:s}}_{{d:g}}.jpg" width="640" height="290" image-fit="stretch"/>

以档位 4 为例,m 是 36,一张图的过程是:

  1. 倒数到 0,g 加一。这是一轮里唯一一次写 data,图片地址随之变成 …/<会话>_<g>.jpg。

  2. 手机下载最新一帧,经蓝牙传给眼镜,眼镜解码显示。

  3. 这段时间里页面继续倒数 36、35……1,全程不写 data,图片不会被打断。

  4. 又倒到 0,回到第 1 步。

还有两个写法上的细节:

  • 九条规则就能倒任意步数。 每页不同的 match 数量有限(最多 32 个),而 match 是前缀匹配:event://d3 能命中 d3、d30、d36。所以 d1~d9 按 n 的首位数字分流,只有 n 到 0 时才命中 d0?。

  • 地址每次都不一样。 data 里的数超过 2147483647 会被卡住,时间戳存不进去。所以 s 只取打开页面时的月日时分秒,g 是从 0 开始的小计数器,两者拼成的地址不会溢出,每次打开页面也不会命中缓存。地址还必须以 .jpg 结尾,用 ?ts= 防缓存的地址能下载,但眼镜不显示。

档位和真实帧数

start_cast 的 fps 参数是速度档位,不是眼镜上的帧数。它决定两件事:

  • 电脑每秒截几张图。 档位 4 时电脑每秒截 4 张,眼镜只来得及显示约 1.5 帧,手机每次取到的都是最新一张。

  • 页面每轮倒数多少步。 hops = round(1000 / 档位 / 20)(Python 的 round,12.5 取 12;20 是 GLASSCAST_EMIT_HOP_MS 的默认值),限制在 1~25,m = hops × 3。hops 由 start_cast 算好,模型打开页面时传进去,所以换档不用改页面。

档位

每轮步数

换图间隔

真实帧数

表现

1~2

75

约 1 秒(估算)

约每秒 1 帧(估算)

没有直接测过

3~4

36~51

正常时 630~720 毫秒

约每秒 1.5 帧

图小时稳定,见下

4.5 及以上

33 及以下

不固定,4.5 档卡住时约 405 毫秒

时好时坏

容易卡住(只实测过 4.5 档)

3~4.5 档是实测的,1~2 档是按步数估算的。3、3.3 档用约 4.1 KB 的图,4 档的 630~720 毫秒和 4.5 档用约 2.5 KB 的图。图越小越不容易卡:约 4.1 KB 的图到 3.5 档就开始不稳,3.8 档约 500 毫秒、时好时坏,4 档不行;约 2.5 KB 的图到 4 档还算稳。

上限和卡住是怎么来的

每张图有约 0.65 秒的固定开销,所以倒数再短,真实帧数也基本停在每秒 1.5 帧左右。

档位 4 的 36 步按每步 13 毫秒算只要约 470 毫秒,比 0.65 秒还短,正常时实测却是 630~720 毫秒。这是因为眼镜处理图片时,事件循环也被拖慢了。

问题在于倒数并不知道图片显示完了没有。只要有一张图没显示出来,眼镜就不再被拖慢,循环回到全速(每步约 12.5 毫秒),下一张来得更快,也就更显示不出来。真机日志里这种状态能持续几十秒,换图间隔只有 405~450 毫秒,画面却不动。档位越高越容易掉进去,4 是实测能稳住的最高档,但也不是绝对不会卡。

想再快,只能一次下载里装多帧,在眼镜本地播放,这条路还在实验中。现在传的始终是一张张普通 JPEG,不是视频流,也不是 GIF:<gif> 的 src 在模拟器里只在创建时取一次,换不了内容(真机没测过),GIF 输出只是默认关闭的实验开关,现有页面都没用它。

需要准备

  • 千问 AI 眼镜 S1 和手机 App「千问AI穿戴」

  • 千问 AI 硬件开放平台账号

  • 一台装好 uv 的 Mac,投屏时不能锁屏或睡眠

  • 一个指向这台电脑的公网 HTTPS 域名,必须是真证书

快速开始

先在本机试一下,不需要眼镜:

git clone https://github.com/Edint386/glasscast.git
cd glasscast
uv sync
GLASSCAST_TOKEN=local-test-token-123456 GLASSCAST_CAST_KEY=localtest123 \
  uv run glasscast serve --source synthetic --public-url http://127.0.0.1:8766 --autostart image

用浏览器打开 http://127.0.0.1:8766/s/localtest123/screen.jpg,合成画面约每秒更新一帧,隔一秒以上刷新就能看到新画面。

接到眼镜上:

  1. 运行 cp .env.example .env,填好域名和 token(用 openssl rand -hex 24 生成)。

  2. 给启动 glasscast 的终端打开「屏幕录制」权限。

  3. 把服务暴露到公网 HTTPS,见 公网部署。

  4. 启动服务:. ./.env && uv run glasscast serve。

  5. 在平台上建 MCP 插件、技能和两个页面,见 平台配置。

  6. 对眼镜说「开始投屏」。

语音命令

你说

效果

开始投屏

用普通模式投屏,约每秒 1 帧

用流畅模式投屏

用流畅模式投屏,最高约每秒 1.5 帧

最流畅

调到 4 档,约每秒 1.5 帧

最省流量

调到 1 档,约每秒 1 帧

投屏调到 N 档

N 取 1~10。档位不等于帧数,见上面的表,建议不超过 4 档

投屏状态

查询是否在投、电脑多久前截过图。看不出眼镜上的画面是否卡住

停止投屏

电脑停止截屏,再用眼镜的返回手势离开页面

安全

  • 图片地址里的 KEY 等于看屏口令,拿到完整地址的人就能看到你的屏幕。

  • 投屏会投出屏幕上的一切,包括通知和密码框。

  • Token 只填在平台的插件配置和本机的 .env 里,不要写进技能或页面。

详见 使用手册的安全一节。

文档

  • 使用手册:完整部署步骤、命令行和环境变量、HTTP 和 MCP 接口、排错、已知问题

  • 公网部署:反向 SSH 隧道、nginx、1Panel、cloudflared

  • 平台配置:在千问平台上建插件、技能和页面

  • 眼镜页面:每个页面是什么、改页面前要知道的限制

  • 本地模拟器:不用眼镜预览页面

  • 实验记录:带日期的调研和真机测试笔记

许可

代码以 MIT 许可证 发布。「千问」「Qwen」等名称和商标归其各自所有者。模拟器用到的官方渲染内核不包含在本仓库里,由脚本从官方 CDN 下载。使用时请遵守平台的开发者协议,投屏内容和公网暴露的风险由使用者自行承担。

English: glasscast mirrors a Mac screen to Qwen AI glasses S1 by serving small grayscale JPEGs over your own HTTPS domain, at about 1 to 1.5 images per second. Setup docs are in Simplified Chinese. This is an unofficial personal project.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A small Model Context Protocol (MCP) server that gives an LLM eyes on your desktop without burning context. It can take one-off screenshots, crop a region around the mouse cursor, and run timed streaming sessions that save frames to disk and only return image bytes when explicitly asked.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that gives any AI assistant eyes and hands on your desktop — screenshots, clicking, typing, OCR, window management, accessibility-tree queries, workflow recording.
    5
    Apache 2.0
  • A
    license
    A
    quality
    F
    maintenance
    Provides an MCP server for local low-power screen vision, enabling AI agents to perform OCR and UI detection on inaccessible screens (games, remote desktops) using NPU acceleration and system OCR.
    5
    1
    MIT