@talmolab/sleap-io.js 0.1.0 → 0.1.2

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.
package/README.md CHANGED
@@ -69,6 +69,21 @@ The demo in `demo/` loads the built package from `dist/`. Build first, then serv
69
69
  npm run build
70
70
  ```
71
71
 
72
+ ## Release & Publishing
73
+
74
+ This package uses npm Trusted Publishing. The first publish must be done manually to unlock the npm package settings:
75
+
76
+ 1. First-time publish (one-time):
77
+
78
+ ```bash
79
+ npm login
80
+ npm publish --access public
81
+ ```
82
+
83
+ 2. Enable Trusted Publisher at `https://www.npmjs.com/package/@talmolab/sleap-io.js/access`.
84
+
85
+ After that, GitHub Releases trigger the publish workflow automatically.
86
+
72
87
  ## Links
73
88
 
74
89
  - Python sleap-io: https://github.com/talmolab/sleap-io
package/dist/index.d.ts CHANGED
@@ -433,4 +433,7 @@ declare function labelsFromNumpy(data: number[][][][], options: {
433
433
  returnConfidence?: boolean;
434
434
  }): Labels;
435
435
 
436
- export { Camera, CameraGroup, Edge, FrameGroup, Instance, InstanceGroup, LabeledFrame, Labels, type LabelsDict, LabelsSet, Mp4BoxVideoBackend, Node, type NodeOrIndex, type Point, type PointsArray, PredictedInstance, type PredictedPoint, type PredictedPointsArray, RecordingSession, Skeleton, SuggestionFrame, Symmetry, Track, Video, type VideoBackend, type VideoFrame, fromDict, fromNumpy, labelsFromNumpy, loadSlp, loadVideo, makeCameraFromDict, pointsEmpty, pointsFromArray, pointsFromDict, predictedPointsEmpty, predictedPointsFromArray, predictedPointsFromDict, rodriguesTransformation, saveSlp, toDict, toNumpy };
436
+ declare function decodeYamlSkeleton(yamlData: string): Skeleton | Skeleton[];
437
+ declare function encodeYamlSkeleton(skeletons: Skeleton | Skeleton[]): string;
438
+
439
+ export { Camera, CameraGroup, Edge, FrameGroup, Instance, InstanceGroup, LabeledFrame, Labels, type LabelsDict, LabelsSet, Mp4BoxVideoBackend, Node, type NodeOrIndex, type Point, type PointsArray, PredictedInstance, type PredictedPoint, type PredictedPointsArray, RecordingSession, Skeleton, SuggestionFrame, Symmetry, Track, Video, type VideoBackend, type VideoFrame, decodeYamlSkeleton, encodeYamlSkeleton, fromDict, fromNumpy, labelsFromNumpy, loadSlp, loadVideo, makeCameraFromDict, pointsEmpty, pointsFromArray, pointsFromDict, predictedPointsEmpty, predictedPointsFromArray, predictedPointsFromDict, rodriguesTransformation, saveSlp, toDict, toNumpy };
package/dist/index.js CHANGED
@@ -2578,6 +2578,81 @@ async function loadVideo(filename, options) {
2578
2578
  const backend = await createVideoBackend(filename, { dataset: options?.dataset });
2579
2579
  return new Video({ filename, backend, openBackend: options?.openBackend ?? true });
2580
2580
  }
2581
+
2582
+ // src/codecs/skeleton-yaml.ts
2583
+ import YAML from "yaml";
2584
+ function getNodeName(entry) {
2585
+ if (typeof entry === "string") return entry;
2586
+ if (entry && typeof entry.name === "string") return entry.name;
2587
+ throw new Error("Invalid node entry in skeleton YAML.");
2588
+ }
2589
+ function resolveName(value) {
2590
+ if (typeof value === "string") return value;
2591
+ if (value && typeof value.name === "string") return value.name;
2592
+ throw new Error("Invalid name reference in skeleton YAML.");
2593
+ }
2594
+ function decodeSkeleton(data, fallbackName) {
2595
+ if (!data?.nodes) throw new Error("Skeleton YAML missing nodes.");
2596
+ const nodes = data.nodes.map((entry) => new Node(getNodeName(entry)));
2597
+ const edges = (data.edges ?? []).map((edge) => {
2598
+ if (Array.isArray(edge)) {
2599
+ const [source2, destination] = edge;
2600
+ return new Edge(nodes[Number(source2)], nodes[Number(destination)]);
2601
+ }
2602
+ const sourceName = resolveName(edge.source);
2603
+ const destName = resolveName(edge.destination);
2604
+ const source = nodes.find((node) => node.name === sourceName);
2605
+ const dest = nodes.find((node) => node.name === destName);
2606
+ if (!source || !dest) throw new Error("Edge references unknown node.");
2607
+ return new Edge(source, dest);
2608
+ });
2609
+ const symmetries = (data.symmetries ?? []).map((symmetry) => {
2610
+ if (!Array.isArray(symmetry) || symmetry.length !== 2) {
2611
+ throw new Error("Symmetry must contain exactly 2 nodes.");
2612
+ }
2613
+ const [left, right] = symmetry;
2614
+ const leftName = resolveName(left);
2615
+ const rightName = resolveName(right);
2616
+ const leftNode = nodes.find((node) => node.name === leftName);
2617
+ const rightNode = nodes.find((node) => node.name === rightName);
2618
+ if (!leftNode || !rightNode) throw new Error("Symmetry references unknown node.");
2619
+ return new Symmetry([leftNode, rightNode]);
2620
+ });
2621
+ return new Skeleton({
2622
+ name: data.name ?? fallbackName,
2623
+ nodes,
2624
+ edges,
2625
+ symmetries
2626
+ });
2627
+ }
2628
+ function decodeYamlSkeleton(yamlData) {
2629
+ const parsed = YAML.parse(yamlData);
2630
+ if (!parsed) throw new Error("Empty skeleton YAML.");
2631
+ if (Object.prototype.hasOwnProperty.call(parsed, "nodes")) {
2632
+ return decodeSkeleton(parsed);
2633
+ }
2634
+ return Object.entries(parsed).map(
2635
+ ([name, skeletonData]) => decodeSkeleton(skeletonData, name)
2636
+ );
2637
+ }
2638
+ function encodeYamlSkeleton(skeletons) {
2639
+ const list = Array.isArray(skeletons) ? skeletons : [skeletons];
2640
+ const payload = {};
2641
+ list.forEach((skeleton, index) => {
2642
+ const name = skeleton.name ?? `Skeleton-${index}`;
2643
+ const nodes = skeleton.nodes.map((node) => ({ name: node.name }));
2644
+ const edges = skeleton.edges.map((edge) => ({
2645
+ source: { name: edge.source.name },
2646
+ destination: { name: edge.destination.name }
2647
+ }));
2648
+ const symmetries = skeleton.symmetries.map((symmetry) => {
2649
+ const pair = Array.from(symmetry.nodes);
2650
+ return [{ name: pair[0].name }, { name: pair[1].name }];
2651
+ });
2652
+ payload[name] = { nodes, edges, symmetries };
2653
+ });
2654
+ return YAML.stringify(payload);
2655
+ }
2581
2656
  export {
2582
2657
  Camera,
2583
2658
  CameraGroup,
@@ -2597,6 +2672,8 @@ export {
2597
2672
  Symmetry,
2598
2673
  Track,
2599
2674
  Video,
2675
+ decodeYamlSkeleton,
2676
+ encodeYamlSkeleton,
2600
2677
  fromDict,
2601
2678
  fromNumpy,
2602
2679
  labelsFromNumpy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talmolab/sleap-io.js",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -12,6 +12,10 @@
12
12
  "main": "./dist/index.js",
13
13
  "types": "./dist/index.d.ts",
14
14
  "files": ["dist"],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/talmolab/sleap-io.js.git"
18
+ },
15
19
  "scripts": {
16
20
  "build": "tsup src/index.ts --format esm --dts",
17
21
  "test": "vitest",