@overcrow/mcp 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.
Files changed (461) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -2
  3. package/dist/audit/index.js +103 -0
  4. package/dist/audit/lexer.js +417 -0
  5. package/dist/audit/project.js +200 -0
  6. package/dist/audit/rules.js +661 -0
  7. package/dist/bootstrap/download.js +229 -0
  8. package/dist/bootstrap/install.js +280 -0
  9. package/dist/bootstrap/pin.js +85 -0
  10. package/dist/bootstrap/pin.json +119 -0
  11. package/dist/bootstrap/zip.js +258 -0
  12. package/dist/cli.js +200 -0
  13. package/dist/confine.js +244 -0
  14. package/dist/content/docs/en/cli.md +353 -0
  15. package/dist/content/docs/en/dev-channel.md +130 -0
  16. package/dist/content/docs/en/elements.md +469 -0
  17. package/dist/content/docs/en/forms.md +328 -0
  18. package/dist/content/docs/en/guide.md +253 -0
  19. package/dist/content/docs/en/index.md +85 -0
  20. package/dist/content/docs/en/limits.md +241 -0
  21. package/dist/content/docs/en/logic.md +446 -0
  22. package/dist/content/docs/en/manifest.md +381 -0
  23. package/dist/content/docs/en/mcp.md +165 -0
  24. package/dist/content/docs/en/package.md +131 -0
  25. package/dist/content/docs/en/publishing.md +162 -0
  26. package/dist/content/docs/en/reference.md +55 -0
  27. package/dist/content/docs/en/result-shapes.md +332 -0
  28. package/dist/content/docs/en/sdk.md +295 -0
  29. package/dist/content/docs/en/security.md +115 -0
  30. package/dist/content/docs/en/service-reference.md +344 -0
  31. package/dist/content/docs/en/services.md +517 -0
  32. package/dist/content/docs/en/style-properties.md +270 -0
  33. package/dist/content/docs/en/style.md +266 -0
  34. package/dist/content/docs/en/testing.md +400 -0
  35. package/dist/content/docs/en/view.md +338 -0
  36. package/dist/content/docs/en/widgets.md +76 -0
  37. package/dist/content/docs/fr/cli.md +367 -0
  38. package/dist/content/docs/fr/dev-channel.md +140 -0
  39. package/dist/content/docs/fr/elements.md +475 -0
  40. package/dist/content/docs/fr/forms.md +341 -0
  41. package/dist/content/docs/fr/guide.md +264 -0
  42. package/dist/content/docs/fr/index.md +90 -0
  43. package/dist/content/docs/fr/limits.md +244 -0
  44. package/dist/content/docs/fr/logic.md +461 -0
  45. package/dist/content/docs/fr/manifest.md +392 -0
  46. package/dist/content/docs/fr/mcp.md +173 -0
  47. package/dist/content/docs/fr/package.md +139 -0
  48. package/dist/content/docs/fr/publishing.md +172 -0
  49. package/dist/content/docs/fr/reference.md +59 -0
  50. package/dist/content/docs/fr/result-shapes.md +333 -0
  51. package/dist/content/docs/fr/sdk.md +301 -0
  52. package/dist/content/docs/fr/security.md +129 -0
  53. package/dist/content/docs/fr/service-reference.md +346 -0
  54. package/dist/content/docs/fr/services.md +540 -0
  55. package/dist/content/docs/fr/style-properties.md +272 -0
  56. package/dist/content/docs/fr/style.md +281 -0
  57. package/dist/content/docs/fr/testing.md +417 -0
  58. package/dist/content/docs/fr/view.md +352 -0
  59. package/dist/content/docs/fr/widgets.md +81 -0
  60. package/dist/content/examples/clock/LICENSE +21 -0
  61. package/dist/content/examples/clock/README.md +75 -0
  62. package/dist/content/examples/clock/listing.json +19 -0
  63. package/dist/content/examples/clock/locales/en.json +4 -0
  64. package/dist/content/examples/clock/locales/fr.json +4 -0
  65. package/dist/content/examples/clock/logic.ts +85 -0
  66. package/dist/content/examples/clock/manifest.json +44 -0
  67. package/dist/content/examples/clock/package.json +16 -0
  68. package/dist/content/examples/clock/style.ocss +26 -0
  69. package/dist/content/examples/clock/tests/hidden.scenario.json +68 -0
  70. package/dist/content/examples/clock/tests/load-logic.mjs +22 -0
  71. package/dist/content/examples/clock/tests/logic.test.mjs +89 -0
  72. package/dist/content/examples/clock/tests/options.scenario.json +108 -0
  73. package/dist/content/examples/clock/tests/preview.scenario.json +25 -0
  74. package/dist/content/examples/clock/tests/render.scenario.json +94 -0
  75. package/dist/content/examples/clock/tests/summer-time.scenario.json +74 -0
  76. package/dist/content/examples/clock/tests/ticks.scenario.json +120 -0
  77. package/dist/content/examples/clock/tsconfig.json +16 -0
  78. package/dist/content/examples/clock/view.ocml +8 -0
  79. package/dist/content/examples/countdown/LICENSE +20 -0
  80. package/dist/content/examples/countdown/listing.json +10 -0
  81. package/dist/content/examples/countdown/locales/en.json +15 -0
  82. package/dist/content/examples/countdown/locales/fr.json +15 -0
  83. package/dist/content/examples/countdown/logic.ts +179 -0
  84. package/dist/content/examples/countdown/manifest.json +34 -0
  85. package/dist/content/examples/countdown/package.json +15 -0
  86. package/dist/content/examples/countdown/style.ocss +94 -0
  87. package/dist/content/examples/countdown/tsconfig.json +16 -0
  88. package/dist/content/examples/countdown/view.ocml +42 -0
  89. package/dist/content/examples/fps/LICENSE +21 -0
  90. package/dist/content/examples/fps/README.md +64 -0
  91. package/dist/content/examples/fps/listing.json +19 -0
  92. package/dist/content/examples/fps/locales/en.json +11 -0
  93. package/dist/content/examples/fps/locales/fr.json +11 -0
  94. package/dist/content/examples/fps/logic.ts +64 -0
  95. package/dist/content/examples/fps/manifest.json +30 -0
  96. package/dist/content/examples/fps/package.json +16 -0
  97. package/dist/content/examples/fps/style.ocss +31 -0
  98. package/dist/content/examples/fps/tests/label.scenario.json +63 -0
  99. package/dist/content/examples/fps/tests/load-logic.mjs +22 -0
  100. package/dist/content/examples/fps/tests/logic.test.mjs +60 -0
  101. package/dist/content/examples/fps/tests/preview.scenario.json +29 -0
  102. package/dist/content/examples/fps/tests/refused.scenario.json +20 -0
  103. package/dist/content/examples/fps/tests/render.scenario.json +96 -0
  104. package/dist/content/examples/fps/tests/stale.scenario.json +91 -0
  105. package/dist/content/examples/fps/tests/unavailable.scenario.json +111 -0
  106. package/dist/content/examples/fps/tsconfig.json +16 -0
  107. package/dist/content/examples/fps/view.ocml +11 -0
  108. package/dist/content/examples/media/LICENSE +21 -0
  109. package/dist/content/examples/media/README.md +147 -0
  110. package/dist/content/examples/media/listing.json +19 -0
  111. package/dist/content/examples/media/locales/en.json +11 -0
  112. package/dist/content/examples/media/locales/fr.json +11 -0
  113. package/dist/content/examples/media/logic.ts +191 -0
  114. package/dist/content/examples/media/manifest.json +35 -0
  115. package/dist/content/examples/media/package.json +16 -0
  116. package/dist/content/examples/media/style.ocss +148 -0
  117. package/dist/content/examples/media/tests/covers.scenario.json +144 -0
  118. package/dist/content/examples/media/tests/gesture.scenario.json +173 -0
  119. package/dist/content/examples/media/tests/load-logic.mjs +22 -0
  120. package/dist/content/examples/media/tests/logic.test.mjs +176 -0
  121. package/dist/content/examples/media/tests/marquee.scenario.json +127 -0
  122. package/dist/content/examples/media/tests/preview.scenario.json +52 -0
  123. package/dist/content/examples/media/tests/read-only.scenario.json +53 -0
  124. package/dist/content/examples/media/tests/refused.scenario.json +22 -0
  125. package/dist/content/examples/media/tests/refused.test.mjs +31 -0
  126. package/dist/content/examples/media/tests/render.scenario.json +136 -0
  127. package/dist/content/examples/media/tests/states.scenario.json +257 -0
  128. package/dist/content/examples/media/tests/unavailable.scenario.json +120 -0
  129. package/dist/content/examples/media/tsconfig.json +16 -0
  130. package/dist/content/examples/media/view.ocml +41 -0
  131. package/dist/content/examples/notes/LICENSE +21 -0
  132. package/dist/content/examples/notes/README.md +219 -0
  133. package/dist/content/examples/notes/listing.json +19 -0
  134. package/dist/content/examples/notes/locales/en.json +25 -0
  135. package/dist/content/examples/notes/locales/fr.json +25 -0
  136. package/dist/content/examples/notes/logic.ts +799 -0
  137. package/dist/content/examples/notes/manifest.json +40 -0
  138. package/dist/content/examples/notes/package.json +16 -0
  139. package/dist/content/examples/notes/style.ocss +469 -0
  140. package/dist/content/examples/notes/tests/checks.scenario.json +237 -0
  141. package/dist/content/examples/notes/tests/create.scenario.json +260 -0
  142. package/dist/content/examples/notes/tests/delete.scenario.json +342 -0
  143. package/dist/content/examples/notes/tests/drafts.scenario.json +714 -0
  144. package/dist/content/examples/notes/tests/editor.scenario.json +232 -0
  145. package/dist/content/examples/notes/tests/frame.scenario.json +93 -0
  146. package/dist/content/examples/notes/tests/interactive.scenario.json +344 -0
  147. package/dist/content/examples/notes/tests/limits.scenario.json +1351 -0
  148. package/dist/content/examples/notes/tests/load-logic.mjs +22 -0
  149. package/dist/content/examples/notes/tests/logic.test.mjs +514 -0
  150. package/dist/content/examples/notes/tests/preview.scenario.json +99 -0
  151. package/dist/content/examples/notes/tests/read-only.scenario.json +105 -0
  152. package/dist/content/examples/notes/tests/refused.scenario.json +33 -0
  153. package/dist/content/examples/notes/tests/save.scenario.json +378 -0
  154. package/dist/content/examples/notes/tests/states.scenario.json +640 -0
  155. package/dist/content/examples/notes/tests/typing.scenario.json +562 -0
  156. package/dist/content/examples/notes/tests/unavailable.scenario.json +246 -0
  157. package/dist/content/examples/notes/tsconfig.json +16 -0
  158. package/dist/content/examples/notes/view.ocml +154 -0
  159. package/dist/content/examples/performance/LICENSE +21 -0
  160. package/dist/content/examples/performance/README.md +134 -0
  161. package/dist/content/examples/performance/listing.json +19 -0
  162. package/dist/content/examples/performance/locales/en.json +20 -0
  163. package/dist/content/examples/performance/locales/fr.json +20 -0
  164. package/dist/content/examples/performance/logic.ts +210 -0
  165. package/dist/content/examples/performance/manifest.json +83 -0
  166. package/dist/content/examples/performance/package.json +16 -0
  167. package/dist/content/examples/performance/style.ocss +75 -0
  168. package/dist/content/examples/performance/tests/fahrenheit.scenario.json +110 -0
  169. package/dist/content/examples/performance/tests/horizontal.scenario.json +96 -0
  170. package/dist/content/examples/performance/tests/load-logic.mjs +22 -0
  171. package/dist/content/examples/performance/tests/logic.test.mjs +226 -0
  172. package/dist/content/examples/performance/tests/menu.scenario.json +170 -0
  173. package/dist/content/examples/performance/tests/no-fps-source.scenario.json +47 -0
  174. package/dist/content/examples/performance/tests/preview.scenario.json +45 -0
  175. package/dist/content/examples/performance/tests/refused.scenario.json +20 -0
  176. package/dist/content/examples/performance/tests/refused.test.mjs +19 -0
  177. package/dist/content/examples/performance/tests/region.scenario.json +89 -0
  178. package/dist/content/examples/performance/tests/render.scenario.json +112 -0
  179. package/dist/content/examples/performance/tests/sources.scenario.json +151 -0
  180. package/dist/content/examples/performance/tests/stale.scenario.json +111 -0
  181. package/dist/content/examples/performance/tests/telemetry-only.scenario.json +44 -0
  182. package/dist/content/examples/performance/tests/thresholds.scenario.json +147 -0
  183. package/dist/content/examples/performance/tests/waiting.scenario.json +105 -0
  184. package/dist/content/examples/performance/tsconfig.json +16 -0
  185. package/dist/content/examples/performance/view.ocml +18 -0
  186. package/dist/content/examples/playervox-journal/LICENSE +21 -0
  187. package/dist/content/examples/playervox-journal/README.md +150 -0
  188. package/dist/content/examples/playervox-journal/listing.json +19 -0
  189. package/dist/content/examples/playervox-journal/locales/en.json +25 -0
  190. package/dist/content/examples/playervox-journal/locales/fr.json +25 -0
  191. package/dist/content/examples/playervox-journal/logic.ts +556 -0
  192. package/dist/content/examples/playervox-journal/manifest.json +19 -0
  193. package/dist/content/examples/playervox-journal/package.json +16 -0
  194. package/dist/content/examples/playervox-journal/style.ocss +142 -0
  195. package/dist/content/examples/playervox-journal/tests/changes.scenario.json +482 -0
  196. package/dist/content/examples/playervox-journal/tests/delete.scenario.json +432 -0
  197. package/dist/content/examples/playervox-journal/tests/frame.scenario.json +169 -0
  198. package/dist/content/examples/playervox-journal/tests/load-logic.mjs +22 -0
  199. package/dist/content/examples/playervox-journal/tests/logic.test.mjs +349 -0
  200. package/dist/content/examples/playervox-journal/tests/paging.scenario.json +428 -0
  201. package/dist/content/examples/playervox-journal/tests/preview.scenario.json +184 -0
  202. package/dist/content/examples/playervox-journal/tests/read-only.scenario.json +157 -0
  203. package/dist/content/examples/playervox-journal/tests/refused.scenario.json +39 -0
  204. package/dist/content/examples/playervox-journal/tests/scale.scenario.json +286 -0
  205. package/dist/content/examples/playervox-journal/tests/signed-out.scenario.json +134 -0
  206. package/dist/content/examples/playervox-journal/tests/states.scenario.json +741 -0
  207. package/dist/content/examples/playervox-journal/tests/unavailable.scenario.json +183 -0
  208. package/dist/content/examples/playervox-journal/tsconfig.json +16 -0
  209. package/dist/content/examples/playervox-journal/view.ocml +52 -0
  210. package/dist/content/examples/playervox-rating/LICENSE +21 -0
  211. package/dist/content/examples/playervox-rating/README.md +166 -0
  212. package/dist/content/examples/playervox-rating/listing.json +19 -0
  213. package/dist/content/examples/playervox-rating/locales/en.json +35 -0
  214. package/dist/content/examples/playervox-rating/locales/fr.json +35 -0
  215. package/dist/content/examples/playervox-rating/logic.ts +581 -0
  216. package/dist/content/examples/playervox-rating/manifest.json +19 -0
  217. package/dist/content/examples/playervox-rating/package.json +16 -0
  218. package/dist/content/examples/playervox-rating/style.ocss +333 -0
  219. package/dist/content/examples/playervox-rating/tests/account.scenario.json +125 -0
  220. package/dist/content/examples/playervox-rating/tests/bounds.scenario.json +73 -0
  221. package/dist/content/examples/playervox-rating/tests/draft.scenario.json +199 -0
  222. package/dist/content/examples/playervox-rating/tests/form.scenario.json +142 -0
  223. package/dist/content/examples/playervox-rating/tests/load-logic.mjs +22 -0
  224. package/dist/content/examples/playervox-rating/tests/logic.test.mjs +346 -0
  225. package/dist/content/examples/playervox-rating/tests/offline.scenario.json +142 -0
  226. package/dist/content/examples/playervox-rating/tests/preview.scenario.json +44 -0
  227. package/dist/content/examples/playervox-rating/tests/publish-keyboard.scenario.json +221 -0
  228. package/dist/content/examples/playervox-rating/tests/publish-pointer.scenario.json +314 -0
  229. package/dist/content/examples/playervox-rating/tests/read-only.scenario.json +70 -0
  230. package/dist/content/examples/playervox-rating/tests/refused.scenario.json +45 -0
  231. package/dist/content/examples/playervox-rating/tests/states.scenario.json +362 -0
  232. package/dist/content/examples/playervox-rating/tsconfig.json +16 -0
  233. package/dist/content/examples/playervox-rating/view.ocml +62 -0
  234. package/dist/content/examples/playervox-reviews/LICENSE +21 -0
  235. package/dist/content/examples/playervox-reviews/README.md +194 -0
  236. package/dist/content/examples/playervox-reviews/listing.json +19 -0
  237. package/dist/content/examples/playervox-reviews/locales/en.json +32 -0
  238. package/dist/content/examples/playervox-reviews/locales/fr.json +32 -0
  239. package/dist/content/examples/playervox-reviews/logic.ts +822 -0
  240. package/dist/content/examples/playervox-reviews/manifest.json +30 -0
  241. package/dist/content/examples/playervox-reviews/package.json +16 -0
  242. package/dist/content/examples/playervox-reviews/style.ocss +260 -0
  243. package/dist/content/examples/playervox-reviews/tests/account.scenario.json +249 -0
  244. package/dist/content/examples/playervox-reviews/tests/bounds.scenario.json +336 -0
  245. package/dist/content/examples/playervox-reviews/tests/changes.scenario.json +515 -0
  246. package/dist/content/examples/playervox-reviews/tests/filter.scenario.json +400 -0
  247. package/dist/content/examples/playervox-reviews/tests/frame.scenario.json +185 -0
  248. package/dist/content/examples/playervox-reviews/tests/keyboard.scenario.json +188 -0
  249. package/dist/content/examples/playervox-reviews/tests/load-logic.mjs +22 -0
  250. package/dist/content/examples/playervox-reviews/tests/logic.test.mjs +559 -0
  251. package/dist/content/examples/playervox-reviews/tests/offline-start.scenario.json +152 -0
  252. package/dist/content/examples/playervox-reviews/tests/offline.scenario.json +311 -0
  253. package/dist/content/examples/playervox-reviews/tests/paging.scenario.json +497 -0
  254. package/dist/content/examples/playervox-reviews/tests/preview.scenario.json +286 -0
  255. package/dist/content/examples/playervox-reviews/tests/reading.scenario.json +591 -0
  256. package/dist/content/examples/playervox-reviews/tests/refused.scenario.json +54 -0
  257. package/dist/content/examples/playervox-reviews/tests/scale.scenario.json +303 -0
  258. package/dist/content/examples/playervox-reviews/tests/states.scenario.json +700 -0
  259. package/dist/content/examples/playervox-reviews/tests/unavailable.scenario.json +192 -0
  260. package/dist/content/examples/playervox-reviews/tsconfig.json +16 -0
  261. package/dist/content/examples/playervox-reviews/view.ocml +110 -0
  262. package/dist/content/examples/playervox-score/LICENSE +21 -0
  263. package/dist/content/examples/playervox-score/README.md +131 -0
  264. package/dist/content/examples/playervox-score/listing.json +19 -0
  265. package/dist/content/examples/playervox-score/locales/en.json +23 -0
  266. package/dist/content/examples/playervox-score/locales/fr.json +23 -0
  267. package/dist/content/examples/playervox-score/logic.ts +430 -0
  268. package/dist/content/examples/playervox-score/manifest.json +47 -0
  269. package/dist/content/examples/playervox-score/package.json +16 -0
  270. package/dist/content/examples/playervox-score/style.ocss +247 -0
  271. package/dist/content/examples/playervox-score/tests/grades.scenario.json +279 -0
  272. package/dist/content/examples/playervox-score/tests/load-logic.mjs +22 -0
  273. package/dist/content/examples/playervox-score/tests/logic.test.mjs +229 -0
  274. package/dist/content/examples/playervox-score/tests/options.scenario.json +302 -0
  275. package/dist/content/examples/playervox-score/tests/preview.scenario.json +68 -0
  276. package/dist/content/examples/playervox-score/tests/pulse.scenario.json +157 -0
  277. package/dist/content/examples/playervox-score/tests/refused.scenario.json +21 -0
  278. package/dist/content/examples/playervox-score/tests/signed-out.scenario.json +46 -0
  279. package/dist/content/examples/playervox-score/tests/states.scenario.json +450 -0
  280. package/dist/content/examples/playervox-score/tests/unavailable.scenario.json +84 -0
  281. package/dist/content/examples/playervox-score/tsconfig.json +16 -0
  282. package/dist/content/examples/playervox-score/view.ocml +51 -0
  283. package/dist/content/examples/session/LICENSE +21 -0
  284. package/dist/content/examples/session/README.md +57 -0
  285. package/dist/content/examples/session/listing.json +19 -0
  286. package/dist/content/examples/session/locales/en.json +3 -0
  287. package/dist/content/examples/session/locales/fr.json +3 -0
  288. package/dist/content/examples/session/logic.ts +26 -0
  289. package/dist/content/examples/session/manifest.json +19 -0
  290. package/dist/content/examples/session/package.json +16 -0
  291. package/dist/content/examples/session/style.ocss +16 -0
  292. package/dist/content/examples/session/tests/hidden.scenario.json +45 -0
  293. package/dist/content/examples/session/tests/load-logic.mjs +22 -0
  294. package/dist/content/examples/session/tests/logic.test.mjs +37 -0
  295. package/dist/content/examples/session/tests/preview.scenario.json +28 -0
  296. package/dist/content/examples/session/tests/refused.scenario.json +20 -0
  297. package/dist/content/examples/session/tests/refused.test.mjs +16 -0
  298. package/dist/content/examples/session/tests/render.scenario.json +95 -0
  299. package/dist/content/examples/session/tests/ticks.scenario.json +139 -0
  300. package/dist/content/examples/session/tests/unknown.scenario.json +37 -0
  301. package/dist/content/examples/session/tsconfig.json +16 -0
  302. package/dist/content/examples/session/view.ocml +11 -0
  303. package/dist/content/examples/stopwatch/LICENSE +21 -0
  304. package/dist/content/examples/stopwatch/README.md +99 -0
  305. package/dist/content/examples/stopwatch/listing.json +19 -0
  306. package/dist/content/examples/stopwatch/locales/en.json +8 -0
  307. package/dist/content/examples/stopwatch/locales/fr.json +8 -0
  308. package/dist/content/examples/stopwatch/logic.ts +93 -0
  309. package/dist/content/examples/stopwatch/manifest.json +19 -0
  310. package/dist/content/examples/stopwatch/package.json +16 -0
  311. package/dist/content/examples/stopwatch/style.ocss +54 -0
  312. package/dist/content/examples/stopwatch/tests/errors.scenario.json +121 -0
  313. package/dist/content/examples/stopwatch/tests/gesture.scenario.json +154 -0
  314. package/dist/content/examples/stopwatch/tests/hidden.scenario.json +57 -0
  315. package/dist/content/examples/stopwatch/tests/hundredths.scenario.json +173 -0
  316. package/dist/content/examples/stopwatch/tests/load-logic.mjs +22 -0
  317. package/dist/content/examples/stopwatch/tests/logic.test.mjs +99 -0
  318. package/dist/content/examples/stopwatch/tests/preview.scenario.json +36 -0
  319. package/dist/content/examples/stopwatch/tests/read-only.scenario.json +42 -0
  320. package/dist/content/examples/stopwatch/tests/read-only.test.mjs +18 -0
  321. package/dist/content/examples/stopwatch/tests/refused.scenario.json +22 -0
  322. package/dist/content/examples/stopwatch/tests/refused.test.mjs +18 -0
  323. package/dist/content/examples/stopwatch/tests/render.scenario.json +105 -0
  324. package/dist/content/examples/stopwatch/tests/states.scenario.json +246 -0
  325. package/dist/content/examples/stopwatch/tests/unknown.scenario.json +40 -0
  326. package/dist/content/examples/stopwatch/tsconfig.json +16 -0
  327. package/dist/content/examples/stopwatch/view.ocml +29 -0
  328. package/dist/content/examples/twitch-chat/LICENSE +21 -0
  329. package/dist/content/examples/twitch-chat/README.md +283 -0
  330. package/dist/content/examples/twitch-chat/listing.json +19 -0
  331. package/dist/content/examples/twitch-chat/locales/en.json +52 -0
  332. package/dist/content/examples/twitch-chat/locales/fr.json +52 -0
  333. package/dist/content/examples/twitch-chat/logic.ts +887 -0
  334. package/dist/content/examples/twitch-chat/manifest.json +33 -0
  335. package/dist/content/examples/twitch-chat/package.json +16 -0
  336. package/dist/content/examples/twitch-chat/style.ocss +544 -0
  337. package/dist/content/examples/twitch-chat/tests/account.scenario.json +325 -0
  338. package/dist/content/examples/twitch-chat/tests/burst.scenario.json +1866 -0
  339. package/dist/content/examples/twitch-chat/tests/channel-refused.scenario.json +372 -0
  340. package/dist/content/examples/twitch-chat/tests/channel.scenario.json +480 -0
  341. package/dist/content/examples/twitch-chat/tests/draft.scenario.json +279 -0
  342. package/dist/content/examples/twitch-chat/tests/fade.scenario.json +269 -0
  343. package/dist/content/examples/twitch-chat/tests/failures.scenario.json +420 -0
  344. package/dist/content/examples/twitch-chat/tests/favorites.scenario.json +376 -0
  345. package/dist/content/examples/twitch-chat/tests/frame.scenario.json +152 -0
  346. package/dist/content/examples/twitch-chat/tests/lifetime.scenario.json +186 -0
  347. package/dist/content/examples/twitch-chat/tests/load-logic.mjs +22 -0
  348. package/dist/content/examples/twitch-chat/tests/logic.test.mjs +1053 -0
  349. package/dist/content/examples/twitch-chat/tests/passive.scenario.json +536 -0
  350. package/dist/content/examples/twitch-chat/tests/preview.scenario.json +147 -0
  351. package/dist/content/examples/twitch-chat/tests/read-only.scenario.json +202 -0
  352. package/dist/content/examples/twitch-chat/tests/read-only.test.mjs +63 -0
  353. package/dist/content/examples/twitch-chat/tests/refused.scenario.json +65 -0
  354. package/dist/content/examples/twitch-chat/tests/refused.test.mjs +43 -0
  355. package/dist/content/examples/twitch-chat/tests/render.scenario.json +347 -0
  356. package/dist/content/examples/twitch-chat/tests/reply.scenario.json +384 -0
  357. package/dist/content/examples/twitch-chat/tests/send-refused.scenario.json +383 -0
  358. package/dist/content/examples/twitch-chat/tests/send.scenario.json +300 -0
  359. package/dist/content/examples/twitch-chat/tests/states.scenario.json +455 -0
  360. package/dist/content/examples/twitch-chat/tests/unavailable.scenario.json +256 -0
  361. package/dist/content/examples/twitch-chat/tests/unread.scenario.json +997 -0
  362. package/dist/content/examples/twitch-chat/tsconfig.json +16 -0
  363. package/dist/content/examples/twitch-chat/view.ocml +141 -0
  364. package/dist/content/examples/warframe-market/LICENSE +21 -0
  365. package/dist/content/examples/warframe-market/README.md +176 -0
  366. package/dist/content/examples/warframe-market/listing.json +19 -0
  367. package/dist/content/examples/warframe-market/locales/en.json +44 -0
  368. package/dist/content/examples/warframe-market/locales/fr.json +44 -0
  369. package/dist/content/examples/warframe-market/logic.ts +1265 -0
  370. package/dist/content/examples/warframe-market/manifest.json +92 -0
  371. package/dist/content/examples/warframe-market/package.json +16 -0
  372. package/dist/content/examples/warframe-market/style.ocss +422 -0
  373. package/dist/content/examples/warframe-market/tests/bounds.scenario.json +60 -0
  374. package/dist/content/examples/warframe-market/tests/cached.scenario.json +70 -0
  375. package/dist/content/examples/warframe-market/tests/detail.scenario.json +251 -0
  376. package/dist/content/examples/warframe-market/tests/errors.scenario.json +105 -0
  377. package/dist/content/examples/warframe-market/tests/fixtures.json +295 -0
  378. package/dist/content/examples/warframe-market/tests/load-logic.mjs +22 -0
  379. package/dist/content/examples/warframe-market/tests/logic.test.mjs +505 -0
  380. package/dist/content/examples/warframe-market/tests/no-clipboard.scenario.json +104 -0
  381. package/dist/content/examples/warframe-market/tests/passive.scenario.json +87 -0
  382. package/dist/content/examples/warframe-market/tests/preview.scenario.json +146 -0
  383. package/dist/content/examples/warframe-market/tests/refresh.scenario.json +56 -0
  384. package/dist/content/examples/warframe-market/tests/refused.scenario.json +74 -0
  385. package/dist/content/examples/warframe-market/tests/render.scenario.json +210 -0
  386. package/dist/content/examples/warframe-market/tests/search.scenario.json +189 -0
  387. package/dist/content/examples/warframe-market/tests/unavailable.scenario.json +54 -0
  388. package/dist/content/examples/warframe-market/tsconfig.json +16 -0
  389. package/dist/content/examples/warframe-market/view.ocml +116 -0
  390. package/dist/content/examples/weather/LICENSE +20 -0
  391. package/dist/content/examples/weather/listing.json +10 -0
  392. package/dist/content/examples/weather/locales/en.json +9 -0
  393. package/dist/content/examples/weather/locales/fr.json +9 -0
  394. package/dist/content/examples/weather/logic.ts +62 -0
  395. package/dist/content/examples/weather/manifest.json +51 -0
  396. package/dist/content/examples/weather/package.json +15 -0
  397. package/dist/content/examples/weather/style.ocss +29 -0
  398. package/dist/content/examples/weather/tsconfig.json +16 -0
  399. package/dist/content/examples/weather/view.ocml +12 -0
  400. package/dist/content/index.json +3601 -0
  401. package/dist/content/reference/errors.json +1712 -0
  402. package/dist/content/reference/limits.json +1154 -0
  403. package/dist/content/reference/manifest.md +223 -0
  404. package/dist/content/reference/permissions.json +413 -0
  405. package/dist/content/templates/blank/locales/en.json +3 -0
  406. package/dist/content/templates/blank/locales/fr.json +3 -0
  407. package/dist/content/templates/blank/logic.ts +7 -0
  408. package/dist/content/templates/blank/manifest.json +16 -0
  409. package/dist/content/templates/blank/style.ocss +10 -0
  410. package/dist/content/templates/blank/tests/example.scenario.json +10 -0
  411. package/dist/content/templates/blank/view.ocml +6 -0
  412. package/dist/content/templates/chart/locales/en.json +3 -0
  413. package/dist/content/templates/chart/locales/fr.json +3 -0
  414. package/dist/content/templates/chart/logic.ts +27 -0
  415. package/dist/content/templates/chart/manifest.json +16 -0
  416. package/dist/content/templates/chart/style.ocss +27 -0
  417. package/dist/content/templates/chart/tests/example.scenario.json +10 -0
  418. package/dist/content/templates/chart/view.ocml +10 -0
  419. package/dist/content/templates/counter/locales/en.json +4 -0
  420. package/dist/content/templates/counter/locales/fr.json +4 -0
  421. package/dist/content/templates/counter/logic.ts +20 -0
  422. package/dist/content/templates/counter/manifest.json +16 -0
  423. package/dist/content/templates/counter/style.ocss +26 -0
  424. package/dist/content/templates/counter/tests/example.scenario.json +11 -0
  425. package/dist/content/templates/counter/view.ocml +13 -0
  426. package/dist/content/templates/list/locales/en.json +8 -0
  427. package/dist/content/templates/list/locales/fr.json +8 -0
  428. package/dist/content/templates/list/logic.ts +35 -0
  429. package/dist/content/templates/list/manifest.json +16 -0
  430. package/dist/content/templates/list/style.ocss +42 -0
  431. package/dist/content/templates/list/tests/example.scenario.json +10 -0
  432. package/dist/content/templates/list/view.ocml +17 -0
  433. package/dist/content/templates/shared/LICENSE +20 -0
  434. package/dist/content/templates/shared/package.json +14 -0
  435. package/dist/content/templates/shared/tsconfig.json +16 -0
  436. package/dist/content.js +68 -0
  437. package/dist/env.js +156 -0
  438. package/dist/fingerprint.js +32 -0
  439. package/dist/ids.js +27 -0
  440. package/dist/index.js +82 -0
  441. package/dist/knowledge.js +222 -0
  442. package/dist/npm.js +149 -0
  443. package/dist/prompts.js +47 -0
  444. package/dist/resources.js +82 -0
  445. package/dist/run.js +120 -0
  446. package/dist/server.js +43 -0
  447. package/dist/session.js +205 -0
  448. package/dist/sources.js +218 -0
  449. package/dist/text.js +80 -0
  450. package/dist/texts.js +44 -0
  451. package/dist/tools/audit.js +105 -0
  452. package/dist/tools/build.js +453 -0
  453. package/dist/tools/common.js +122 -0
  454. package/dist/tools/docs.js +196 -0
  455. package/dist/tools/preview.js +87 -0
  456. package/dist/tools/project.js +178 -0
  457. package/dist/tools/setup.js +146 -0
  458. package/dist/tools/submission.js +369 -0
  459. package/dist/version.js +3 -0
  460. package/npm-shrinkwrap.json +402 -0
  461. package/package.json +52 -4
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023"],
5
+ "types": [],
6
+ "module": "ES2022",
7
+ "moduleResolution": "bundler",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "isolatedModules": true,
11
+ "verbatimModuleSyntax": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true
14
+ },
15
+ "include": ["logic.ts"]
16
+ }
@@ -0,0 +1,8 @@
1
+ <!-- Clock: the local time of day and, optionally, the date on a second line
2
+ (parity sheet: playervox-overcrow docs/builtin-parity/clock.md). -->
3
+ <box class="clock" label={clockLabel(state.now, state.seconds, state.showDate, state.order)}>
4
+ <text class="time">{clockTime(state.now, state.seconds)}</text>
5
+ <if test={state.showDate}>
6
+ <text class="date">{clockDate(state.now, state.order)}</text>
7
+ </if>
8
+ </box>
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) the authors of Countdown
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ {
2
+ "author": "Example Studio",
3
+ "spdxLicense": "MIT",
4
+ "sourceUrl": "https://github.com/example/countdown-widget",
5
+ "defaultLocale": "en",
6
+ "localizations": [
7
+ { "locale": "en", "name": "Countdown", "description": "A countdown of a few minutes that counts the rounds you finish." },
8
+ { "locale": "fr", "name": "Compte à rebours", "description": "Un compte à rebours de quelques minutes, qui compte les tours terminés." }
9
+ ]
10
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "duration": "Duration",
3
+ "minutes": "{count} min",
4
+ "pause": "Pause",
5
+ "remaining": "Time left",
6
+ "repeat": "Start again when it ends",
7
+ "reset-rounds": "Reset the rounds",
8
+ "rounds": "Rounds",
9
+ "rounds-drawn": "{count} finished rounds",
10
+ "start": "Start",
11
+ "state": "State",
12
+ "state-done": "Finished",
13
+ "state-paused": "Paused",
14
+ "state-running": "Running"
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "duration": "Durée",
3
+ "minutes": "{count} min",
4
+ "pause": "Mettre en pause",
5
+ "remaining": "Temps restant",
6
+ "repeat": "Recommencer à la fin",
7
+ "reset-rounds": "Remettre les tours à zéro",
8
+ "rounds": "Tours",
9
+ "rounds-drawn": "{count} tours terminés",
10
+ "start": "Démarrer",
11
+ "state": "État",
12
+ "state-done": "Terminé",
13
+ "state-paused": "En pause",
14
+ "state-running": "En cours"
15
+ }
@@ -0,0 +1,179 @@
1
+ // A countdown of a few minutes. It counts the rounds the user finished,
2
+ // keeps that count in the widget's storage and draws one dot per round.
3
+ import {
4
+ draw,
5
+ formatDuration,
6
+ initState,
7
+ log,
8
+ onHost,
9
+ onMenu,
10
+ option,
11
+ storage,
12
+ t,
13
+ timers,
14
+ type DrawCommand,
15
+ type Timer,
16
+ } from "@overcrow/sdk";
17
+
18
+ const MINUTE = 60_000;
19
+ /** Dots drawn at most; the count itself goes on. */
20
+ const MAX_DOTS = 12;
21
+
22
+ declare module "@overcrow/sdk" {
23
+ interface WidgetState {
24
+ durations: number[];
25
+ minutes: number;
26
+ remainingMs: number;
27
+ running: boolean;
28
+ repeat: boolean;
29
+ rounds: number;
30
+ showRounds: boolean;
31
+ menu: boolean;
32
+ }
33
+ }
34
+
35
+ const state = initState({
36
+ durations: [5, 15, 25, 50],
37
+ minutes: 25,
38
+ remainingMs: 25 * MINUTE,
39
+ running: false,
40
+ repeat: false,
41
+ rounds: 0,
42
+ showRounds: option("show-rounds", true),
43
+ menu: false,
44
+ });
45
+
46
+ export function total(minutes: number): number {
47
+ return minutes * MINUTE;
48
+ }
49
+
50
+ /** `24:59`, counted down to the second. */
51
+ export function timeLeft(ms: number): string {
52
+ return formatDuration(Math.ceil(ms / 1000) * 1000);
53
+ }
54
+
55
+ /** The value of an `option` is text. */
56
+ export function minutesValue(minutes: number): string {
57
+ return String(minutes);
58
+ }
59
+
60
+ export function ringClass(ms: number): string {
61
+ return ms === 0 ? "ring done" : "ring";
62
+ }
63
+
64
+ export function startLabel(running: boolean): string {
65
+ return t(running ? "pause" : "start");
66
+ }
67
+
68
+ export function stateText(running: boolean, ms: number): string {
69
+ return t(running ? "state-running" : ms === 0 ? "state-done" : "state-paused");
70
+ }
71
+
72
+ /** One dot per finished round, on the `dots` canvas. */
73
+ function paint(): void {
74
+ const dots: DrawCommand[] = [];
75
+ for (let index = 0; index < Math.min(state.rounds, MAX_DOTS); index += 1) {
76
+ dots.push(["circle", 6 + index * 14, 6, 4], ["fill", "var(--color-accent)"]);
77
+ }
78
+ draw("dots", dots);
79
+ }
80
+
81
+ function setRounds(rounds: number): void {
82
+ state.rounds = rounds;
83
+ paint();
84
+ // Storage needs the user's consent: without it the count lasts as long
85
+ // as the widget runs.
86
+ storage.set({ key: "rounds", value: rounds }).catch(() => {});
87
+ }
88
+
89
+ let ticker: Timer | undefined;
90
+ /** When the running countdown ends, in `Date.now()` time. */
91
+ let endsAt = 0;
92
+
93
+ function stop(): void {
94
+ ticker?.cancel();
95
+ ticker = undefined;
96
+ state.running = false;
97
+ }
98
+
99
+ function start(): void {
100
+ if (state.remainingMs === 0) {
101
+ state.remainingMs = total(state.minutes);
102
+ }
103
+ endsAt = Date.now() + state.remainingMs;
104
+ state.running = true;
105
+ ticker = timers.every(250, tick);
106
+ }
107
+
108
+ // A timer does not tick while the widget is hidden: the time left comes
109
+ // from the clock, not from the number of ticks.
110
+ function tick(): void {
111
+ state.remainingMs = Math.max(0, endsAt - Date.now());
112
+ if (state.remainingMs > 0) {
113
+ return;
114
+ }
115
+ stop();
116
+ setRounds(state.rounds + 1);
117
+ log.info(`round ${state.rounds} finished`);
118
+ if (state.repeat) {
119
+ start();
120
+ }
121
+ }
122
+
123
+ export function toggle(): void {
124
+ if (state.running) {
125
+ stop();
126
+ } else {
127
+ start();
128
+ }
129
+ }
130
+
131
+ export function setMinutes(event: { value: unknown }): void {
132
+ const minutes = Number(event.value);
133
+ if (state.durations.includes(minutes)) {
134
+ state.minutes = minutes;
135
+ state.remainingMs = total(minutes);
136
+ }
137
+ }
138
+
139
+ export function setRepeat(event: { value: unknown }): void {
140
+ state.repeat = event.value === true;
141
+ }
142
+
143
+ export function openMenu(): void {
144
+ state.menu = true;
145
+ }
146
+
147
+ export function closeMenu(): void {
148
+ state.menu = false;
149
+ }
150
+
151
+ export function resetRounds(): void {
152
+ state.menu = false;
153
+ setRounds(0);
154
+ }
155
+
156
+ // The `reset-rounds` row of the options menu does the same as the button
157
+ // of the context menu.
158
+ onMenu((row) => {
159
+ if (row === "reset-rounds") {
160
+ resetRounds();
161
+ }
162
+ });
163
+
164
+ onHost((changed) => {
165
+ if (changed.includes("options")) {
166
+ state.showRounds = option("show-rounds", true);
167
+ paint();
168
+ }
169
+ });
170
+
171
+ storage.get({ key: "rounds" }).then(
172
+ (stored) => {
173
+ if (typeof stored === "number" && Number.isInteger(stored) && stored > 0) {
174
+ state.rounds = stored;
175
+ paint();
176
+ }
177
+ },
178
+ () => {},
179
+ );
@@ -0,0 +1,34 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "apiVersion": 1,
4
+ "id": "com.example.countdown",
5
+ "version": "1.0.0",
6
+ "name": { "en": "Countdown", "fr": "Compte à rebours" },
7
+ "sizing": {
8
+ "fit": "none",
9
+ "preferred": { "width": 220, "height": 190 },
10
+ "min": { "width": 180, "height": 160 },
11
+ "max": { "width": 480, "height": 400 }
12
+ },
13
+ "permissions": {
14
+ "storage": true
15
+ },
16
+ "wrapper": {
17
+ "menu": [
18
+ {
19
+ "type": "toggle",
20
+ "id": "show-rounds",
21
+ "label": { "en": "Show finished rounds", "fr": "Afficher les tours terminés" },
22
+ "icon": "circle-check",
23
+ "default": true
24
+ },
25
+ {
26
+ "type": "action",
27
+ "id": "reset-rounds",
28
+ "label": { "en": "Reset the rounds", "fr": "Remettre les tours à zéro" },
29
+ "icon": "rotate-ccw",
30
+ "visibleWhen": "show-rounds"
31
+ }
32
+ ]
33
+ }
34
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "overcrow-example-countdown",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "scripts": {
8
+ "check": "overcrow-widget check",
9
+ "package": "overcrow-widget package"
10
+ },
11
+ "devDependencies": {
12
+ "@overcrow/sdk": "1.0.0",
13
+ "typescript": "6.0.3"
14
+ }
15
+ }
@@ -0,0 +1,94 @@
1
+ .countdown {
2
+ flex-direction: column;
3
+ gap: var(--space-3);
4
+ padding: var(--space-4);
5
+ }
6
+
7
+ /* The time sits in the middle of the ring: both share one grid cell. */
8
+ .dial {
9
+ display: grid;
10
+ grid-template-columns: 72px;
11
+ grid-template-rows: 72px;
12
+ justify-content: center;
13
+ justify-items: center;
14
+ align-items: center;
15
+ }
16
+
17
+ .ring {
18
+ grid-column: 1;
19
+ grid-row: 1;
20
+ width: 72px;
21
+ height: 72px;
22
+ color: var(--color-accent);
23
+ }
24
+
25
+ .ring.done {
26
+ color: var(--color-success);
27
+ animation: countdown-pulse 800ms ease-in-out 3 alternate;
28
+ }
29
+
30
+ @keyframes countdown-pulse {
31
+ from { opacity: 1; }
32
+ to { opacity: 0.4; }
33
+ }
34
+
35
+ .time {
36
+ grid-column: 1;
37
+ grid-row: 1;
38
+ font-family: var(--font-mono);
39
+ font-size: var(--font-size-body);
40
+ font-variant-numeric: tabular-nums;
41
+ }
42
+
43
+ .controls {
44
+ align-items: center;
45
+ gap: var(--space-2);
46
+ }
47
+
48
+ .duration {
49
+ flex-grow: 1;
50
+ }
51
+
52
+ .start {
53
+ width: var(--control-height);
54
+ height: var(--control-height);
55
+ justify-content: center;
56
+ align-items: center;
57
+ border-radius: var(--radius-md);
58
+ background: var(--color-surface-raised);
59
+ transition: background-color var(--duration-fast) ease-out;
60
+ }
61
+
62
+ .start:hover {
63
+ background: var(--color-surface-hover);
64
+ }
65
+
66
+ .start:focus {
67
+ border: 1px solid var(--color-accent);
68
+ }
69
+
70
+ .repeat:checked {
71
+ color: var(--color-accent);
72
+ }
73
+
74
+ .stat {
75
+ justify-content: space-between;
76
+ font-size: var(--font-size-small);
77
+ }
78
+
79
+ .stat-name {
80
+ color: var(--color-text-muted);
81
+ }
82
+
83
+ .dots {
84
+ height: 12px;
85
+ }
86
+
87
+ .menu-row {
88
+ padding: var(--space-2) var(--space-4);
89
+ border-radius: var(--radius-sm);
90
+ }
91
+
92
+ .menu-row:hover {
93
+ background: var(--color-surface-hover);
94
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023"],
5
+ "types": [],
6
+ "module": "ES2022",
7
+ "moduleResolution": "bundler",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "isolatedModules": true,
11
+ "verbatimModuleSyntax": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true
14
+ },
15
+ "include": ["logic.ts"]
16
+ }
@@ -0,0 +1,42 @@
1
+ <!-- A countdown: a ring that empties, a duration chosen in a list, and the
2
+ finished rounds drawn as dots. A right click opens a small menu. -->
3
+ <component name="stat" props="name value">
4
+ <box class="stat">
5
+ <text class="stat-name">{name}</text>
6
+ <text class="stat-value">{value}</text>
7
+ </box>
8
+ </component>
9
+
10
+ <box ref="panel" class="countdown" on:contextmenu={openMenu}>
11
+ <box class="dial">
12
+ <gauge class={ringClass(state.remainingMs)} value={state.remainingMs} max={total(state.minutes)} label={t("remaining")}/>
13
+ <text class="time">{timeLeft(state.remainingMs)}</text>
14
+ </box>
15
+ <box class="controls">
16
+ <select class="duration" value={minutesValue(state.minutes)} label={t("duration")} disabled={state.running} on:change={setMinutes}>
17
+ <for each={state.durations} as="minutes" key={minutes}>
18
+ <option value={minutesValue(minutes)}>{t("minutes", { count: minutes })}</option>
19
+ </for>
20
+ </select>
21
+ <button class="start" label={startLabel(state.running)} on:activate={toggle}>
22
+ <if test={state.running}>
23
+ <icon name="pause"/>
24
+ </if>
25
+ <else>
26
+ <icon name="play"/>
27
+ </else>
28
+ </button>
29
+ <toggle class="repeat" label={t("repeat")} tooltip={t("repeat")} checked={state.repeat} on:change={setRepeat}/>
30
+ </box>
31
+ <stat name={t("state")} value={stateText(state.running, state.remainingMs)}/>
32
+ <if test={state.showRounds}>
33
+ <stat name={t("rounds")} value={state.rounds}/>
34
+ <canvas ref="dots" class="dots" label={t("rounds-drawn", { count: state.rounds })}/>
35
+ </if>
36
+ </box>
37
+
38
+ <popover anchor="panel" placement="pointer" open={state.menu} on:dismiss={closeMenu}>
39
+ <button class="menu-row" on:activate={resetRounds}>
40
+ <text class="menu-text">{t("reset-rounds")}</text>
41
+ </button>
42
+ </popover>
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Valhallab SASU
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # FPS
2
+
3
+ `com.playervox.overcrow.fps` — the frame rate the game presents, observed
4
+ from outside the game. A built-in of OverCrow, written against the public
5
+ `@overcrow/sdk` and packaged with `overcrow-widget` like any creator's
6
+ widget. MIT.
7
+
8
+ ## What it shows
9
+
10
+ | State | Shows |
11
+ | --- | --- |
12
+ | A reading | `144 FPS` (the unit muted, 12 px semibold) |
13
+ | A gap of the capture | the last reading, exactly as it was |
14
+ | No reading yet | `— FPS`, muted |
15
+ | Label off | the value alone |
16
+
17
+ Hovering the widget in Interactive mode shows one sentence, the
18
+ measurement status's (`ready`, `waiting`, `unsupported`,
19
+ `permission_denied`, `ambiguous`, `events_lost`, `unavailable`).
20
+
21
+ ## Menu
22
+
23
+ | Row | Type | Default |
24
+ | --- | --- | --- |
25
+ | Show “FPS” label / Afficher le libellé « FPS » | toggle `show-label` | on |
26
+
27
+ ## Permissions
28
+
29
+ `fps.read` (not sensitive), and `requires: ["fps"]`: on a machine without a
30
+ frame-rate source OverCrow neither starts nor shows the widget, and keeps
31
+ its place for when the source comes back.
32
+
33
+ ## How it works
34
+
35
+ `fps.subscribe` gives `{ fps, stale, status }`; the host keeps the last
36
+ value of the game through a gap of its capture until the next one, so the
37
+ widget runs no timer and shows the value as it is: a value shown never
38
+ disappears and shows no sign of its age (`stale` is not drawn). The
39
+ accessible label is "144 frames per second" or "Frame rate unavailable".
40
+
41
+ ## Tests
42
+
43
+ - `tests/logic.test.mjs`: the logic on `@overcrow/sdk/testing` (value,
44
+ colour, sentences, labels, updates, the label row).
45
+ - Scenarios with their reference images: `render` (both themes and
46
+ languages at 100 and 150 %), `stale` (a reading kept through a gap looks
47
+ unchanged), `unavailable` (the statuses, the
48
+ service stopping), `label`, `refused`.
49
+
50
+ ## Cost
51
+
52
+ Measured on 2026-09-30 with OverCrow's release build, on an AMD Ryzen 7
53
+ 5800X3D Linux workstation and in a Windows 11 virtual machine (2 vCPU):
54
+
55
+ | | Linux | Windows (VM) |
56
+ | --- | --- | --- |
57
+ | Widget start, warm, into the overlay's runtime | 7 ms at most | — |
58
+ | VM memory | 0.55–0.59 MiB anonymous | similar to the Clock's 0.83 MiB private working set |
59
+ | VM CPU | one short turn per new reading | — |
60
+ | Overlay frames | one per new reading | — |
61
+
62
+ With the Clock and Session widgets beside it, the overlay's process grows
63
+ by about 2 MB per widget and stays at 0.15 % of one core with a reading
64
+ each second; nothing runs while the overlay is hidden.
@@ -0,0 +1,19 @@
1
+ {
2
+ "author": "PlayerVox",
3
+ "spdxLicense": "MIT",
4
+ "sourceUrl": "https://github.com/Valhallab/playervox-overcrow-releases/tree/main/widgets/fps",
5
+ "preview": "assets/preview.png",
6
+ "defaultLocale": "en",
7
+ "localizations": [
8
+ {
9
+ "locale": "en",
10
+ "name": "FPS",
11
+ "description": "Shows the game’s presented frame rate, when the host has a frame rate source."
12
+ },
13
+ {
14
+ "locale": "fr",
15
+ "name": "FPS",
16
+ "description": "Affiche la fréquence d’images présentée par le jeu, quand l’hôte dispose d’une source."
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "label": "{fps} frames per second",
3
+ "label-none": "Frame rate unavailable",
4
+ "hint-ready": "Frames the game presented, observed from outside the game: its presentation rate, not the refresh rate of the display.",
5
+ "hint-waiting": "Waiting for frames from the game window. A paused game keeps this value unavailable.",
6
+ "hint-unsupported": "The frame rate of this game window cannot be measured on this system.",
7
+ "hint-permission_denied": "OverCrow was denied access to the game's frame events.",
8
+ "hint-ambiguous": "Several presentation sources prevent a reliable FPS measurement.",
9
+ "hint-events_lost": "Frame events were lost. No reliable FPS measurement is available.",
10
+ "hint-unavailable": "FPS capture is not available. See Diagnostics in the Control Center."
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "label": "{fps} images par seconde",
3
+ "label-none": "FPS indisponibles",
4
+ "hint-ready": "Images présentées par le jeu, observées de l’extérieur du jeu : son rythme de présentation, pas la fréquence de l’écran.",
5
+ "hint-waiting": "En attente d’images de la fenêtre de jeu. Un jeu en pause laisse cette valeur indisponible.",
6
+ "hint-unsupported": "Les FPS de cette fenêtre de jeu ne peuvent pas être mesurés sur ce système.",
7
+ "hint-permission_denied": "OverCrow s’est vu refuser l’accès aux événements d’image du jeu.",
8
+ "hint-ambiguous": "Plusieurs sources de présentation empêchent une mesure fiable des FPS.",
9
+ "hint-events_lost": "Des événements d’image ont été perdus. Aucune mesure fiable des FPS n’est disponible.",
10
+ "hint-unavailable": "La capture FPS n’est pas disponible. Ouvrez Diagnostic dans le Centre de contrôle."
11
+ }
@@ -0,0 +1,64 @@
1
+ // FPS: the game's presented frame rate. The host measures it outside the
2
+ // game and keeps the last value through a gap until the next one; the
3
+ // widget shows it as it is, with no sign of its age (a value shown never
4
+ // disappears or changes look while the game runs), and a sentence for each
5
+ // measurement status.
6
+ import { fps, hasGrant, initState, onHost, option, t, type Fps } from "@overcrow/sdk";
7
+
8
+ type Status = Fps["status"];
9
+
10
+ declare module "@overcrow/sdk" {
11
+ interface WidgetState {
12
+ fps: number | null;
13
+ status: Status;
14
+ showLabel: boolean;
15
+ }
16
+ }
17
+
18
+ const state = initState({
19
+ fps: null as number | null,
20
+ status: "waiting" as Status,
21
+ showLabel: option("show-label", true),
22
+ });
23
+
24
+ /** The integer value, or an em dash without one. */
25
+ export function fpsValue(value: number | null): string {
26
+ return value === null ? "—" : String(Math.round(value));
27
+ }
28
+
29
+ /** A value is primary, fresh or kept through a gap; no value is muted. */
30
+ export function valueClass(value: number | null): string {
31
+ return value === null ? "value muted" : "value";
32
+ }
33
+
34
+ export function fpsLabel(value: number | null): string {
35
+ return value === null ? t("label-none") : t("label", { fps: fpsValue(value) });
36
+ }
37
+
38
+ /** The hover sentence of the measurement status. */
39
+ export function fpsTooltip(status: Status): string {
40
+ return t(`hint-${status}`);
41
+ }
42
+
43
+ /** The state an update, or a failure of the subscription, leaves. */
44
+ export function reading(
45
+ update: { ok: true; value: Fps } | { ok: false },
46
+ ): Pick<Fps, "fps" | "status"> {
47
+ return update.ok
48
+ ? { fps: update.value.fps, status: update.value.status }
49
+ : { fps: null, status: "unavailable" };
50
+ }
51
+
52
+ onHost((changed) => {
53
+ if (changed.includes("options")) {
54
+ state.showLabel = option("show-label", true);
55
+ }
56
+ });
57
+
58
+ if (hasGrant("fps.read")) {
59
+ fps.subscribe((update) => {
60
+ Object.assign(state, reading(update));
61
+ });
62
+ } else {
63
+ state.status = "unavailable";
64
+ }