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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"js/ts.tsdk.path": "node_modules\\typescript\\lib"
}
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented here.

## [unreleased]

## [0.24.0] - July 22nd, 2026
- Add `ConfidenceSlider` toolbox item (`AllowedToolboxItem.ConfidenceSlider`) that deprecates (hides) or shows spatial annotations based on their confidence values. Unlike the now-deprecated `KeypointSlider`, it works with all spatial annotation types that have a confidence payload (`bbox`, `bbox3`, `polygon`, `polyline`, `contour`, `tbar`, and `point`), across every subtask.
- Supports a single global "all" slider and/or per-class sliders, controlled by `class_filter_mode` (`"toggle"`, `"all-only"`, or `"class-only"`).
- Configurable via `confidence_slider_toolbox_item`, including `filter_min`/`filter_max`/`step_value`, per-class `default_values`, `target_spatial_types`, and `target_class_ids`.
- Add `get_confidence_slider_value()` public API method to get the current confidence slider values.
- The default `toolbox_order` (used when none is provided) now includes `ConfidenceSlider` instead of `KeypointSlider`.
- Log a warning when both the `KeypointSlider` and `ConfidenceSlider` toolbox items are enabled at once.
- Deprecate the `KeypointSlider` toolbox item and `get_keypoint_slider_value()` in favor of the `ConfidenceSlider` and `get_confidence_slider_value()`. The `KeypointSlider` is retained for backwards compatibility and continues to filter only `point` annotations. It will be removed in a future release.

## [0.23.7] - July 21st, 2026
- Ship generated `.d.ts` declarations (`dist/types/`) and a generated type entry (`dist/index.d.ts`) instead of pointing consumers' type resolution at the raw `.ts` source. This stops downstream TypeScript projects from compiling ULabel's source under their own (stricter) `tsconfig`.
- Stop publishing the `src/` directory in the npm package (`files` now ships `dist/` only).
Expand Down
47 changes: 47 additions & 0 deletions api_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ enum AllowedToolboxItem {
ImageFilters, // 10
AnnotationList, // 11
Keybinds, // 12
ConfidenceSlider, // 13
}
```
You can access the AllowedToolboxItem enum by calling the static method:
Expand Down Expand Up @@ -434,6 +435,44 @@ The `AnnotationList` toolbox item displays all annotations in the current subtas

This toolbox item requires no configuration and can be added to the `toolbox_order` array using `AllowedToolboxItem.AnnotationList`.

### `confidence_slider_toolbox_item`

The `ConfidenceSlider` toolbox item (added to `toolbox_order` via `AllowedToolboxItem.ConfidenceSlider`) deprecates (hides) or shows spatial annotations based on their confidence values. Unlike the deprecated `KeypointSlider`, it works with **all** spatial annotation types that have a confidence payload (`bbox`, `bbox3`, `polygon`, `polyline`, `contour`, `tbar`, and `point`), across every subtask.

It supports two modes:

- **"all" mode** (default): a single slider applies one confidence threshold to every targeted spatial annotation across all subtasks, using each annotation's highest confidence value.
- **Per-class mode**: one slider is shown per targeted class id. Each slider only filters annotations whose assigned (highest-confidence) class matches that slider, using that class's confidence value.

The `class_filter_mode` config controls whether these modes are user-toggleable:
- `"toggle"` (default): a checkbox lets the user switch between the two modes.
- `"all-only"`: only the single global "all" slider is shown.
- `"class-only"`: only the per-class sliders are shown.

Any annotation with a confidence at or above the threshold is shown; any below is deprecated. Thresholds are expressed as percentages, and the slider's range and increment are configurable via `filter_min`, `filter_max`, and `step_value`.

Configuration object with the following custom definitions:
```javascript
type ConfidenceSliderClasses = {
"all": number, // percentage threshold (0-100) used by the single global slider
[classId: string]?: number // per-class-id thresholds (class id as a string key)
}

type ConfidenceSliderConfig = {
"name"?: string, // Default: "Confidence Filter"
"filter_min"?: number, // Default: 0 (%)
"filter_max"?: number, // Default: 100 (%)
"default_values"?: ConfidenceSliderClasses, // Default: {"all": 0}
"step_value"?: number, // Default: 1 (%)
"class_filter_mode"?: "toggle" | "all-only" | "class-only", // Default: "toggle"
"filter_on_load"?: boolean, // Default: true
// The spatial types to filter. Defaults to all confidence-filterable spatial types.
"target_spatial_types"?: ULabelSpatialType[],
// The class ids to create sliders for in class-only/toggle mode. Defaults to all class ids.
"target_class_ids"?: number[],
}
```

### `reset_zoom_keybind`
Keybind to reset the zoom level to the `initial_crop`. Default is `r`.

Expand All @@ -452,6 +491,8 @@ Keybind to delete a vertex of a polygon or polyline annotation. The vertex must
### `keypoint_slider_default_value`
Default value for the keypoint slider. Must be a number between 0 and 1. Default is `0`.

> **Deprecated:** The `KeypointSlider` toolbox item only filters `point` annotations. Use the `ConfidenceSlider` toolbox item (`confidence_slider_toolbox_item`) instead, which filters all spatial annotation types and supports per-class targeting and multiple sliders.

### `filter_annotations_on_load`
If true, the annotations will be filtered on load based on the `keypoint_slider_default_value`. Default is `true`.

Expand Down Expand Up @@ -563,10 +604,16 @@ Sets the zoom to focus on the provided annotation, and switches to its subtask i

*() => number | null* -- Returns the current keypoint slider value as a number between 0 and 1. Returns `null` if the KeypointSlider toolbox item is not active or the slider element is not found.

> **Deprecated:** Prefer `get_confidence_slider_value()` with the `ConfidenceSlider` toolbox item.

### `get_distance_filter_value()`

*() => object | null* -- Returns an object mapping class identifiers to their distance filter values (in pixels). The object always includes a `closest_row` key for the single-class slider. In multi-class mode, additional keys correspond to each class ID. Returns `null` if the FilterDistance toolbox item is not active or no sliders are found.

### `get_confidence_slider_value()`

*() => object | null* -- Returns an object mapping class identifiers to their confidence threshold values (as percentages, 0–100). The object always includes an `all` key for the single global slider. In per-class mode, additional keys correspond to each class ID. Returns `null` if the ConfidenceSlider toolbox item is not active or no sliders are found.

## Generic Callbacks

Callbacks can be provided by calling `.on(fn, callback)` on a `ULabel` object.
Expand Down
87 changes: 85 additions & 2 deletions demo/live_demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,98 @@
"spatial_type": "bbox",
"spatial_payload": [[871.84, 480.78], [833.71, 396.29]],
"classification_payloads": [
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.75},
],
},
{
"id": "dec78d65-9cb4-43ec-8c5a-dcbbae7a3d74",
"spatial_type": "bbox",
"spatial_payload": [[1257.66, 541.35], [1079.71, 411.99]],
"classification_payloads": [
{"class_id": 10, "confidence": 1.0},
{"class_id": 10, "confidence": 0.85},
],
},
// Additional annotations with varied confidences to demo the ConfidenceSlider
{
"id": "71be2a9d-5f1c-4a98-835e-e7826ebec6cf",
"spatial_type": "bbox",
"spatial_payload": [[1381.27, 510.38], [1268.86, 410.89]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.9},
],
},
{
"id": "79c81e3e-0a08-4fa1-a6b0-1e58a498116f",
"spatial_type": "polygon",
"spatial_payload": [
[
[452.24, 540.10], [625.38, 532.35], [642.18, 483.25],
[630.55, 447.07], [591.79, 414.77], [462.58, 413.48],
[445.78, 421.23], [447.07, 469.04], [434.15, 503.92],
[421.23, 510.38], [416.06, 537.52], [452.24, 540.10]
]
],
"spatial_payload_holes": [false],
"spatial_payload_child_indices": [[]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.35},
],
},
{
"id": "c170e38a-eafd-429d-87b1-9a1ee75e25b0",
"spatial_type": "bbox",
"spatial_payload": [[1447.58, 484.52], [1418.42, 397.04]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.55},
],
},
{
"id": "ec96ec1f-2007-4d10-a286-16af43775105",
"spatial_type": "bbox",
"spatial_payload": [[1477.49, 480.78], [1453.56, 401.52]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.2},
],
},
{
"id": "ca9209d9-f787-42e4-8d4b-4408e10ae1ed",
"spatial_type": "bbox",
"spatial_payload": [[1064.00, 468.07], [1031.85, 400.03]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.7},
],
},
{
"id": "39f9f056-383a-4b25-9e31-e71951a1ecaf",
"spatial_type": "bbox",
"spatial_payload": [[1037.67, 477.22], [1013.63, 393.07]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.45},
],
},
{
"id": "9cf8c7ef-814e-48e1-aa1a-e5e74e922938",
"spatial_type": "bbox",
"spatial_payload": [[952.93, 470.00], [898.24, 409.90]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.6},
],
},
{
"id": "84ba0141-fc65-4f89-9057-38eef9d93586",
"spatial_type": "polygon",
"spatial_payload": [
[
[4.78, 791.18], [341.47, 702.03], [358.98, 666.22],
[374.90, 595.38], [369.32, 543.64], [332.71, 497.47],
[305.65, 486.33], [275.40, 484.74], [175.91, 423.45],
[71.64, 410.71], [0, 408.33], [4.78, 791.18]
]
],
"spatial_payload_holes": [false],
"spatial_payload_child_indices": [[]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.65},
],
},
];
Expand Down
6 changes: 5 additions & 1 deletion demo/multi-class.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.FilterDistance,
AllowedToolboxItem.RecolorActive,
],
Expand All @@ -141,6 +142,9 @@
"brightness": 120
},
},
"confidence_slider_toolbox_item": {
"step_value": 5,
},
});
// Wait for ULabel instance to finish initialization
ulabel.init(function () {
Expand Down
24 changes: 17 additions & 7 deletions demo/resume-from.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"spatial_payload": [[300, 300]],
"classification_payloads": [
{"class_id": 12, "confidence": 0.0},
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.9},
{"class_id": 10, "confidence": 0.0},
],
},
Expand All @@ -45,15 +45,15 @@
"spatial_type": "point",
"spatial_payload": [[400, 300]],
"classification_payloads": [
{"class_id": 10, "confidence": 1.0},
{"class_id": 10, "confidence": 0.25},
],
},
{
"id": "4a686dc4-0efa-4563-a42b-8eea3dd5b04b",
"spatial_type": "point",
"spatial_payload": [[300, 400]],
"classification_payloads": [
{"class_id": 12, "confidence": 1.0},
{"class_id": 12, "confidence": 0.55},
],
},
{
Expand Down Expand Up @@ -102,7 +102,7 @@
]
],
"classification_payloads": [
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.75},
{"class_id": -1, "confidence": 0.0}
],
},
Expand Down Expand Up @@ -175,7 +175,7 @@
"classification_payloads": [
{
"class_id": 10,
"confidence": 1
"confidence": 0.15
},
{
"class_id": 11,
Expand Down Expand Up @@ -209,7 +209,7 @@
"classification_payloads": [
{
"class_id": 10,
"confidence": 1
"confidence": 0.6
},
{
"class_id": 11,
Expand Down Expand Up @@ -275,6 +275,7 @@
};

// Initial ULabel configuration
const AllowedToolboxItem = ULabel.get_allowed_toolbox_item_enum();
let ulabel = new ULabel({
"container_id": "container",
"image_data": "https://ulabel.s3.us-east-2.amazonaws.com/cs-demo-0.png",
Expand All @@ -285,7 +286,16 @@
"allow_annotations_outside_image": false,
"fly_to_next_annotation_keybind": "w",
"fly_to_previous_annotation_keybind": "`",
"fly_to_max_zoom": 6
"fly_to_max_zoom": 6,
"toolbox_order": [
AllowedToolboxItem.ModeSelect,
AllowedToolboxItem.ZoomPan,
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.SubmitButtons,
],
});
// Wait for ULabel instance to finish initialization
ulabel.init(function() {
Expand Down
10 changes: 8 additions & 2 deletions demo/row-filtering-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@
AllowedToolboxItem.ZoomPan,
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.FilterDistance,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.SubmitButtons,
Expand All @@ -761,7 +761,13 @@
// "disable_multi_class_mode": true,
// "filter_during_polyline_move": false,
},
"keypoint_slider_default_value": 0.2,
"confidence_slider_toolbox_item": {
"class_filter_mode": "class-only",
"target_class_ids": [10], // Plant only
"default_values": {
"all": 20, // %
},
},
});
// Wait for ULabel instance to finish initialization
ulabel.init(function () {
Expand Down
43 changes: 42 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ export type Offset = {
/**
* Valid keys for the DeprecatedBy type
*/
export type ValidDeprecatedBy = "human" | "confidence_filter" | "distance_from_row";
export type ValidDeprecatedBy = "human" | "confidence_filter" | "distance_from_row" | "confidence_slider";

export type DeprecatedBy = {
human?: boolean;
confidence_filter?: boolean;
distance_from_row?: boolean;
confidence_slider?: boolean;
};

/**
Expand Down Expand Up @@ -118,6 +119,45 @@ export type FilterDistanceConfig = {
filter_during_polyline_move?: boolean;
};

/**
* Stores the current confidence slider threshold values (percentages, 0-100).
* The key is the class id. "all" is a special key that stores the threshold applied to
* all annotations in single-class mode.
*/
export type ConfidenceSliderClasses = {
all: number;
[key: string]: number;
};

/**
* Controls how the ConfidenceSlider ToolboxItem filters by class:
* - "toggle": a checkbox lets the user switch between the single "all" slider and per-class sliders
* - "all-only": only a single global slider (keyed "all") is shown, filtering every targeted annotation
* - "class-only": only per-class sliders are shown
*/
export type ConfidenceSliderClassFilterMode = "toggle" | "all-only" | "class-only";

/**
* Config object for the ConfidenceSlider ToolboxItem.
*/
export type ConfidenceSliderConfig = {
name?: string;
filter_min?: number;
filter_max?: number;
default_values?: ConfidenceSliderClasses;
step_value?: number;
class_filter_mode?: ConfidenceSliderClassFilterMode;
filter_on_load?: boolean;
// The spatial types to filter. Defaults to all confidence-filterable spatial types.
target_spatial_types?: ULabelSpatialType[];
// The class ids to create sliders for in class-only/toggle mode. Defaults to all class ids.
target_class_ids?: number[];
keybinds?: {
increment: string;
decrement: string;
};
};

export type ULabelSubmitButton = {
name: string;
hook: (submit_data: ULabelSubmitData) => void;
Expand Down Expand Up @@ -367,6 +407,7 @@ export class ULabel {
): void;
public get_keypoint_slider_value(): number | null;
public get_distance_filter_value(): DistanceFromPolylineClasses | null;
public get_confidence_slider_value(): ConfidenceSliderClasses | null;
public fly_to_next_annotation(increment: number, max_zoom?: number): boolean;
public fly_to_annotation_id(annotation_id: string, subtask_key?: string | null, max_zoom?: number): boolean;
public fly_to_annotation(annotation: ULabelAnnotation, subtask_key?: string, max_zoom?: number): boolean;
Expand Down
Loading
Loading