Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cdn/RUNTIMES.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,14 @@
"detectorSha256": "54882ff7faebb854f79505b4f00313ea9a8ef927741c1501ac60d98022fe356e",
"recognizerSha256": "0722ca4a2b9e76b37f3e0d32b78bb1d9afd5d040d219de3560a322c98a966d79"
}
},
"0.8.0": {
"vendoredCommit": "77dcac029e1e351df2d3add687e647463f4b0ce2",
"ortWeb": "1.29.0",
"bundledRelease": {
"id": "862aec0f937da326",
"detectorSha256": "54882ff7faebb854f79505b4f00313ea9a8ef927741c1501ac60d98022fe356e",
"recognizerSha256": "0722ca4a2b9e76b37f3e0d32b78bb1d9afd5d040d219de3560a322c98a966d79"
}
}
}
2 changes: 1 addition & 1 deletion cdn/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# The publishing tool, `cardvision cdn` (the toolkit's docs/cdn.md), with boto3 for the uploads.
cardvision[cdn]==0.10.1
cardvision[cdn]==0.11.0
1 change: 1 addition & 0 deletions docs/store-listing.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ anything. Read the store's current policies before each submission: they change.
| 0.5.0 | release `387bdfb29b4b050f` bundled; card details in French, German, Italian, Spanish and Portuguese (the browser's language); the paused-video fix; runtime cardvision 0.5.0rc2 | Public | Chrome: submitted 2026-10-29, replaced by 0.6.0; Firefox: skipped (0.4.0 went straight to 0.6.0) |
| 0.6.0 | release `387bdfb29b4b050f` bundled; the session on the toolkit's two-frame contract (pictures stop 60 s after the pointer last moved; a tap opens 10 s); the "Ancient eye" icon and new store images; runtime cardvision 0.6.0rc2 | Public | Chrome: submitted 2026-10-30, live 2026-10-31, replaced by 0.7.0; Firefox: public 2026-10-31, replaced by 0.7.0 |
| 0.7.0 | release `387bdfb29b4b050f` bundled; the Card language menu in the popup; the tooltip keeps its picture through a settings refresh and retries a details file that failed; runtime cardvision 0.6.0rc2 (unchanged) | Public | Chrome: submitted 2026-11-09, live 2026-11-09; Firefox: submitted 2026-11-09, public 2026-11-09 |
| 0.8.0 | release `862aec0f937da326` bundled (the 2026-11-10 card update `f3ed25290dde66e9`, converted to a binary bank); a card lying at an angle is outlined and hovered along its own edges; analysis paced from what it costs on the computer, so a slower computer is not kept busy; runtime cardvision 0.11.0 (toolkit main 77dcac0) | Public | Chrome: not yet submitted; Firefox: not yet submitted |

Update this table with each submission (date submitted, date approved, store item ID). Chrome's item is
`okngcckiafmekbmdgoakggfbicgoagnc`; Firefox's add-on is `duelsight@duelsight.com`
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "duelsight",
"version": "0.7.0",
"version": "0.8.0",
"description": "Hover a Yu-Gi-Oh! card in a YouTube or Twitch video to see which card it is. Unofficial fan project, not affiliated with or endorsed by Konami.",
"license": "Apache-2.0",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion release-legal/NOTICE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DuelSight Yu-Gi-Oh! models, release T2 (id 387bdfb29b4b050f), converted losslessly from 0927859c6f18302f
DuelSight Yu-Gi-Oh! models, release T2 + cards to 2026-11-10 (id 862aec0f937da326), converted losslessly from f3ed25290dde66e9
Copyright 2026 The DuelSight authors and the cardvision authors

The files in the release folder (release.json, detector.onnx, recognizer.onnx, bank.json,
Expand Down
6 changes: 5 additions & 1 deletion release-legal/PROVENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| | |
| --- | --- |
| Release | T2, release document id `387bdfb29b4b050f`: T2 (`0927859c6f18302f`) converted with `cardvision convert-release` (toolkit 0.4.0rc2) to a binary bank and a compact catalog. The models, the vectors and the catalog's values are unchanged, so it scores exactly as T2. Game `yugioh`, 14,636 entries in the bank, 14,639 in the catalog |
| Release | T2 + cards to 2026-11-10, release document id `862aec0f937da326`: release `f3ed25290dde66e9` (T2 with the card updates to 2026-11-10, below) converted with `cardvision convert-release` (toolkit 0.11.0) to a binary bank and a compact catalog. The models, the vectors and the catalog's values are unchanged, so it scores exactly as `f3ed25290dde66e9`. Game `yugioh`, 14,636 entries in the bank, 14,639 in the catalog |
| Status | Measured on a held-out test before release (docs/accuracy.md). Replaces the early preview release T (`6666477f410559ac`). |
| License | Apache-2.0 (LICENSE beside this file); NOTICE says what it does not cover |
| Trained by | the DuelSight project, with the open-source cardvision toolkit 0.2.0rc4 (https://github.com/ryangswe/riftsight-vision) |
Expand Down Expand Up @@ -38,3 +38,7 @@
## Not included

No card art, no video frames, no labels. The card art and the videos belong to their owners.

## 2026-11-10 (release f3ed25290dde66e9)

Cards added: 0. Card names updated: 15, to the official English names in YGOPRODeck's card list pulled on 2026-11-10 (11 announced for the TCG, 4 released in Master Duel). Detector, recognizer, accept rule and every bank row are unchanged.
8 changes: 6 additions & 2 deletions src/compute/frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// pictures it closes. What is DuelSight's own:
// - the options it starts with: its message tag, the pages it serves (`allowedParentOrigin`),
// the shown card held through short gaps (`SHOWN_HOLD`), turned cards' outlines
// (`rotatedOutlines`), the release it loads;
// (`rotatedOutlines`), analysis paced from its measured cost (`measuredPacing`), the release
// it loads;
// - the card facts channel. A card of a remote release goes to the tooltip frame with its facts
// over an extension-only channel (`postFacts`), never through the page, and they leave before
// the card does. A tooltip frame that lacks a card's facts asks on that channel, and is
Expand Down Expand Up @@ -67,7 +68,7 @@ export function createFactsChannel(postFacts: (message: CardFactsMessage) => voi
}

/** What DuelSight's compute frame starts from: the toolkit's options, less the ones it sets. */
export type DuelSightFrameEnv = Omit<ComputeFrameEnv, "protocol" | "allowedParentOrigin" | "hold" | "onShown" | "parentOrigin" | "rotatedOutlines"> & {
export type DuelSightFrameEnv = Omit<ComputeFrameEnv, "protocol" | "allowedParentOrigin" | "hold" | "onShown" | "parentOrigin" | "rotatedOutlines" | "measuredPacing"> & {
/** `location.ancestorOrigins[0]`: missing, or the string "null" when a referrer policy hides it. */
parentOrigin: string | null | undefined;
dev: boolean;
Expand All @@ -90,6 +91,9 @@ export function computeFrameEnv(env: DuelSightFrameEnv, facts: FactsChannel): Co
// A card lying at an angle is hovered and outlined along its own edges, not its upright box
// (the shown card then carries `rotation`, `localWidth`, `localHeight`; outline.ts draws them).
rotatedOutlines: true,
// Analyses are spaced from what they cost on this computer (a quarter of the time at most by
// default), never faster than the fixed rates: a slow computer is not kept busy analyzing.
measuredPacing: true,
onShown: facts.onShown,
};
}
Expand Down
4 changes: 4 additions & 0 deletions test/compute-frame.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ describe("compute frame: the pages it serves", () => {
});

describe("compute frame: the shown card", () => {
it("paces analysis from its measured cost (measuredPacing is on)", () => {
expect(computeFrameEnv({ ...computeHarness().env }, createFactsChannel(() => undefined)).measuredPacing).toBe(true);
});

it("asks for turned cards' outlines (rotatedOutlines is on)", () => {
expect(computeFrameEnv({ ...computeHarness().env }, createFactsChannel(() => undefined)).rotatedOutlines).toBe(true);
});
Expand Down
4 changes: 2 additions & 2 deletions vendor/cardvision-browser/VENDOR.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.1.0",
"license": "Apache-2.0",
"source": "cardvision-browser, the browser runtime of the cardvision toolkit (source published with the toolkit release)",
"commit": "8a0f2c269b9df699c38928d9d4da745111469bd7",
"toolkitRelease": "cardvision 0.10.1",
"commit": "77dcac029e1e351df2d3add687e647463f4b0ce2",
"toolkitRelease": "cardvision 0.11.0",
"onnxruntimeWeb": "1.29.0",
"ortFiles": [
"ort-wasm-simd-threaded.jsep.mjs",
Expand Down
668 changes: 334 additions & 334 deletions vendor/cardvision-browser/cardvision.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion vendor/cardvision-browser/compute-session.js

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions vendor/cardvision-browser/types/cadence.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,50 @@ export declare function activeAnalyzeIntervalMs(ep: ExecutionProvider | null): n
export declare function cadenceMs(ep: ExecutionProvider | null, mode: AnalysisMode): number;
/** Whether this device runs the slower cadences. */
export declare function isSlowDevice(ep: ExecutionProvider | null): boolean;
/** Measured pacing: the share of time spent analyzing, by default. */
export declare const MEASURED_PACING_SHARE = 0.25;
/** Measured pacing: the longest wait while the pointer is active. */
export declare const MEASURED_PACING_ACTIVE_CEILING_MS = 4000;
/** Measured pacing: the longest wait in always-on mode. */
export declare const MEASURED_PACING_SLOW_CEILING_MS = 8000;
/** Measured pacing: the longest wait while the pointer rests ("reading"). A name stops showing
* `hoverMaxAgeMs` after its frame and the reading state ends `READING_LINGER_MS` after that, so a
* longer wait would never come due and analysis would stop until the pointer moved. */
export declare function readingCeilingMs(hoverMaxAgeMs: number): number;
/** Measured pacing: analyses measured before the measured wait applies. */
export declare const MEASURED_PACING_MIN_SAMPLES = 3;
/** Measured pacing: how many of the latest analyses the median is taken over. */
export declare const MEASURED_PACING_WINDOW = 5;
/** The `measuredPacing` option: `true` for the default share, or the share of time analysis may
* take, in (0, 1]. */
export type MeasuredPacingOption = boolean | {
share?: number;
};
/** The share the option asks for, or null when pacing is off. Throws on a share outside (0, 1]. */
export declare function resolveMeasuredPacing(option: MeasuredPacingOption | undefined): number | null;
/**
* The wait between analyses under measured pacing.
* @param fixedMs Today's fixed interval for the mode and backend: the wait is never shorter, and
* it is the wait until `MEASURED_PACING_MIN_SAMPLES` analyses have been measured.
* @param ceilingMs The longest wait: `MEASURED_PACING_ACTIVE_CEILING_MS` while the pointer is
* active, `readingCeilingMs` while it rests, `MEASURED_PACING_SLOW_CEILING_MS` in always-on mode.
* @param timesMs Measured analysis times, oldest first.
* @param share The share of time analysis may take.
*/
export declare function pacedIntervalMs(fixedMs: number, ceilingMs: number, timesMs: readonly number[], share: number): number;
/** Learns the analysis time within one session (nothing is stored) and gives the waits. */
export declare class MeasuredPacer {
private readonly share;
private times;
constructor(share: number);
/** Record one analysis's measured time (the reply's `workerMs`); not a number: ignored. */
record(ms: number): void;
/** The wait in force: the fast cadence in pointer mode, the slow one in always-on mode. */
intervalMs(ep: ExecutionProvider | null, mode: AnalysisMode): number;
/** The wait while the pointer rests on a showing tooltip, capped by `readingCeilingMs`. */
readingMs(ep: ExecutionProvider | null, hoverMaxAgeMs: number): number;
/** The wait while the pointer is active. */
activeMs(ep: ExecutionProvider | null): number;
/** The wait in always-on mode. */
slowMs(ep: ExecutionProvider | null): number;
}
2 changes: 1 addition & 1 deletion vendor/cardvision-browser/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export { type ClientBox, createSession, type Session, type SessionOptions, type
export { type AnalyzeOptions, type BoxResult, type FaceResult, type FrameAnalysis, hoverAt, hoverCardsOf, Pipeline, type PipelineOptions } from "./pipeline.js";
export { type AABB, type Candidate, iou, nonMaxSuppression, type Rect } from "./boxes.js";
export { type EmbeddingBank, parseBank } from "./bank.js";
export { type AnalysisMode, cadenceMs, type SessionMode } from "./cadence.js";
export { type AnalysisMode, cadenceMs, type MeasuredPacingOption, type SessionMode } from "./cadence.js";
export { analysisSize, captureFrame, type FrameSource, MAX_ANALYSIS_WIDTH, MIN_ANALYSIS_WIDTH } from "./capture.js";
export { type DecodeSettings, decodeDetections, DEFAULT_DECODE, validBox } from "./detector/decode.js";
export { Detector, type DetectorSettings, type Frame, type FrameDetector } from "./detector/detector.js";
Expand Down
9 changes: 8 additions & 1 deletion vendor/cardvision-browser/types/session-core.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AABB } from "./boxes.js";
import type { AnalysisWidth } from "./capture.js";
import { type SessionMode } from "./cadence.js";
import { type MeasuredPacingOption, type SessionMode } from "./cadence.js";
import { FrameScheduler } from "./frame-scheduler.js";
import { type GeometricStatus, type ReleaseProgress, type ReleaseStatus, type TiltedStatus, type WorkerReply, type WorkerRequest } from "./messages.js";
import { type FractionBox } from "./compute-messages.js";
Expand Down Expand Up @@ -80,6 +80,9 @@ export interface SessionCoreOptions {
/** True: named cards follow their outline on every frame (`SessionOptions.rotatedOutlines`).
* Default false. */
rotatedOutlines?: boolean;
/** Pace analysis from the measured analysis time (`SessionOptions.measuredPacing`). Off when
* absent. */
measuredPacing?: MeasuredPacingOption;
}
/** What `status().loading` becomes on a release-progress reply: the reply's phase while the
* release loads; `undefined` (no change) once it has loaded or failed, or the session has
Expand All @@ -95,6 +98,7 @@ export declare class SessionCore {
private readonly maxOtherBoxes;
private readonly rotatedOutlines;
private readonly hitTest;
private readonly pacer;
private readonly st;
private cardList;
private analysisWidth;
Expand Down Expand Up @@ -134,6 +138,9 @@ export declare class SessionCore {
* blank) and is looked at again after a back-off; otherwise a refusal, retried by nothing. */
captureFailed(requestId: number, reason: string, retry?: boolean): void;
fromWorker(reply: WorkerReply): void;
/** Arm the scheduler with the cadence for the backend: today's fixed rates, or the measured
* ones with `measuredPacing`. */
private applyCadence;
private onFrameResult;
/** Call every `DRIVER_TICK_MS`. */
tick(): void;
Expand Down
10 changes: 9 additions & 1 deletion vendor/cardvision-browser/types/session.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type AABB } from "./boxes.js";
import { type SessionMode } from "./cadence.js";
import { type MeasuredPacingOption, type SessionMode } from "./cadence.js";
import { type ClientBox, type FrameSource, pictureBox } from "./capture.js";
import { type AnalysisState } from "./frame-scheduler.js";
import type { GeometricStatus, ReleaseStatus } from "./messages.js";
Expand All @@ -25,6 +25,14 @@ export interface SessionOptions {
/** "pointer" (the default): analyze only around pointer activity. "always-on": analyze for as
* long as the session runs. */
mode?: SessionMode;
/** Pace analysis from the time recent analyses took on this device. Default off: the fixed
* rates. `true`, or `{ share }`: the wait is the median of the last 5 measured analyses
* divided by the share of time analysis may take (default 0.25), never shorter than the fixed
* rate. It is at most 4 s while the pointer is active, the release's `hover.maxAgeMs` + 4.75 s
* (6.75 s by default) while the pointer rests on a tooltip, and 8 s in always-on mode. The
* fixed rate applies until 3 analyses have been measured. Learned within the session, never
* stored. A share outside (0, 1] throws. */
measuredPacing?: MeasuredPacingOption;
/** URL of the geometric stage's settings document (it names the packed index). Optional and
* off by default: without it recognition is the embedding's alone. With it the stage loads
* after the release and joins between frames; `status().geometric` says where it is. */
Expand Down
4 changes: 3 additions & 1 deletion vendor/cardvision-browser/types/worker-session.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AnalysisWidth } from "./capture.js";
import type { SessionMode } from "./cadence.js";
import { type MeasuredPacingOption, type SessionMode } from "./cadence.js";
import type { GeometricStatus, WorkerReply, WorkerRequest } from "./messages.js";
import type { FrameAnalysis } from "./pipeline.js";
import type { CardTable } from "./remote/card-table.js";
Expand Down Expand Up @@ -37,6 +37,8 @@ export interface WorkerSessionEnv {
/** The clock, in ms. */
now(): number;
mode?: SessionMode;
/** Measured pacing (`SessionOptions.measuredPacing`); off when absent. */
measuredPacing?: MeasuredPacingOption;
/** Hold a shown card through short gaps (`SHOWN_HOLD`); off when absent. */
hold?: ShownHold;
/** True: named cards follow their outline (`SessionOptions.rotatedOutlines`). */
Expand Down
Loading