@harpern/edu-modelhub-viewer-core 0.1.0-beta.0 → 0.1.0-beta.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.
@@ -10,7 +10,7 @@
10
10
  * caller's own loader, so the scene and the metadata can never disagree about
11
11
  * which file they came from. Nothing here touches a renderer or the DOM.
12
12
  */
13
- import { GlbParseError, type EduModelHub, type ValidationResult } from "@osuecampus/edu-modelhub-extractor";
13
+ import type { EduModelHub, ValidationResult } from "./types.js";
14
14
  /** Where a payload came from. `"none"` is the fail-closed case. */
15
15
  export type MetadataSource = "embedded" | "sidecar" | "none";
16
16
  /** Result of a metadata load. */
@@ -82,4 +82,9 @@ export declare function loadModel(url: string, options?: LoadOptions): Promise<L
82
82
  * development without any UI. Errors warn, warnings inform.
83
83
  */
84
84
  export declare function logFindings(findings: ValidationResult[], label?: string, console_?: Pick<Console, "warn" | "info">): void;
85
- export { GlbParseError };
85
+ /**
86
+ * True when a thrown value is the parse error a malformed GLB container
87
+ * raises. Checks the name rather than the class: a bundled copy of the
88
+ * parser is a different class object, so instanceof would quietly fail.
89
+ */
90
+ export declare function isGlbParseError(error: unknown): boolean;
@@ -6,7 +6,7 @@
6
6
  * and marker positions may need converting. Normalizing once, here, keeps
7
7
  * every consumer agreeing about what "annotation 3" means.
8
8
  */
9
- import type { Annotation, EduModelHub, Region } from "@osuecampus/edu-modelhub-extractor";
9
+ import type { Annotation, EduModelHub, Region } from "./types.js";
10
10
  import { type Vec3 } from "./coordinates.js";
11
11
  /** An annotation whose id is guaranteed unique and non-empty. */
12
12
  export type IdentifiedAnnotation = Annotation & {
@@ -57,6 +57,15 @@ export declare function normalizeAnnotationIds(annotations: readonly Annotation[
57
57
  export declare function annotationsInReadingOrder(payload: EduModelHub): IdentifiedAnnotation[];
58
58
  /** Regions sorted by `order`, ties keeping storage order. */
59
59
  export declare function regionsInOrder(payload: EduModelHub): Region[];
60
+ /** True when a region carries a description an author actually wrote. */
61
+ export declare function isAuthoredRegion(region: Region | undefined): boolean;
62
+ /**
63
+ * Regions worth showing in a reading view: those an author described, or
64
+ * those left undescribed but given a real name. A region the tool invented
65
+ * outright is dropped, so a model nobody annotated shows no region list at
66
+ * all rather than a wall of object names.
67
+ */
68
+ export declare function readableRegions(regions: readonly Region[] | undefined): Region[];
60
69
  /** Display name for a region, falling back to its id. */
61
70
  export declare function regionLabel(region: Region | undefined): string;
62
71
  /**
package/dist/regions.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * name is itself a region id.
12
12
  */
13
13
  import type { Mesh, Object3D, Material } from "three";
14
- import type { Region } from "@osuecampus/edu-modelhub-extractor";
14
+ import type { Region } from "./types.js";
15
15
  /** Region id to the meshes that make it up. */
16
16
  export type RegionMeshMap = Map<string, Mesh[]>;
17
17
  /** The parts of a glTF JSON this module reads. */
@@ -5,7 +5,7 @@
5
5
  * screen reader and braille users who want the content without driving a 3D
6
6
  * scene. Pure string building: no DOM, so it runs in Node and in tests.
7
7
  */
8
- import type { EduModelHub } from "@osuecampus/edu-modelhub-extractor";
8
+ import type { EduModelHub } from "./types.js";
9
9
  /** Options for {@link buildTranscript}. */
10
10
  export interface TranscriptOptions {
11
11
  /** Heading for the summary section. */
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The EDU_modelhub payload shape, as this package sees it.
3
+ *
4
+ * These are the same schema-derived definitions the extractor carries, and
5
+ * both are derived from the same source of truth:
6
+ * `packages/edu-modelhub-schema/EDU_modelhub.schema.json`. This package keeps
7
+ * its own copy so the published artifact is self-contained: the extractor is
8
+ * compiled into the bundle rather than installed alongside it, and a type
9
+ * that pointed at an uninstalled package would break every consumer.
10
+ *
11
+ * If the schema changes, both copies change with it.
12
+ *
13
+ * Per-primitive region assignment is NOT part of this payload. Each glTF mesh
14
+ * primitive belonging to a region carries `extras: { modelhubRegionId: "…" }`
15
+ * on the primitive itself, which is why `regions.ts` reads the loaded scene.
16
+ */
17
+ /** Usage license for the model. */
18
+ export type ModelLicense = "CC0" | "CC BY" | "CC BY-SA" | "All Rights Reserved";
19
+ /** How the model was created. */
20
+ export type ModelSource = "scan" | "photogrammetry" | "manual" | "other";
21
+ /** Whether a region is visible when the model first loads. */
22
+ export type VisibilityDefault = "shown" | "hidden";
23
+ /** Anchor type for an annotation. */
24
+ export type AnchorType = "marker" | "node" | "primitive" | "aabb";
25
+ /** A named, selectable sub-section of the model. */
26
+ export interface Region {
27
+ /** Stable snake_case identifier, unique within the model. */
28
+ id: string;
29
+ /** Human-readable display name shown in the region list. */
30
+ label?: string;
31
+ /** Educational description of what this region represents. */
32
+ description?: string;
33
+ /** Free-form tags for filtering or grouping. */
34
+ tags?: string[];
35
+ /** Whether this region is visible when the model first loads. */
36
+ visibilityDefault?: VisibilityDefault;
37
+ /** Display order in the region list. 0 = first. */
38
+ order?: number;
39
+ }
40
+ /** Positions the annotation at a world-space coordinate. */
41
+ export interface PositionAnchor {
42
+ type: "marker";
43
+ /** World-space [x, y, z] in the payload's coordinate space. */
44
+ position: [number, number, number];
45
+ }
46
+ /** Targets a named glTF node, mesh primitive, or bounding box. */
47
+ export interface ReferenceAnchor {
48
+ type: "node" | "primitive" | "aabb";
49
+ /** Name of the target. */
50
+ ref: string;
51
+ }
52
+ /** Every anchor variant. */
53
+ export type Anchor = PositionAnchor | ReferenceAnchor;
54
+ /**
55
+ * An authored camera view for an annotation. Viewers with a tour fly here;
56
+ * viewers without one ignore it. Positions use the payload's coordinate
57
+ * space, the same as `anchor.position`.
58
+ */
59
+ export interface AnnotationCamera {
60
+ /** Camera position as [x, y, z]. */
61
+ eye: [number, number, number];
62
+ /**
63
+ * A point the camera looks toward. Only the direction from `eye` matters,
64
+ * so sources that encode direction as a point beside the eye are valid.
65
+ */
66
+ target: [number, number, number];
67
+ /** Vertical field of view in degrees. Omitted means the viewer default. */
68
+ fov?: number;
69
+ }
70
+ /** An educational note anchored to a specific location on the model. */
71
+ export interface Annotation {
72
+ /** Stable identifier. */
73
+ id: string;
74
+ /** Where in 3D space this annotation sits. */
75
+ anchor: Anchor;
76
+ /** Short headline. */
77
+ title?: string;
78
+ /** Educational content body. */
79
+ body?: string;
80
+ /** Suggested reading sequence. 0 = first. */
81
+ readingOrder?: number;
82
+ /** Id of the Region this belongs to; must match a Region.id in the payload. */
83
+ regionId?: string;
84
+ /** Authored camera view, used by viewers with a tour. */
85
+ camera?: AnnotationCamera;
86
+ }
87
+ /** Top-level metadata describing the whole model. */
88
+ export interface ModelMetadata {
89
+ /** Human-readable name. */
90
+ title: string;
91
+ /** One-sentence accessibility description, 300 characters maximum. */
92
+ altText: string;
93
+ /** Detailed educational description; may be multiple paragraphs. */
94
+ longDescription?: string;
95
+ /** ISO 639-1 two-letter language code. */
96
+ language?: string;
97
+ /** Usage license. */
98
+ license?: ModelLicense;
99
+ /** Credit string, expected when the license is CC BY or CC BY-SA. */
100
+ attribution?: string;
101
+ /** Creator or rights holder. */
102
+ creator?: string;
103
+ /** Where the model came from or how it was acquired. */
104
+ origin?: string;
105
+ /** How rights were determined or asserted. */
106
+ rightsStatement?: string;
107
+ /** ISO 8601 date the institution created or acquired the asset. */
108
+ acquired?: string;
109
+ /** How the model was created. */
110
+ source?: ModelSource;
111
+ /** ISO 8601 UTC timestamp of first creation. */
112
+ created?: string;
113
+ /** ISO 8601 UTC timestamp of last update. */
114
+ modified?: string;
115
+ }
116
+ /**
117
+ * Root payload of the EDU_modelhub glTF extension, embedded at
118
+ * `gltf.extensions.EDU_modelhub` and listed in `gltf.extensionsUsed`.
119
+ */
120
+ export interface EduModelHub {
121
+ /** Semantic version of the spec this payload targets. */
122
+ specVersion: string;
123
+ /**
124
+ * Coordinate space of every position in this payload. Written as "gltf"
125
+ * from spec 0.2.0. Absent means "gltf": almost every payload in the wild
126
+ * predates the field and already stores glTF Y-up. Only an explicit
127
+ * "blender" marks Blender Z-up, converted with (x, y, z) -> (x, z, -y).
128
+ */
129
+ coordinateSpace?: "gltf" | "blender";
130
+ /** Metadata describing the entire model. */
131
+ model: ModelMetadata;
132
+ /** Named, selectable sub-sections. */
133
+ regions: Region[];
134
+ /** Educational notes anchored to parts of the model. */
135
+ annotations: Annotation[];
136
+ }
137
+ /** Severity of a validation finding. */
138
+ export type ValidationSeverity = "error" | "warning";
139
+ /** A single validation finding. */
140
+ export interface ValidationResult {
141
+ /** Dot-path to the offending field, such as "model.altText". */
142
+ field: string;
143
+ /** Human-readable description of the issue. */
144
+ message: string;
145
+ /** Whether this blocks use or is advisory. */
146
+ severity: ValidationSeverity;
147
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harpern/edu-modelhub-viewer-core",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "Framework-agnostic viewer core for EDU_modelhub models: metadata loading, normalization, region binding, annotation markers, and camera behaviour shared by every conforming viewer",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Oregon State University Ecampus",
@@ -54,9 +54,6 @@
54
54
  "test": "vitest run",
55
55
  "prepublishOnly": "npm run typecheck && npm run test && npm run build"
56
56
  },
57
- "dependencies": {
58
- "@osuecampus/edu-modelhub-extractor": "^0.1.0-beta.0"
59
- },
60
57
  "peerDependencies": {
61
58
  "three": ">=0.160.0",
62
59
  "three-mesh-bvh": ">=0.7.0"
@@ -67,6 +64,7 @@
67
64
  }
68
65
  },
69
66
  "devDependencies": {
67
+ "@osuecampus/edu-modelhub-extractor": "^0.1.0-beta.0",
70
68
  "@types/node": "^20.0.0",
71
69
  "@types/three": "^0.180.0",
72
70
  "three": "^0.180.0",