电视显示房间二维码,手机扫码入座,四个人各自在手机上记分、算番,所有屏幕实时同步
🌐 riichi.ruivon.cn · 电脑或电视打开选房型开主控台,手机打开就是加入页
亮点 · 界面 · 怎么用 · 架构 · 快速开始 · 文档
打日麻时最麻烦的是算点:谁和了、几番几符、本场和供托怎么分,往往要翻表、口算、再挨个传点棒。这个计分板把这些交给程序。电视或平板当主控台,摆在牌桌旁显示四家点数和历史;每个人用自己的手机录入和牌,番符由服务端的引擎算,结果同时出现在所有屏幕上。牌型可以拍照识别,村规可以按房间配置。
- 电视加手机的遥控模式:主控台只负责显示,操作都在手机上。手机上正在录入的结算会实时镜像到电视上,全桌一起核对。没带手机的玩家,可以由主控台添加为「本地玩家」代为操作。
- 拍照识别手牌:不用框选、横竖屏都行:对准手牌,它自己在画面里找到手牌(牌河留在上方不碍事),认稳了就自动定格,牌面自动填好并算番。模型是自训的 YOLO11n,在手机浏览器里用 onnxruntime-web 推理,iPhone 15 上一帧不到 300 ms。
- 番符由引擎算,不靠手填:录入牌面后,服务端用
riichi-rs-node算出役种、番数和符数,历史记录里保留整副手牌与役种。也可以直接手填番符。 - 村规按房间配置:内置 M-League(默认)、雀魂段位、天凤凤凰、最高位战、WRC 五套预设。切上满贯、累计役满、击飞、西入、包牌、本场点数等规则都可以单独调整。
- 断线不丢局:房间事件溯源,每条命令都落进 SQLite。服务端重启后按事件回放恢复,撤销、重做随时可用。手机丢了登录状态,也能让离线的旧座位离座后重新坐回去。
- 番符表随手查:役种一览和点数计算表按雀魂的结构排版,每个役种都附例牌。默认只在自己手机上看,想全桌一起看时打开「投到电视」。
- 立直音乐:立直时选一首曲子,电视循环播放,结算时自动停止。按下立直同时记下本局立直,结算时自动勾上。
- 防手滑:番符和放铳者不给默认值,确认键旁同屏显示「谁和了谁、收入多少」;结算弹窗关掉再开草稿还在,别人先记了一笔会自动关闭;撤销、重做全桌都能看到是谁撤了哪一笔。
大厅 · 房间二维码、四家座位、本房规则
|
对局 · 四家点数、点差表、带牌面与役种的历史
|
结算镜像 · 手机上正在录入的荣和同步到电视
|
加入 · 扫码或输入六位房间码
|
入座 · 选座、准备,四人就绪自动开局
|
番符表 · 按番数分组,附例牌
|
- 电视、电脑或平板打开 riichi.ruivon.cn,选「创建四人麻将房间」或「创建二人麻将房间」,房间建好后显示二维码(上次的房间还开着时,按钮会写「继续 … 房间码」,旁边可以「新建」)。
- 四个人用手机扫码,填昵称、选座、点「准备」。四人都准备好后,3 秒倒计时自动开局。
- 有人和牌,就在手机上点「荣和」或「自摸」:先选谁和了(荣和再选放铳者),再录入牌面(或点「拍照识别」)。确认后,所有屏幕上的点数同步更新。
- 流局、途中流局、错和、调整场况也在同一个面板里(主控台点右上角「操作」打开);记错了可以撤销上一次操作。
- 主控台开着房间时屏幕保持常亮;字嫌小可以在大厅或「操作」面板里把界面大小调到 115% 或 130%(每台设备各自记住)。
出自福本伸行《天 天和通りの快男児》:两个人打,没有点棒往来,各自累计得分,限时 1 小时,得分高者胜。每一局分两个阶段——
- Stage A:照常摸打(可吃碰杠),先听牌的一方在手机上按「▶ 立直」(用掉 1 根立直棒,每人 10 根)或「听牌宣言」,成为进攻方;18 巡无人宣言则流局。
- Stage B:防守方每轮指定 2 张牌,猜中进攻方任意一张待牌即流局;没猜中,进攻方连摸 5 张,摸到就是自摸和,否则再指定,直到王牌。电视右侧这时变成全牌型板,防守方在手机上点一下划掉一张、再点恢复,用来排除;猜牌本身在牌桌上口头进行。
和牌只有自摸一种,得分等于这手牌在四人麻将里自摸的总收入(含本场);手牌同样可以拍照识别。大厅里的「玩法说明」可以投到电视,对局中电视也常驻当前阶段该做什么。计时不公开,只在剩 10 分钟、5 分钟和时间到时各提示一次,由玩家点「终局」。二人麻将的对局不计入个人战绩。
拍照识别的摆法:
- 暗牌连着排,和张横放在一端;
- 副露每组 3 或 4 张,其中一张横放(暗杠摆成牌背-X-X-牌背),放在右侧、上方、下方都可以;
- 宝牌指示牌全部正放在手牌上方,两行时上面一行是表宝牌、下面一行是里宝牌,认出里宝牌会自动勾上立直;
- 指示牌紧贴手牌,牌河离远一点——挨得太近的牌河末行会被当成指示牌。
认稳之前画面中央会出现 2 → 1 的倒计时,闪一下就是定格了。一直认不稳时,取景画面上会写出原因(比如「只认出 13 张:和了牌横放在手牌一端了吗?」),也可以随时按右下角快门手动定格;横着拍点一下快门旁的旋转按钮(授权陀螺仪后会自动跟着转)。每次识别的定格照片和结算确认后的手牌会上传保存,用作模型的训练数据;放弃取景、或折腾十几秒才定格时,还会上传最多 6 帧整幅画面,用来排查认不出的原因。照片不会发给任何客户端(存储地址带随机串),排查用的画面会定期清理;每人每小时最多识别 60 次,排查用的画面另计 60 帧。首页的「拍照算点数」不进房间也能用:设好场风、自风、本场和规则,拍一手牌、核对识别结果,点「识别正确」就给出番符、役种和点数;确认的手牌同样用作训练数据。
可以把网页「添加到主屏幕」,全屏使用。不过 iOS 主屏应用和 Safari 各存一份登录状态,同一台手机在两边会被当成两个玩家。
flowchart LR
TV["电视 / 电脑<br/>/console"] <-- WebSocket --> S
P1["手机<br/>/r/:code"] <-- WebSocket --> S
P1 -- 拍照识别<br/>WASM 推理 --> P1
S["Hono 服务端<br/>命令校验 → 引擎算番 → reducer"] --> DB[("SQLite<br/>room_events")]
S --> COS[("COS<br/>头像 / 识别照片")]
| 层 | 组成 | 职责 |
|---|---|---|
领域层 packages/core |
纯 TypeScript | 规则与预设、计分、局次推进、终局结算、reduceRoom(state, event) 纯函数 reducer、番符表数据、协议类型;前后端共用 |
服务端 apps/server |
Hono + @hono/node-ws + node:sqlite + riichi-rs-node |
房间事件溯源:命令带 baseSeq 做并发控制,校验后补全身份与引擎结果,再经 reducer 写入 room_events 并广播;撤销/重做栈在内存里按回放重建 |
前端 apps/web |
Vite + React 19 + Tailwind v4 + Radix | / 按设备分流,/console 主控台,/r/:code 手机端,/calc 拍照算点数;识别推理在 Web Worker 里跑 |
模型 ml/ |
Python + uv + Ultralytics | 公开数据集加合成场景训练 YOLO11n,导出内嵌 NMS 的 ONNX,发布到对象存储 |
| 部分 | 选型 |
|---|---|
| 前端 | React 19、React Router、Zustand、Tailwind CSS v4、Radix UI、qr-scanner、onnxruntime-web |
| 服务端 | Node 24、Hono、WebSocket、node:sqlite、riichi-rs-node、腾讯云 COS SDK |
| 测试 | Vitest 单测、Playwright 端到端(电视 + 多台手机 + 真实识别链路) |
| 部署 | Docker、GitHub Actions、腾讯云 COS + CDN + CCR |
需要 Node 24(最低 22.13)和 Corepack。
corepack enable
yarn install
yarn dev # 服务端 :8787,前端 :5173电脑浏览器打开 http://localhost:5173 就是主控台(ci/dev-tls/certs/ 里有证书时自动改成 https://);手机要扫码或拍照,需要 HTTPS,配置见 本地开发。
yarn test # 单测
yarn e2e # 端到端
docker compose up -d --build # 单容器运行,:8787| 文档 | 内容 |
|---|---|
| docs/development.md | 本地开发、常用命令、手机 HTTPS 调试(mkcert、开发机 caddy) |
| docs/deployment.md | 同源部署、线上 CI/CD、服务器与 secrets、PWA、曲库与模型发布 |
| ml/README.md | 牌面检测模型的数据、训练、导出与发布 |
| CLAUDE.md | 架构与领域概念的完整说明(协议、事件溯源、识别流水线细节) |
代码以 GNU AGPL-3.0-or-later 发布:可以自由部署、修改、再分发,但对外提供服务的修改版必须公开源码。
选它有两个原因:这是一个网络服务,AGPL 保证托管的分叉把改进交回来;ml/ 依赖 Ultralytics YOLO(AGPL-3.0),
训练出的检测模型按其条款同属 AGPL 派生物,整仓同一许可证最省事。
- 牌图来自 lietxia/mahjong_graphic(M+ 式自由许可),见
apps/web/src/assets/tiles/NOTICE.md - 番符计算使用 riichi-rs-node(riichi-rust 的 wasm 封装;上游仓库尚未声明许可证,同组织其它项目为 GPL-3.0)
- 牌面检测:Ultralytics YOLO11(AGPL-3.0)训练,手机端由 onnxruntime-web(MIT)推理
© Ray 2014-present





