跳转至

在 Hex 中捕获

状态:第 2 步和第 3 步,以及第 4 步的输入部分(配合 Scrawl 面板),已作为一项实验性功能构建在 Scrawl 的真实引擎上,位于构建选项后面(所有公开构建中均关闭);第 4 步的那一半在分支 scrawl-in-hex 上。该实验使用了导入到 crates/capture 的 scrawl-capture crate(见 当前已构建内容);目前没有发布任何内容,Kit 之后决定是否进行这次合并。这是 ROADMAP 中“将 Scrawl 并入 Hex”的 Hex 一侧:Hex 如何托管 Scrawl 的采集引擎而不削弱听写功能。

当前已构建内容

第 2 步:crates/capture 是 kitlangton/scrawl 仓库 e351ddb(分支 engine/split)中 Scrawl 的 crates/capture,无历史记录地复制而来,保留包名 scrawl-capture,私有测试值替换为合成值,并执行 cargo fmt 和不改变行为的 clippy 修复。Hex 通过路径依赖它。它位于 [workspace] exclude 中,因此 cargo build、cargo test 和 --workspace 永远不会构建它;它仅作为 capture 功能的 macOS 依赖进行编译,并与根目录的 Cargo.lock 和 target/ 共享。在 macOS 上,scripts/check 和 CI 通过名称(-p "$(cargo pkgid)" -p scrawl-capture --features capture)对其进行 lint 和测试。Scrawl 自己的改动现在通过手工方式迁移过来。

第 3 步:该 crate 上的 capture_host:

hex capture start|stop|cancel|status     // `--features capture`; POST /control `scrawl-capture`
└── listener thread -> capture_host::CaptureHost (exists only with the experiment on)
    ├── start -> owner-only <captures folder>/<unix ms>.scrawl -> reply at once
    │   ├── DictationAudio::open_capture_sink(bounded 512 chunks, since = t0)
    │   └── capture-audio thread -> Engine::start(Start { t0_boot_ns, ActiveDisplay,
    │       AudioIn::External, bundle_dir }) (blocks: target lookup, ScreenCaptureKit)
    ├── capture-audio thread -> Timeline: 16 kHz, gaps padded, start offset kept
    ├── start while two stopped captures are still writing -> busy
    ├── stop -> close_capture_sink(through) (≤ 100 ms wait) -> reply with the bundle path
    │   ├── capture-audio thread -> Capture::stop: screen, window log, and input end now
    │   └── capture-finish thread, one at a time, ≤ 2 waiting ->
    │       SealedCapture::finish(Some(RecordedAudio { start_offset_ms, gaps }))
    │       ├── HexTranscriber -> parakeet::transcribe_with_words, 30 s chunks,
    │       │   each a foreground job on the dictation engine's loaded model
    │       ├── Scrawl writes recording.mp4, audio.wav, frames/, scrawl.json, summary.md
    │       │   (its own files 0600) -> Finished { words, gaps, missing_transcript }
    │       └── Hex makes every file 0600 and folder 0700 (recording.mp4, folders)
    └── cancel -> Capture::cancel, remove the bundle
  • Hex 的接缝是 src/capture_host.rs 中的三个小 trait:CaptureEngine、Recording 和 Sealed,它们为 scrawl_capture::capture::{Engine, Capture, SealedCapture} 实现,因此宿主测试无需屏幕即可运行。Hex 实现了该 crate 的 Host(有界 try_send 事件,日志和指标进入 tracing)、ConfigSource 和 Transcriber。hex capture status 显示上一次捕获的词、音频间隙,以及它为何没有转写文本。
  • ConfigSource 是引擎唯一的设置来源;Hex 的路径上没有任何代码读取 ~/.config/scrawl/config.json(该 crate 只在调用 enable_scrawl_host_defaults 或 enable_file_log 后才读取 Scrawl 的配置并记录日志,而 Hex 从不调用这些)。Hex 还没有捕获设置,因此 HexConfig 有意采用 Scrawl 的默认值:自动裁剪开启(适用于屏幕捕获),agentContext 摘要格式关闭。
  • 引擎是 Engine::new(..).with_resources(SharedResources::none());Hex 从不调用 install_shared_resources,因此没有摄取服务器(47777)、投递重试或全局快捷键。当没有设置 sink 时,Engine::new 将该 crate 的进程级日志路由到 Host::log,因此每一行都会到达 Hex 的 tracing 一次,并且不会有任何内容写入 ~/Library/Logs/Scrawl。Engine::new 和 Engine::start 不调用 TIS/TSM(只有 install_shared_resources 才会解析布局感知的快捷键)。
  • 同一时间只有一次捕获在录制。stop 会将其封存,capture-audio 线程立即调用 Capture::stop,结束 ScreenCaptureKit、窗口日志和输入;随后 SealedCapture 等待该单一写入者,最多同时等待两个。使用 SharedResources::none() 时,每次捕获都有自己的输入遥测,因此一次捕获在录制时,即使较早的一次捕获仍在写入,两者之间也不会共享任何内容。
  • 数据包写入 <captures folder>/<unix ms>.scrawl,即 Scrawl 自己的文件夹,除非 capture.folder 指定了其他目录(第 3 步使用 <support>/captures):采用 Scrawl 自己的 scrawl.json 格式,词以毫秒为单位,基于捕获自身的时钟。
  • hex dev capture-replay <wav>… 在一个全新的转写引擎上以无头模式运行同一个 CaptureHost,用 WAV 文件代替麦克风输入;它也会录制屏幕(仅限 debug 构建,与所有 hex dev 命令一样)。
  • 视图读取单个 CaptureSnapshot(capture_host::snapshot,由 capture_host::watch 唤醒):正在录制的那次捕获(数据包、开始时间、屏幕是否已启动)、处于引擎最新阶段的已停止捕获,以及最后一个已定稿的捕获(完成、失败、取消,包含词和间隙)。宿主在每次变化时发布该快照;引擎进度会推进一次捕获,但绝不会将其定稿。胶囊、路由器和 hex capture list 订阅的是此处,而不是宿主。
  • 路由和投递(第 5 步)、有线连接的 iPhone、胶囊、屏幕上的选择器,以及墨水和激光叠加层均已构建;请参阅相关章节和 docs/features/capture.md。尚未构建:iPhone 摄取(ScrawlKit 配对)、移动摄取令牌,以及用于打开列表的监听器按键路径(⌥⇧V、输入、方向键、Return)。

第 4 步的前半部分(快捷键、输入、Escape),连同第 5 步中的面板、导入和共存:

settings.json capture.* (CaptureSettings, cfg hex_capture; other builds keep the raw key)
├── enabled (off) · hotkey (⌥⇧S) · transcriber (parakeet|apple) · folder (None = Scrawl's)
│   · media_days / bundle_days (Scrawl's Week preset: 7 / 30)
├── every key in `hex settings` (control/settings.rs CAPTURE_KEYS)
└── load -> import once (migration `scrawl-capture-settings`, not in MIGRATIONS):
    ~/.config/scrawl/config.json + Scrawl's shortcut file, read-only

recognition loop, every iteration
├── CaptureHost::reconcile -> start/stop the host as capture_on() changes
│   (experiment && capture.enabled); watch_scrawl polls Scrawl.app every 2 s
├── runtime_hotkeys() drops capture while Scrawl.app runs
├── fresh ⌥⇧S press (CaptureShortcut) -> CaptureHost::toggle: start | stop
│   (a press within SHORTCUT_DEBOUNCE, 400 ms, of the start is ignored)
└── Esc, nothing else recording, a capture recording -> cancel it first

suppression event tap (the one session tap)
├── observation mask + mouse down/up/drag/scroll when capture_available()
├── wants_input() (a capture records) -> report_capture_input -> TAP_INPUT
│   (bounded 1 024, drops counted) -> LiveInput::forward -> HostInput
│   (Moved / ModifiersChanged stand in for Scrawl's 8 ms poller)
└── capture-only events end there; keys, flags, and downs continue to the listener

crates/capture hosted_input.rs: Scrawl's ink and click rules as pure functions
(is_pin_click, drew_before, is_real_ink, on_own_window); Scrawl's own key tap
calls the same key_input / key_name. after_shortcut(): Shift must come up once.

Settings › Experiments › Scrawl (rune_ui/scrawl.rs; PlatformState.scrawl is
Some while capture_available(), so the pane exists only then)
├── Capture with Hex · Shortcut · Screen Recording · Transcriber
├── Captures folder (Reveal | choose) · Keep (retention presets)
├── "Scrawl is running" + Use Hex for captures -> quit_scrawl (NSRunningApplication)
└── "Hex copied Scrawl's settings once…" when the import read a file

capture-retention thread -> retention::run_pass(capture.* policy): 90 s, then hourly;
skipped while a capture is unfinished or Scrawl.app runs
  • 与 Scrawl 的差异:快捷键在按下时生效(Scrawl 的 Carbon 热键也是在按下时启动,但 Hex 没有“松开时启动”的待处理状态);启动后 400 ms 内的按压会被忽略,而不是停止刚刚开始的捕获;指针位置来自点击事件,而非 8 ms 轮询器。
  • 该窗格仅存在于 cfg(hex_capture) 构建中:公开构建永远不会编译该模块、其字符串或其场景;特性构建只有在实验开启时才显示它。它的场景(mac-scrawl*)仅在特性构建中渲染,因此它们没有 golden 基准图(golden 基准图在 Linux 上运行)。
  • iPhone 配对被省略,而不是显示为禁用:它需要摄取服务器,而 Hex 尚未运行该服务器。有线连接的 iPhone 不需要这一行。

特性与门控

  • Hex 的 Cargo 特性 capture(默认关闭)会启用仅限 macOS 的可选依赖 scrawl-capture(default-features = false, features = ["screen", "helper"])和 anyhow(该 crate 的 trait 返回 anyhow::Result)。
  • build.rs 在开启该特性的 macOS 构建(debug 或 release)中设置 cfg(hex_capture),所有捕获代码行都受其保护。未启用该特性的构建(所有公开发布、Linux、Nix、Windows)永远不会编译该 crate 或其 Swift helper,并会以 unsupported 拒绝 scrawl-capture。
  • Release、测试构建和 Nix 构建永远不会传递该特性。scripts/release-app.sh 会拒绝 HEX_CAPTURE,scripts/validate-app.sh(在每个 macOS release 产物上运行)会拒绝包含 Contents/MacOS/scrawl-helper 或含捕获主机启动日志行的 hex 的 bundle。
  • scripts/check 和 macOS CI 使用 --features capture 对 Hex 和该 crate 执行 lint 和测试(该 crate 的约 260 个测试只需数秒即可运行)。Linux、Windows 和 Nix 构建永远不会选择它:该依赖仅限 macOS,且该 crate 位于工作区之外。
  • 关闭:phone(摄取服务器、配对)、mic(引擎自身的 cpal 流)、input(rdev 点击事件)、hex-client、parakeet、cli。helper 保持开启,用于 scrawl-helper,它在完成时将 recording.mp4 解码为全质量关键帧(没有它,bundle 会保留 480 px 的采样帧)。

Helper 与权限

  • scrawl-helper 由该 crate 的 build.rs 构建在二进制文件旁边(target/<profile>,位于 OUT_DIR 上方三级);引擎会在其自身可执行文件旁查找它(helper::path);$SCRAWL_HELPER 可以覆盖。如果缺失,完成时会保留 480 px 的候选帧作为关键帧。Hex 的捕获路径使用它进行影片解码(不需要 TCC)、devices(USB 注册表,不需要 TCC)以及 mirror --no-microphone(有线 iPhone 的捕获,需要 Camera)。
  • Camera 属于 Hex,即 helper 的负责进程;因此只有 HEX_CAPTURE=1 构建会将 NSCameraUsageDescription 添加到 Hex.app 的 Info.plist(以及 helper 内嵌的那份);scripts/validate-app.sh 会拒绝包含它的发布 bundle。
  • HEX_CAPTURE=1 scripts/build-app.sh 使用 --features capture 和 SCRAWL_HELPER_PLIST=packaging/macos/scrawl-helper-Info.plist(内嵌 bundle ID anomaly.hex.scrawl-helper,名称为 Hex)构建,将 helper 复制到 Hex.app/Contents/MacOS/scrawl-helper,并在应用之前用应用的标识、hardened runtime、时间戳、标识符 <bundle id>.scrawl-helper 对其签名,且不附带 entitlements。
  • 屏幕录制权限归属于运行 ScreenCaptureKit 的进程:即 Hex 本身(或运行开发构建的终端)。helper 是 Hex 的子进程,因此它接触到的任何内容都归属于 Hex(其负责进程)。

结构

Hex.app (one process, macOS only for captures)
├─ hex (root package of a new workspace)
│  ├─ capture_host            ← new: the experiment's one owner
│  │  ├─ Host impl            logs → tracing, metrics, own windows, clipboard
│  │  ├─ Transcriber impl     Parakeet words on the transcription engine
│  │  ├─ ConfigSource impl    settings.json `capture.*` + one-time import
│  │  └─ capsule + ink overlay (Rune overlays, storybook scenes)
│  ├─ suppression             + capture shortcut, + pointer events while capturing
│  ├─ dictation_audio         + bounded capture sink on the same timeline
│  └─ transcription_engine    + foreground capture clip (after queued dictation)
└─ crates/capture (package `scrawl-capture`, imported without history)
   ├─ features on in Hex:  screen, helper (phone later, for iPhone ingest)
   └─ features off in Hex: input, mic, hex-client, parakeet, cli

该引擎是 Scrawl 的:屏幕采样、关键帧、草图与摘要、渲染、自动裁剪、bundle、投递、路由(与 Jev 协同)、保留、恢复,以及 iPhone 摄取。Hex 提供麦克风、输入、转录、界面和设置。该引擎在 Hex 内部永远不会自行打开麦克风、安装事件点击、请求输入监控或粘贴。

工作区与构建

  • 根目录下的 Cargo.toml 将 crates/capture 列入 [workspace] exclude(会被构建)。根目录是 hex 包。
  • Hex 仅在 [target.'cfg(target_os = "macos")'.dependencies] 下依赖 scrawl-capture,目前为 default-features = false, features = ["screen", "helper"](phone 将随 iPhone 摄取功能加入)。Linux 和 Windows 构建永远不会编译它,因此它们的 CI 和包不变。
  • crates/capture/Cargo.toml 列出显式版本(没有 workspace = true),以便 Scrawl 应用在停用之前可以通过 Git 修订版依赖它。
  • macOS CI 使用 --features capture 对 -p scrawl-capture 执行 lint 和测试(会被构建)。
  • crates/capture/build.rs 编译引擎的 Swift helper。Hex 使用 Hex 身份(SCRAWL_HELPER_PLIST)构建它,scripts/build-app.sh 会将其复制并签名到 Contents/MacOS/(为 HEX_CAPTURE=1 构建)。

实验门控

实验 capture。当它关闭时,以下一切都不会启动:不注册任何快捷键,不存在捕获汇,不绑定摄取端口,不运行保留或投递重试 worker,也永远不会启动 helper。该门控位于工作开始的位置(capture_host worker),而不仅仅是在窗口中。

输入

  • 捕获快捷键(默认 ⌥⇧S)是 suppression 中除听写和 Voice Action 之外的第三个目标,其捕获和冲突规则与其他绑定相同。它拒绝与听写重叠的绑定。
  • 当捕获正在录制时(且仅在此期间),会话 tap 还会报告鼠标按下、抬起、拖动和滚动,以及 Shift 状态。capture_host 将这些信息提供给 Capture::input()。Scrawl 的墨迹和点击规则(Shift 墨迹、固定和墨迹阈值、忽略对 Hex 自身窗口的点击)作为这些事件上的纯函数移入引擎,因此 Hex 不会运行第二个 tap。
  • Escape 会先取消进行中的捕获,然后才取消听写工作。捕获从不使用按住阈值或松手后的尾部。
  • 已构建:参见目前已构建中的第 4 步。

麦克风

  • dictation_audio 有一个有界的捕获汇(open_capture_sink、close_capture_sink):捕获接收到与听写相同的带时间戳样本。永远不会出现第二个 cpal 流。
  • 听写在捕获期间继续工作。两者是同一时间线的投影,因此在捕获中途按住听写快捷键仍会粘贴,同时捕获仍会将那段语音记录为叙述。
  • 启用“空闲时释放麦克风”时,捕获会在其持续期间保持流打开,就像录音一样。
  • 汇压力会丢弃捕获音频并标记一个间隙;它绝不会阻塞时间线或听写。

转录

  • capture_host 使用转录引擎已加载的模型和词时间戳(parakeet::transcribe_with_words)实现引擎的 Transcriber;听写仍然丢弃其词。
  • 已完成的捕获片段是前台工作:它在已排队的听写之后、会议块之前运行。它绝不会加载第二个模型。它按 30 秒块发送到引擎,每块一个任务,因此同时发送的听写最多只会等待一个块。当听写正在捕获或转录时,块会等待;如果某个块在实时流期间到达,引擎会一直持有它直到流结束,因此它绝不会打断实时流。
  • Scrawl 的口语提示需要经过测量的词时间。与 Apple 的 SpeechAnalyzer 在 36 个真实捕获(10 月 25 日)上的对比显示,Parakeet Unified English 的词时间偏晚:开始时间中位数晚 280 ms(暂停后约 520 ms),结束时间晚 180 ms,在 30 秒接缝处没有漂移也没有开销;原始数据中,53% 的提示词晚于 300 ms。HexTranscriber 会减去基于一半捕获拟合的滞后(capture_host 中的 WORD_LAGS:开始时间 280 ms,或者当与上一个词结束之间的间隔至少为 250 ms 时为 520 ms;结束时间 195 ms),这使得另一半捕获中 96% 的提示词与 Apple 的差距在 300 ms 以内。该滞后与固定的模型文件绑定:更换模型或重新固定都会保留原始时间,直到再次测量。Apple 辅助程序路径仍可选择(hex settings set capture.transcriber apple)。

界面

  • 胶囊(录制中、处理中、完成、路由提示、选择器)以及墨迹和激光叠加层都是可点击穿透的 Rune 叠加层,与会话胶囊一样。它们的窗口 ID 通过 Host::own_windows 传给引擎,因此屏幕捕获会将其排除在外,点击也会穿透。
  • 每个状态都有一个 --snap 场景和一个 storybook 条目。
  • Scrawl 的切换标签(docs/capture.md):由快捷键启动的录制会打开到“区域 · 窗口 · 屏幕”并持续 3.5 秒(悬停时从不收起),或直到第一次点击、滚动或笔画。标签是重启而不是重新定向:Window 和 Area 会丢弃录制并将胶囊变成选择器。宿主端已构建:通过 RecognitionControl::CaptureCommand 传递的 CaptureTarget、CaptureCommand::{Start, Discard, Switch}、RecordingCapture::{target, worked}、SettledCapture::error,以及用于选择器打开时的 ⌥⇧S 和 Esc 的 begin_picking。该快捷键在修饰键释放时启动,和 Scrawl 一样。iPhone 标签的宿主端也已构建:CaptureTarget::Phone、TargetKind::Phone、CaptureSnapshot.phone(来自每次启动以及 CaptureCommand::FindPhone 时的 capture-phone 查找所得到的接线手机名称)。镜像以 --no-microphone 运行;叙述是 Hex 的时间线音频,移至影片的时钟上(RecordedAudio::since),并由 Hex 的转录器转录。自行结束的镜像(Event::PhoneEnded)会在监听器下一次收割时结束捕获。
  • 完成胶囊的路由标签读取 SettledCapture.route(先读取其答案,然后只读取胶囊自身无法知晓的投递项),并发送 CaptureCommand::{Send, Undo, Redirect}。已构建;offer 不会被绘制。
  • Experiments 下有一个由功能模块所有(D-5)的 Scrawl 面板:可选启用、快捷键、屏幕录制、转录器、捕获文件夹、保留策略,以及在 Scrawl 运行时显示“使用 Hex 进行捕获”(已构建;iPhone 随 ingest 加入)。
  • 屏幕录制权限在第一次捕获时或从面板请求,而不是在核心引导流程中。

路由与投递

  • 已构建(capture_host/routing.rs):Scrawl 的路由器(crates/router)在 Hex 的进程中运行,使用 capture.routing(从 Scrawl 导入一次;绝不是 Jev 键)和 Scrawl 自己的路由器文件夹,因此 scrawl router undo、规则建议和评估会将 Hex 的发送视为 Scrawl 的发送。一个 capture-look 线程在停止时读取标签页、终端和会话;唯一的 capture-route 线程(队列 16)在包写入后做出决定,等待规则的 3 秒撤销期结束,发送,并按顺序对新捕获执行胶囊的 Send、Undo 和 Redirect。每次更改最终都会进入 last.route。
  • 投递使用引擎的投递路径。排队的发送每 15 秒重试一次,但测试中、Scrawl.app 运行时,或任何进程在 ingest 端口上提供服务时除外(重试由该进程负责)。Hex 本身从不存储 OpenCode 服务器密码;引擎会像 Scrawl 那样读取它。
  • 未构建:用于路由的 live.ndjson 事件(id、分档、分数、模型、阶段和结果,绝不包含转录文本、摘要或窗口文本)。

与 Scrawl 共存

  • 同一时间只有一个所有者。当 Scrawl(dev.kitlangton.scrawl)运行时,Hex 不会注册捕获快捷键、不会运行保留策略、不会绑定 ingest 端口(47777),也不会运行投递重试。设置中会显示“使用 Hex 进行捕获”,但只有点击该选项时才会退出 Scrawl(已构建,不含 ingest)。
  • 配置:将 Scrawl 的设置一次性、只读地导入 settings.json 的 capture.* 键,每个都有对应的 hex settings 键(已构建)。ingest 令牌会移到 Hex 支持文件夹中仅所有者可访问的文件,以便已配对的手机继续工作(未构建)。
  • 捕获继续留在 Scrawl 的捕获文件夹中;Hex 在其中写入并清理它们(已构建)。

要添加的不变量

  • Capture 从不打开麦克风、安装事件监听(event tap),也不会加载自己的模型,并且从不阻塞或丢弃听写音频。
  • Capture 队列是有界的:捕获接收器(capture sink)、引擎的无障碍(accessibility)和保留(retention)队列(目前在 Scrawl 中是无界的;导入前请为它们设置边界),以及帧候选缓冲区(低于 Scrawl 的 384 MB)。
  • 每个进程只有一个引擎(引擎保持进程全局状态)。
  • 实验关闭意味着完全不进行任何捕获工作。

CLI

与其他一切功能一样,通过 POST /control 提供,并受构建选项控制(已构建;docs/cli.md):hex capture start|stop|cancel|status、hex capture list [--limit N]|show <capture>、hex capture send <capture> [--to <session>] 和 hex capture route <capture> [--ask-jev]。未构建:调试构建中 hex dev capture 下的引擎工具(autocrop 评估、捕获模拟、重新处理)。

分支上的顺序

  1. Scrawl 在自己的探索分支上准备引擎(其清单中的重构:lib.rs、从 main.rs 中拆出的管道、事件、配置、权限、剪贴板和转录器接缝、一个 Capture 类型、Cargo 特性)。
  2. 在此导入 crates/capture,包含仅限 macOS 的依赖和 CI。已构建:从 e351ddb 无历史复制。
  3. capture_host 带有实验门控、捕获接收器、Parakeet 词和生成 bundle 的无头 hex capture start|stop。已构建。
  4. 输入与 Escape,然后是 Rune 胶囊、选择器和带有场景与运动轨迹的墨迹叠加层。已构建。
  5. 进程内路由器、Scrawl 面板、导入和共存。已构建。
  6. 在录制的捕获上比较 Parakeet 和 SpeechAnalyzer 的词时间。已完成(10月25日):Parakeet 的延迟已在 capture_host 中修正。

10月18日的 experiment/scrawl 分支是一个已漂移的副本;feat/capture 取代了它的捕获接收器和词转录器,因此可以删除。

对 Scrawl API 的请求

由 engine/split 回答:Start::t0_boot_ns、带有 start_offset_ms 和 gaps 的 RecordedAudio、相对于第一个样本的词,以及默认的 SharedResources::none()。

然后在 86d7d6c 回答:Capture::stop 返回 SealedCapture(屏幕在 seal 时停止,finish 只负责写入)、无全局快捷键的逐捕获遥测、Engine::new 中不包含 TIS/TSM,以及来自 ConfigSource 的 autocrop 和 agentContext。

然后在 e351ddb(导入的提交)回答:当未设置接收器时,Engine::new 将 crate 的日志桥接到 Host::log,并且库仅在被要求时才写入 Scrawl 的日志文件或读取其配置;Engine::start 的文档说明它会阻塞;Scrawl 写入的 bundle 文件权限为 0600;Finished 报告 gaps 和 missing_transcript。

托管真实引擎后遗留的问题:

  • 没有纯音频目标:每次捕获都会录制屏幕,因此需要屏幕录制权限。Hex 的纯旁白测试使用假引擎。
  • Engine::start 在目标发现和 ScreenCaptureKit 上阻塞;Hex 在监听线程之外运行它。
  • finish 启动 scrawl-helper 来解码影片,因此库宿主需要附带并签名第二个可执行文件(Hex 通过 HEX_CAPTURE=1 这样做),否则会丢失全质量关键帧。进程内解码则可以省去第二个可执行文件。
  • phone、routing、delivery 和 ingest HTTP 代码无论特性如何都会编译,并且该 crate 会为其 Windows 目标将第二个 windows(0.61)拉入 Cargo.lock。
  • 公共 trait 中的 anyhow 使得 color_eyre 宿主必须转换每个错误。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 hex19/hex