@harpern/edu-modelhub-viewer-core 0.1.0-beta.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.
- package/CHANGELOG.md +31 -0
- package/LICENSE +201 -0
- package/README.md +88 -0
- package/dist/announce.d.ts +25 -0
- package/dist/backgrounds.d.ts +40 -0
- package/dist/camera.d.ts +77 -0
- package/dist/coordinates.d.ts +40 -0
- package/dist/dispose.d.ts +10 -0
- package/dist/framing.d.ts +31 -0
- package/dist/index.cjs +21 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +625 -0
- package/dist/lighting.d.ts +64 -0
- package/dist/markers.d.ts +75 -0
- package/dist/metadata.d.ts +85 -0
- package/dist/normalize.d.ts +76 -0
- package/dist/occlusion.d.ts +38 -0
- package/dist/regions.d.ts +52 -0
- package/dist/transcript.d.ts +26 -0
- package/package.json +77 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Annotation markers.
|
|
3
|
+
*
|
|
4
|
+
* Two presentations, one numbering. Sprites live in the 3D scene and follow
|
|
5
|
+
* the model; projected screen positions let a host draw real HTML buttons
|
|
6
|
+
* over the canvas, which is the accessible option because a sprite cannot be
|
|
7
|
+
* focused or read by a screen reader.
|
|
8
|
+
*
|
|
9
|
+
* Numbers always follow reading order, so what a sighted user sees and what a
|
|
10
|
+
* screen reader announces cannot disagree.
|
|
11
|
+
*/
|
|
12
|
+
import { Sprite, Vector3 } from "three";
|
|
13
|
+
import type { Camera, Object3D } from "three";
|
|
14
|
+
import type { MarkerAnchor } from "./normalize.js";
|
|
15
|
+
/** Colours for a marker's circle and number. */
|
|
16
|
+
export interface MarkerColors {
|
|
17
|
+
fill?: string;
|
|
18
|
+
text?: string;
|
|
19
|
+
textStroke?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Default unselected marker colour. */
|
|
22
|
+
export declare const MARKER_FILL = "#2196f3";
|
|
23
|
+
/** Default selected marker colour. */
|
|
24
|
+
export declare const MARKER_FILL_ACTIVE = "#ff5722";
|
|
25
|
+
/**
|
|
26
|
+
* Draw a numbered marker: a filled circle, a white ring, and the number.
|
|
27
|
+
* Rendered at 256px so it stays crisp when the camera is close.
|
|
28
|
+
*/
|
|
29
|
+
export declare function drawMarkerCanvas(value: number | string, colors?: MarkerColors): HTMLCanvasElement;
|
|
30
|
+
/**
|
|
31
|
+
* A numbered sprite for the 3D scene.
|
|
32
|
+
*
|
|
33
|
+
* `depthTest` is off so a marker is never swallowed by the geometry it sits
|
|
34
|
+
* on; occlusion, when a viewer wants it, is decided explicitly in
|
|
35
|
+
* `occlusion.ts` rather than by the depth buffer.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createMarkerSprite(value: number | string, scale?: number, colors?: MarkerColors): Sprite;
|
|
38
|
+
/** Redraw a sprite's texture in a new colour, disposing the old one. */
|
|
39
|
+
export declare function setMarkerSpriteColor(sprite: Sprite, value: number | string, fill: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Add one sprite per marker anchor, parented to the model so they inherit
|
|
42
|
+
* its centring and scaling. Returns the sprites in reading order.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createMarkerSprites(model: Object3D, anchors: readonly MarkerAnchor[], scale?: number, colors?: MarkerColors): Sprite[];
|
|
45
|
+
/** Where one marker landed on screen, and how to draw it. */
|
|
46
|
+
export interface MarkerScreenPosition {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
/** Perspective scale relative to the camera's distance to its target. */
|
|
50
|
+
scale: number;
|
|
51
|
+
/** Nearer markers stack above farther ones; occluded ones sink below both. */
|
|
52
|
+
zIndex: number;
|
|
53
|
+
/** False when the marker is behind the camera or outside the frame. */
|
|
54
|
+
inView: boolean;
|
|
55
|
+
occluded: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** Inputs for {@link projectMarkers}. */
|
|
58
|
+
export interface ProjectMarkersOptions {
|
|
59
|
+
camera: Camera;
|
|
60
|
+
model: Object3D;
|
|
61
|
+
anchors: readonly MarkerAnchor[];
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
/** Camera-to-target distance, so marker size tracks zoom. */
|
|
65
|
+
referenceDistance?: number;
|
|
66
|
+
/** Optional occlusion test; see `occlusion.ts`. */
|
|
67
|
+
isOccluded?: (world: Vector3, distance: number) => boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Project every marker anchor into canvas pixel space.
|
|
71
|
+
*
|
|
72
|
+
* Call after each render. Depth survives two ways: stacking order, so a near
|
|
73
|
+
* marker covers a far one, and a scale factor, so distance reads visually.
|
|
74
|
+
*/
|
|
75
|
+
export declare function projectMarkers(options: ProjectMarkersOptions): Record<string, MarkerScreenPosition>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Getting a model's metadata, from whichever source has it.
|
|
3
|
+
*
|
|
4
|
+
* The spec sets a precedence: a valid embedded `EDU_modelhub` extension wins;
|
|
5
|
+
* otherwise a `<model>.modelhub.json` sidecar beside the file; otherwise the
|
|
6
|
+
* viewer fails closed with an accessible error rather than quietly rendering
|
|
7
|
+
* a bare model as though nothing were missing.
|
|
8
|
+
*
|
|
9
|
+
* The GLB is fetched exactly once and the same bytes are returned for the
|
|
10
|
+
* caller's own loader, so the scene and the metadata can never disagree about
|
|
11
|
+
* which file they came from. Nothing here touches a renderer or the DOM.
|
|
12
|
+
*/
|
|
13
|
+
import { GlbParseError, type EduModelHub, type ValidationResult } from "@osuecampus/edu-modelhub-extractor";
|
|
14
|
+
/** Where a payload came from. `"none"` is the fail-closed case. */
|
|
15
|
+
export type MetadataSource = "embedded" | "sidecar" | "none";
|
|
16
|
+
/** Result of a metadata load. */
|
|
17
|
+
export interface MetadataResult {
|
|
18
|
+
/** The payload, or `null` when no source had one. */
|
|
19
|
+
payload: EduModelHub | null;
|
|
20
|
+
/** Which source supplied it. */
|
|
21
|
+
source: MetadataSource;
|
|
22
|
+
/** Validator findings for the payload; empty when there is none. */
|
|
23
|
+
findings: ValidationResult[];
|
|
24
|
+
/**
|
|
25
|
+
* Human-readable reason the load failed closed, suitable for an error
|
|
26
|
+
* region. `null` whenever a payload was found.
|
|
27
|
+
*/
|
|
28
|
+
problem: string | null;
|
|
29
|
+
}
|
|
30
|
+
/** A metadata load plus the bytes it was read from. */
|
|
31
|
+
export interface LoadedModel extends MetadataResult {
|
|
32
|
+
/** The GLB bytes, for the caller's own loader. */
|
|
33
|
+
bytes: ArrayBuffer;
|
|
34
|
+
}
|
|
35
|
+
/** Options for {@link loadModel}. */
|
|
36
|
+
export interface LoadOptions {
|
|
37
|
+
/** Injected for tests and non-browser hosts. Defaults to global `fetch`. */
|
|
38
|
+
fetchImpl?: typeof fetch;
|
|
39
|
+
/** Set false to skip the sidecar request entirely. */
|
|
40
|
+
sidecar?: boolean;
|
|
41
|
+
/** Resolve a sidecar URL yourself, for hosts with rewriting asset paths. */
|
|
42
|
+
sidecarUrl?: (glbUrl: string) => string | null;
|
|
43
|
+
}
|
|
44
|
+
/** Only `error` findings block use; warnings are advisory. */
|
|
45
|
+
export declare function errorsOf(findings: ValidationResult[]): ValidationResult[];
|
|
46
|
+
/**
|
|
47
|
+
* The sidecar URL for a GLB URL: the same basename with `.modelhub.json`.
|
|
48
|
+
* Returns `null` when the URL is not a `.glb`, so there is nothing to try.
|
|
49
|
+
*/
|
|
50
|
+
export declare function sidecarUrlFor(glbUrl: string): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* The directory a GLB was fetched from, so a loader can resolve any relative
|
|
53
|
+
* URIs inside it, such as external textures.
|
|
54
|
+
*
|
|
55
|
+
* `blob:` and `data:` URLs have no directory, and neither do self-contained
|
|
56
|
+
* files, so both get an empty path, which is what loaders expect.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resourcePathFor(url: string, base?: string): string;
|
|
59
|
+
/** Fetch a URL as bytes. Works for http(s), `blob:` and `data:` alike. */
|
|
60
|
+
export declare function fetchBytes(url: string, fetchImpl?: typeof fetch): Promise<ArrayBuffer>;
|
|
61
|
+
/**
|
|
62
|
+
* Read the embedded payload out of GLB bytes and validate it.
|
|
63
|
+
*
|
|
64
|
+
* `parseGlb` checks the GLB header and chunk bounds and strips
|
|
65
|
+
* prototype-polluting keys, so the result is safe to spread. A malformed
|
|
66
|
+
* container throws `GlbParseError`; a well-formed one with no extension
|
|
67
|
+
* returns a `"none"` result so the caller can try the sidecar.
|
|
68
|
+
*/
|
|
69
|
+
export declare function readEmbedded(bytes: ArrayBuffer): MetadataResult;
|
|
70
|
+
/**
|
|
71
|
+
* Load a model's metadata, trying the embedded extension and then a sidecar.
|
|
72
|
+
*
|
|
73
|
+
* Resolves rather than throws for a model with no metadata: that is a state
|
|
74
|
+
* the UI must render, not an exception. A malformed GLB container does throw,
|
|
75
|
+
* because the file itself is unusable.
|
|
76
|
+
*
|
|
77
|
+
* @throws {GlbParseError} If the GLB container is malformed.
|
|
78
|
+
*/
|
|
79
|
+
export declare function loadModel(url: string, options?: LoadOptions): Promise<LoadedModel>;
|
|
80
|
+
/**
|
|
81
|
+
* Print validator findings compactly, so authoring mistakes surface during
|
|
82
|
+
* development without any UI. Errors warn, warnings inform.
|
|
83
|
+
*/
|
|
84
|
+
export declare function logFindings(findings: ValidationResult[], label?: string, console_?: Pick<Console, "warn" | "info">): void;
|
|
85
|
+
export { GlbParseError };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a raw payload into the shapes a UI can bind to.
|
|
3
|
+
*
|
|
4
|
+
* A viewer should never hand a raw `EDU_modelhub` payload straight to its
|
|
5
|
+
* components. Ids may be missing or duplicated, reading order may be absent,
|
|
6
|
+
* and marker positions may need converting. Normalizing once, here, keeps
|
|
7
|
+
* every consumer agreeing about what "annotation 3" means.
|
|
8
|
+
*/
|
|
9
|
+
import type { Annotation, EduModelHub, Region } from "@osuecampus/edu-modelhub-extractor";
|
|
10
|
+
import { type Vec3 } from "./coordinates.js";
|
|
11
|
+
/** An annotation whose id is guaranteed unique and non-empty. */
|
|
12
|
+
export type IdentifiedAnnotation = Annotation & {
|
|
13
|
+
id: string;
|
|
14
|
+
};
|
|
15
|
+
/** A marker annotation with its position already in renderer space. */
|
|
16
|
+
export interface MarkerAnchor {
|
|
17
|
+
annotation: IdentifiedAnnotation;
|
|
18
|
+
/** Position in renderer (glTF Y-up) space. */
|
|
19
|
+
position: Vec3;
|
|
20
|
+
/** Authored camera, converted to renderer space, when the payload has one. */
|
|
21
|
+
camera?: {
|
|
22
|
+
eye: Vec3;
|
|
23
|
+
target: Vec3;
|
|
24
|
+
fov?: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** One run of annotation body text, optionally a link. */
|
|
28
|
+
export interface BodySegment {
|
|
29
|
+
text: string;
|
|
30
|
+
url?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Everything a UI needs, derived once from a payload. */
|
|
33
|
+
export interface NormalizedModel {
|
|
34
|
+
payload: EduModelHub;
|
|
35
|
+
regions: Region[];
|
|
36
|
+
regionsById: Map<string, Region>;
|
|
37
|
+
annotations: IdentifiedAnnotation[];
|
|
38
|
+
annotationsById: Map<string, IdentifiedAnnotation>;
|
|
39
|
+
annotationsByRegion: Map<string, IdentifiedAnnotation[]>;
|
|
40
|
+
markerAnchors: MarkerAnchor[];
|
|
41
|
+
hiddenRegionIds: Set<string>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Give every annotation a stable, unique id.
|
|
45
|
+
*
|
|
46
|
+
* Repeats keep storage order rather than reading order, so re-ordering a tour
|
|
47
|
+
* later never renames a pin. Bilateral labels ("Transverse process" left and
|
|
48
|
+
* right) commonly share an id in Sketchfab-era exports, and without this they
|
|
49
|
+
* would collapse onto one marker.
|
|
50
|
+
*/
|
|
51
|
+
export declare function normalizeAnnotationIds(annotations: readonly Annotation[] | undefined): IdentifiedAnnotation[];
|
|
52
|
+
/**
|
|
53
|
+
* Annotations sorted by `readingOrder`, ties and absences keeping storage
|
|
54
|
+
* order. This is the order markers are numbered in, the order the list is
|
|
55
|
+
* rendered in, and the order a tour steps through, so they cannot disagree.
|
|
56
|
+
*/
|
|
57
|
+
export declare function annotationsInReadingOrder(payload: EduModelHub): IdentifiedAnnotation[];
|
|
58
|
+
/** Regions sorted by `order`, ties keeping storage order. */
|
|
59
|
+
export declare function regionsInOrder(payload: EduModelHub): Region[];
|
|
60
|
+
/** Display name for a region, falling back to its id. */
|
|
61
|
+
export declare function regionLabel(region: Region | undefined): string;
|
|
62
|
+
/**
|
|
63
|
+
* Split an annotation body into plain-text and link segments.
|
|
64
|
+
*
|
|
65
|
+
* Bodies are untrusted text that may carry markdown links. Returning
|
|
66
|
+
* segments lets a UI render real anchors without ever putting payload text
|
|
67
|
+
* through `innerHTML`, which is what the spec requires.
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseBodySegments(body: string | undefined): BodySegment[];
|
|
70
|
+
/**
|
|
71
|
+
* Build every index a UI needs from one payload.
|
|
72
|
+
*
|
|
73
|
+
* Marker positions and authored cameras come out already in renderer space,
|
|
74
|
+
* so no consumer has to remember the coordinate rule.
|
|
75
|
+
*/
|
|
76
|
+
export declare function normalizeModel(payload: EduModelHub): NormalizedModel;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deciding whether a marker is behind the model.
|
|
3
|
+
*
|
|
4
|
+
* Markers draw on top of everything so they are never swallowed by geometry,
|
|
5
|
+
* which leaves a marker on the far side of a skull looking like it is on the
|
|
6
|
+
* near side. Testing each marker against the mesh lets a viewer dim the ones
|
|
7
|
+
* that are actually hidden.
|
|
8
|
+
*
|
|
9
|
+
* A ray per marker per frame against a few hundred thousand triangles is far
|
|
10
|
+
* too slow unmodified, so this uses `three-mesh-bvh` when the host has it.
|
|
11
|
+
* The dependency is optional: without it, `createOcclusionIndex` resolves to
|
|
12
|
+
* an index that reports nothing occluded, and markers simply all stay bright.
|
|
13
|
+
*/
|
|
14
|
+
import { Vector3 } from "three";
|
|
15
|
+
import type { Camera, Object3D } from "three";
|
|
16
|
+
/**
|
|
17
|
+
* Markers sit on, or a hair inside, the surface they label, so the ray to an
|
|
18
|
+
* unoccluded marker still hits its own mesh at about the marker's distance.
|
|
19
|
+
* Anything nearer than this margin counts as geometry in front. Expressed in
|
|
20
|
+
* normalized model units, where the longest axis is 2.
|
|
21
|
+
*/
|
|
22
|
+
export declare const OCCLUSION_BIAS = 0.03;
|
|
23
|
+
/** Tests whether a world-space point is hidden behind geometry. */
|
|
24
|
+
export interface OcclusionIndex {
|
|
25
|
+
/** True when the index can actually answer; false when it is a no-op. */
|
|
26
|
+
readonly enabled: boolean;
|
|
27
|
+
isOccluded(camera: Camera, point: Vector3, distance: number): boolean;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build an occlusion index for a loaded model.
|
|
32
|
+
*
|
|
33
|
+
* Resolves to a no-op index when `three-mesh-bvh` is not installed or the
|
|
34
|
+
* acceleration has not been patched onto three's prototypes by the host.
|
|
35
|
+
* Skinned meshes are indexed in their bind pose, so occlusion is approximate
|
|
36
|
+
* while an animation plays.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createOcclusionIndex(root: Object3D): Promise<OcclusionIndex>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binding regions to geometry.
|
|
3
|
+
*
|
|
4
|
+
* Region membership is not stored in the extension payload. Each glTF mesh
|
|
5
|
+
* primitive that belongs to a region carries `extras.modelhubRegionId`, so
|
|
6
|
+
* the binding has to be read from the loaded scene, not from the metadata.
|
|
7
|
+
*
|
|
8
|
+
* Three lookups are tried in turn, because exporters differ in what survives
|
|
9
|
+
* into the loaded scene: the extras three.js copies onto geometry userData,
|
|
10
|
+
* the raw glTF JSON when the host still has it, and finally an object whose
|
|
11
|
+
* name is itself a region id.
|
|
12
|
+
*/
|
|
13
|
+
import type { Mesh, Object3D, Material } from "three";
|
|
14
|
+
import type { Region } from "@osuecampus/edu-modelhub-extractor";
|
|
15
|
+
/** Region id to the meshes that make it up. */
|
|
16
|
+
export type RegionMeshMap = Map<string, Mesh[]>;
|
|
17
|
+
/** The parts of a glTF JSON this module reads. */
|
|
18
|
+
export interface GltfJsonLike {
|
|
19
|
+
meshes?: {
|
|
20
|
+
name?: string;
|
|
21
|
+
primitives?: {
|
|
22
|
+
extras?: Record<string, unknown>;
|
|
23
|
+
}[];
|
|
24
|
+
}[];
|
|
25
|
+
nodes?: {
|
|
26
|
+
name?: string;
|
|
27
|
+
mesh?: number;
|
|
28
|
+
}[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the region-to-geometry map for a loaded scene.
|
|
32
|
+
*
|
|
33
|
+
* @param root - The loaded model root (`gltf.scene`).
|
|
34
|
+
* @param gltfJson - Raw glTF JSON, when available (`gltf.parser.json`).
|
|
35
|
+
* @param regions - Payload regions, used only for the name-matching fallback.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildRegionMeshMap(root: Object3D, gltfJson?: GltfJsonLike, regions?: readonly Region[]): RegionMeshMap;
|
|
38
|
+
/** How many meshes each region resolved to, for diagnostics and UI badges. */
|
|
39
|
+
export declare function regionBindingCounts(map: RegionMeshMap): Record<string, number>;
|
|
40
|
+
/** Show or hide every mesh bound to one region. */
|
|
41
|
+
export declare function setRegionVisible(map: RegionMeshMap, regionId: string, visible: boolean): void;
|
|
42
|
+
/**
|
|
43
|
+
* Apply each region's `visibilityDefault` on load.
|
|
44
|
+
*
|
|
45
|
+
* Required by the spec and implemented by neither viewer before this package:
|
|
46
|
+
* a region authored as hidden was showing up anyway.
|
|
47
|
+
*/
|
|
48
|
+
export declare function applyVisibilityDefaults(map: RegionMeshMap, hiddenRegionIds: ReadonlySet<string>): void;
|
|
49
|
+
/** Swap in a highlight material, remembering what was there before. */
|
|
50
|
+
export declare function highlightRegion(map: RegionMeshMap, regionId: string, material: Material): void;
|
|
51
|
+
/** Put a region's authored material back. */
|
|
52
|
+
export declare function clearRegionHighlight(map: RegionMeshMap, regionId: string): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown transcript of everything a model says.
|
|
3
|
+
*
|
|
4
|
+
* A linear, offline-readable equivalent of the whole viewer experience, for
|
|
5
|
+
* screen reader and braille users who want the content without driving a 3D
|
|
6
|
+
* scene. Pure string building: no DOM, so it runs in Node and in tests.
|
|
7
|
+
*/
|
|
8
|
+
import type { EduModelHub } from "@osuecampus/edu-modelhub-extractor";
|
|
9
|
+
/** Options for {@link buildTranscript}. */
|
|
10
|
+
export interface TranscriptOptions {
|
|
11
|
+
/** Heading for the summary section. */
|
|
12
|
+
summaryHeading?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build a Markdown transcript for a payload.
|
|
16
|
+
*
|
|
17
|
+
* Sections are omitted when the payload has nothing to put in them, so a
|
|
18
|
+
* sparse model produces a short document rather than a page of "not
|
|
19
|
+
* specified".
|
|
20
|
+
*
|
|
21
|
+
* @param payload - The EDU_modelhub payload.
|
|
22
|
+
* @returns Markdown text.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildTranscript(payload: EduModelHub, options?: TranscriptOptions): string;
|
|
25
|
+
/** Filename a transcript should download as, without a path. */
|
|
26
|
+
export declare function transcriptFileName(payload: EduModelHub): string;
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@harpern/edu-modelhub-viewer-core",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
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
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Oregon State University Ecampus",
|
|
7
|
+
"contributors": [
|
|
8
|
+
{
|
|
9
|
+
"name": "Nick Harper",
|
|
10
|
+
"email": "nick.harper@oregonstate.edu"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"gltf",
|
|
15
|
+
"glb",
|
|
16
|
+
"edu_modelhub",
|
|
17
|
+
"3d",
|
|
18
|
+
"threejs",
|
|
19
|
+
"accessibility",
|
|
20
|
+
"viewer"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/osuecampus/3d-model-hub.git",
|
|
25
|
+
"directory": "packages/edu-modelhub-viewer-core"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/osuecampus/3d-model-hub/tree/main/packages/edu-modelhub-viewer-core#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/osuecampus/3d-model-hub/issues"
|
|
30
|
+
},
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"main": "./dist/index.cjs",
|
|
34
|
+
"module": "./dist/index.js",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js",
|
|
40
|
+
"require": "./dist/index.cjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"CHANGELOG.md"
|
|
46
|
+
],
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "vite build && tsc -p tsconfig.build.json --emitDeclarationOnly --declarationDir dist",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"prepublishOnly": "npm run typecheck && npm run test && npm run build"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@osuecampus/edu-modelhub-extractor": "^0.1.0-beta.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"three": ">=0.160.0",
|
|
62
|
+
"three-mesh-bvh": ">=0.7.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"three-mesh-bvh": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@types/node": "^20.0.0",
|
|
71
|
+
"@types/three": "^0.180.0",
|
|
72
|
+
"three": "^0.180.0",
|
|
73
|
+
"typescript": "^5.4.0",
|
|
74
|
+
"vite": "^6.4.3",
|
|
75
|
+
"vitest": "^4.1.10"
|
|
76
|
+
}
|
|
77
|
+
}
|