soonspacejs 3.0.0-alpha.11 → 3.0.0-alpha.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soonspacejs",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.12",
4
4
  "homepage": "https://www.xwbuilders.com/soonspacejs/",
5
5
  "description": "SoonSpace.js 3.0 alpha",
6
6
  "module": "./dist/index.esm.js",
@@ -0,0 +1,6 @@
1
+ import { Texture } from 'three';
2
+ /** Only fresh pixels decoded by the parsed-model cache enter this registry. */
3
+ export declare function ownDecodedImage(image: ImageBitmap): () => void;
4
+ export declare function assertDecodedTextureAlive(texture: Texture): void;
5
+ /** Capture the current pixels so later texture mutation cannot release another image. */
6
+ export declare function retainDecodedTexture(texture: Texture): () => void;
@@ -3,6 +3,20 @@ interface CacheOptions {
3
3
  maxEntryBytes?: number;
4
4
  onDiagnostic?: (event: ModelCacheDiagnostic) => void;
5
5
  }
6
+ export interface ModelBufferResult {
7
+ buffer: ArrayBuffer;
8
+ /** Hashed request identity; never a URL or credential. */
9
+ cacheKey: string | null;
10
+ cacheable: boolean;
11
+ forbidPersistence: boolean;
12
+ isCurrent: () => boolean;
13
+ }
14
+ type RequestInit = {
15
+ headers: Headers;
16
+ credentials: RequestCredentials;
17
+ signal?: AbortSignal;
18
+ redirect?: RequestRedirect;
19
+ };
6
20
  /** Raw HTTP model bytes only. Runtime leases / GPU graphs are never persisted. */
7
21
  export declare class ModelBufferCache {
8
22
  private readonly store;
@@ -13,12 +27,9 @@ export declare class ModelBufferCache {
13
27
  private maximumEntryBytes;
14
28
  private withinLimit;
15
29
  private diagnose;
16
- load(url: string, init: {
17
- headers: Headers;
18
- credentials: RequestCredentials;
19
- signal?: AbortSignal;
20
- redirect?: RequestRedirect;
21
- }): Promise<ArrayBuffer>;
30
+ load(url: string, init: RequestInit): Promise<ArrayBuffer>;
31
+ loadWithMetadata(url: string, init: RequestInit): Promise<ModelBufferResult>;
32
+ private loadBytes;
22
33
  private key;
23
34
  private mutate;
24
35
  clear(): Promise<void>;
@@ -0,0 +1,81 @@
1
+ import { ModelBufferResult } from './ModelBufferCache';
2
+ import { ParsedModelSnapshot } from './ParsedModelCodec';
3
+ import { ParsedCacheLimits, ParsedCacheMetadata, ParsedCacheStore } from './ParsedModelStore';
4
+ import { ParsedModelCacheDiagnostic } from '../Interface/modelCache';
5
+ export interface ParsedModelCacheOptions {
6
+ enabled?: boolean;
7
+ maxBytes?: number;
8
+ maxEntryBytes?: number;
9
+ maxEntries?: number;
10
+ onDiagnostic?: (event: ParsedModelCacheDiagnostic) => void;
11
+ }
12
+ export interface ParsedCacheIdentity {
13
+ key: string;
14
+ rootKey: string;
15
+ version: string;
16
+ }
17
+ interface RootState {
18
+ latest: symbol;
19
+ refs: number;
20
+ }
21
+ interface Coordinator {
22
+ epoch: number;
23
+ roots: Map<string, RootState>;
24
+ scopes: Set<ParsedCacheScope>;
25
+ limitsKey?: string;
26
+ pruning?: Promise<unknown>;
27
+ }
28
+ export declare class ParsedCacheScope {
29
+ private coordinator;
30
+ private root;
31
+ private identity;
32
+ private release;
33
+ readonly controller: AbortController;
34
+ readonly token: symbol;
35
+ readonly epoch: number;
36
+ storageEpoch?: number;
37
+ sourceCurrent: () => boolean;
38
+ entry?: ParsedCacheMetadata;
39
+ private finished;
40
+ private parentAbort;
41
+ constructor(coordinator: Coordinator, root: RootState, identity: string, release: () => void, parent?: AbortSignal);
42
+ get signal(): AbortSignal;
43
+ isCurrent(): boolean;
44
+ assertCurrent(): void;
45
+ invalidate(): void;
46
+ finish(): void;
47
+ }
48
+ /** Coordinates live requests; the storage adapter owns atomic byte/count/LRU limits. */
49
+ export declare class ParsedModelCache {
50
+ private options;
51
+ private store;
52
+ private coordinator;
53
+ private scopes;
54
+ private warned;
55
+ private disposed;
56
+ readonly stats: {
57
+ hits: number;
58
+ misses: number;
59
+ writes: number;
60
+ evictions: number;
61
+ errors: number;
62
+ skipped: number;
63
+ bytes: number;
64
+ entries: number;
65
+ };
66
+ constructor(options?: () => ParsedModelCacheOptions, store?: ParsedCacheStore);
67
+ get limits(): ParsedCacheLimits;
68
+ get enabled(): boolean;
69
+ begin(identity: string, parent?: AbortSignal): ParsedCacheScope;
70
+ private diagnostic;
71
+ private enforceLimits;
72
+ identify(scope: ParsedCacheScope, source: ModelBufferResult, profile: string): Promise<ParsedCacheIdentity | null>;
73
+ assertAvailable(scope: ParsedCacheScope, bytes: number): void;
74
+ read(scope: ParsedCacheScope, identity: ParsedCacheIdentity): Promise<ParsedModelSnapshot | null>;
75
+ discard(scope: ParsedCacheScope, identity: ParsedCacheIdentity): Promise<void>;
76
+ write(scope: ParsedCacheScope, identity: ParsedCacheIdentity, snapshot: ParsedModelSnapshot): Promise<void>;
77
+ clear(): Promise<void>;
78
+ dispose(): void;
79
+ }
80
+ export declare const clearParsedModelCache: () => Promise<void>;
81
+ export {};
@@ -0,0 +1,102 @@
1
+ import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
+ import { RegisteredPart } from '../Entity/ModelResources';
3
+ import * as THREE from 'three';
4
+ declare const arrays: {
5
+ Float32Array: Float32ArrayConstructor;
6
+ Float64Array: Float64ArrayConstructor;
7
+ Uint32Array: Uint32ArrayConstructor;
8
+ Uint16Array: Uint16ArrayConstructor;
9
+ Uint8Array: Uint8ArrayConstructor;
10
+ Uint8ClampedArray: Uint8ClampedArrayConstructor;
11
+ Int32Array: Int32ArrayConstructor;
12
+ Int16Array: Int16ArrayConstructor;
13
+ Int8Array: Int8ArrayConstructor;
14
+ };
15
+ declare const materialTypes: {
16
+ MeshBasicMaterial: typeof THREE.MeshBasicMaterial;
17
+ MeshStandardMaterial: typeof THREE.MeshStandardMaterial;
18
+ MeshPhysicalMaterial: typeof THREE.MeshPhysicalMaterial;
19
+ };
20
+ type MaterialType = keyof typeof materialTypes;
21
+ interface AttributeData {
22
+ buffer: number;
23
+ type: keyof typeof arrays;
24
+ itemSize: number;
25
+ normalized: boolean;
26
+ name: string;
27
+ stride?: number;
28
+ offset?: number;
29
+ interleavedId?: number;
30
+ float16: boolean;
31
+ gpuType?: number;
32
+ usage: number;
33
+ }
34
+ interface GeometryData {
35
+ attributes: Record<string, number>;
36
+ index: number | null;
37
+ groups: {
38
+ start: number;
39
+ count: number;
40
+ materialIndex?: number;
41
+ }[];
42
+ drawRange: {
43
+ start: number;
44
+ count: number;
45
+ };
46
+ box: number[][] | null;
47
+ sphere: [number[], number] | null;
48
+ }
49
+ interface MaterialData {
50
+ type: MaterialType;
51
+ json: Record<string, any>;
52
+ colors: Record<string, number[]>;
53
+ vectors: Record<string, number[]>;
54
+ values: Record<string, number | boolean>;
55
+ }
56
+ interface TextureData {
57
+ json: Record<string, any>;
58
+ matrix: number[];
59
+ matrixAutoUpdate: boolean;
60
+ }
61
+ type PartData = Omit<RegisteredPart, 'geometry' | 'material' | 'matrix'> & {
62
+ geometry: number;
63
+ material: number;
64
+ matrix: number[];
65
+ };
66
+ export interface ParsedModelSnapshot {
67
+ schema: 2;
68
+ three: string;
69
+ bytes: number;
70
+ parts: PartData[];
71
+ buffers: Blob[];
72
+ attributes: AttributeData[];
73
+ geometries: GeometryData[];
74
+ materials: MaterialData[];
75
+ textures: TextureData[];
76
+ images: {
77
+ uuid: string;
78
+ blob: Blob;
79
+ width: number;
80
+ height: number;
81
+ }[];
82
+ bitmapOptions: ImageBitmapOptions;
83
+ }
84
+ export interface ParsedCodecOptions {
85
+ signal?: AbortSignal;
86
+ assertCurrent?: () => void;
87
+ maxBytes?: number;
88
+ decodeImage?: (blob: Blob, options: ImageBitmapOptions, signal: AbortSignal) => Promise<ImageBitmap>;
89
+ }
90
+ export interface HydratedParsedModel {
91
+ parts: RegisteredPart[];
92
+ /** Call only after ModelResources has retained every resource. */
93
+ transfer(): void;
94
+ dispose(): void;
95
+ }
96
+ /** Logical payload size, including a bounded JSON metadata estimate, not physical disk usage. */
97
+ export declare function parsedSnapshotBytes(snapshot: ParsedModelSnapshot): number;
98
+ /** No runtime objects or decoded pixels enter persistent storage. */
99
+ export declare function packParsedModel(gltf: GLTF, parts: readonly RegisteredPart[], options?: ParsedCodecOptions): Promise<ParsedModelSnapshot | null>;
100
+ export declare function validateParsedModel(value: unknown, maximum?: number): asserts value is ParsedModelSnapshot;
101
+ export declare function hydrateParsedModel(snapshot: ParsedModelSnapshot, options?: ParsedCodecOptions): Promise<HydratedParsedModel>;
102
+ export {};
@@ -0,0 +1,58 @@
1
+ import { ParsedModelSnapshot } from './ParsedModelCodec';
2
+ export interface ParsedCacheLimits {
3
+ maxBytes: number;
4
+ maxEntryBytes: number;
5
+ maxEntries: number;
6
+ }
7
+ export interface ParsedCacheMetadata {
8
+ key: string;
9
+ rootKey: string;
10
+ version: string;
11
+ bytes: number;
12
+ lastUsed: number;
13
+ writeId: string;
14
+ }
15
+ export interface ParsedCacheRead {
16
+ epoch: number;
17
+ entry?: {
18
+ metadata: ParsedCacheMetadata;
19
+ snapshot: ParsedModelSnapshot;
20
+ };
21
+ }
22
+ export interface ParsedCacheWrite {
23
+ stored: boolean;
24
+ evicted: number;
25
+ bytes: number;
26
+ entries: number;
27
+ }
28
+ export interface ParsedCacheStore {
29
+ read(key: string, version: string, signal?: AbortSignal): Promise<ParsedCacheRead>;
30
+ write(metadata: ParsedCacheMetadata, snapshot: ParsedModelSnapshot, epoch: number, limits: ParsedCacheLimits, guard: () => boolean, signal?: AbortSignal): Promise<ParsedCacheWrite>;
31
+ remove(key: string, writeId: string, guard: () => boolean): Promise<void>;
32
+ invalidateRoot(rootKey: string, guard: () => boolean): Promise<void>;
33
+ prune(limits: ParsedCacheLimits): Promise<ParsedCacheWrite>;
34
+ touch(metadata: ParsedCacheMetadata): void;
35
+ clear(): Promise<void>;
36
+ onClear(listener: () => void): () => void;
37
+ }
38
+ /** Payload and LRU metadata are committed/evicted in the same native transaction. */
39
+ export declare class IndexedParsedModelStore implements ParsedCacheStore {
40
+ readonly name: string;
41
+ private database?;
42
+ private channel?;
43
+ private listeners;
44
+ private touches;
45
+ private touchTimer?;
46
+ constructor(name?: string);
47
+ private open;
48
+ private transaction;
49
+ read(key: string, version: string, signal?: AbortSignal): Promise<ParsedCacheRead>;
50
+ write(metadata: ParsedCacheMetadata, snapshot: ParsedModelSnapshot, epoch: number, limits: ParsedCacheLimits, guard: () => boolean, signal?: AbortSignal): Promise<ParsedCacheWrite>;
51
+ remove(key: string, writeId: string, guard: () => boolean): Promise<void>;
52
+ invalidateRoot(rootKey: string, guard: () => boolean): Promise<void>;
53
+ prune(limits: ParsedCacheLimits): Promise<ParsedCacheWrite>;
54
+ touch(metadata: ParsedCacheMetadata): void;
55
+ clear(): Promise<void>;
56
+ onClear(listener: () => void): () => void;
57
+ }
58
+ export declare const parsedModelStore: IndexedParsedModelStore;
@@ -0,0 +1,5 @@
1
+ export declare function parsedAbortError(): DOMException;
2
+ export declare function checkParsedSignal(signal?: AbortSignal): void;
3
+ /** Races cancellation without leaving rejection handlers or abort listeners behind. */
4
+ export declare function parsedAbortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T>;
5
+ export declare function parsedParallel<T, R>(values: readonly T[], work: (value: T, index: number) => Promise<R>, check: () => void, concurrency?: number): Promise<R[]>;
@@ -1,6 +1,7 @@
1
1
  import { BufferGeometry, Material, Matrix4, Texture } from 'three';
2
2
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
3
3
  import { ModelBufferCache } from '../Cache/ModelBufferCache';
4
+ import { ParsedModelCacheOptions } from '../Cache/ParsedModelCache';
4
5
  export interface ModelPart {
5
6
  /** Omitted for triangle meshes. Basic line segments share the Entity lifecycle. */
6
7
  kind?: 'mesh' | 'line-segments';
@@ -29,6 +30,7 @@ interface ResourceRecord<T> {
29
30
  dead: boolean;
30
31
  gpu: Set<BufferGeometry | Material | Texture>;
31
32
  dependencies: Set<ResourceRecord<Material>>;
33
+ imageReleases: Set<() => void>;
32
34
  }
33
35
  export declare class ResourceLease<T> {
34
36
  readonly registry: ModelResources;
@@ -65,8 +67,12 @@ export declare class ModelResources {
65
67
  private urls;
66
68
  private gltfLoader;
67
69
  private bufferCache;
70
+ private parsedCacheOptions;
71
+ private parsedCache;
68
72
  /** Borrow a host-configured loader; its decoder workers remain host-owned. */
69
- setGLTFLoader(loader: GLTFLoader, bufferCache?: ModelBufferCache): void;
73
+ setGLTFLoader(loader: GLTFLoader, bufferCache?: ModelBufferCache, parsedOptions?: () => ParsedModelCacheOptions & {
74
+ profile?: string;
75
+ }): void;
70
76
  readonly materials: {
71
77
  register: (material: Material, options: {
72
78
  ownership: "transfer";
@@ -7,3 +7,14 @@ export interface ModelCacheDiagnostic {
7
7
  maxEntryBytes: number;
8
8
  errorName?: string;
9
9
  }
10
+ /** Parsed-cache evidence is bounded and contains no URLs, headers or exception text. */
11
+ export interface ParsedModelCacheDiagnostic {
12
+ key: string;
13
+ operation: 'read' | 'write' | 'skip' | 'evict' | 'clear';
14
+ reason: 'storage-error' | 'invalid-entry' | 'entry-too-large' | 'capacity';
15
+ maxBytes: number;
16
+ maxEntryBytes: number;
17
+ maxEntries: number;
18
+ bytes?: number;
19
+ errorName?: string;
20
+ }
@@ -8,6 +8,8 @@ interface SignalsState {
8
8
  sceneRendered: Signal;
9
9
  /** Dispatches ModelCacheDiagnostic when persistent model caching fails or skips a size limit. */
10
10
  modelCacheDiagnostic: Signal;
11
+ /** Dispatches redacted ParsedModelCacheDiagnostic for storage/capacity failures. */
12
+ parsedModelCacheDiagnostic: Signal;
11
13
  tweenUpdate: Signal;
12
14
  hover: Signal;
13
15
  click: Signal;
@@ -104,6 +104,14 @@ interface ViewportOptions {
104
104
  useIndexedDB?: boolean;
105
105
  /** Maximum bytes per persistent model resource; default 1 GiB, zero disables persistence. */
106
106
  modelCacheMaxEntryBytes?: number;
107
+ /** Cache decoded static Entity model resources when useIndexedDB is enabled; default true. */
108
+ useParsedModelCache?: boolean;
109
+ /** Parsed cache logical total budget; default 512 MiB. Zero disables and trims this cache. */
110
+ parsedModelCacheMaxBytes?: number;
111
+ /** Maximum logical parsed resource size; default 256 MiB. */
112
+ parsedModelCacheMaxEntryBytes?: number;
113
+ /** Maximum persistent parsed resources; default 256. */
114
+ parsedModelCacheMaxEntries?: number;
107
115
  }
108
116
  interface ViewportState {
109
117
  useFreq: number;
@@ -0,0 +1,6 @@
1
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
+ /** Called during SDK construction, before host code can customize its loader. */
3
+ export declare function parsedLoaderPolicy(loader: GLTFLoader): {
4
+ eligible: () => boolean;
5
+ profile: () => string;
6
+ };
@@ -36,6 +36,7 @@ export declare class TexturePreloader {
36
36
  private onContextRestored;
37
37
  private cancelFrame;
38
38
  prepare(root: Object3D, signal?: AbortSignal, managerSignal?: AbortSignal): Promise<void>;
39
+ prepareMaterials(materials: Iterable<unknown>, signal?: AbortSignal, managerSignal?: AbortSignal): Promise<void>;
39
40
  private schedule;
40
41
  private pump;
41
42
  private cancel;
package/types/index.d.ts CHANGED
@@ -3538,17 +3538,23 @@ declare class ModelBufferCache {
3538
3538
  private maximumEntryBytes;
3539
3539
  private withinLimit;
3540
3540
  private diagnose;
3541
- load(url: string, init: {
3542
- headers: Headers;
3543
- credentials: RequestCredentials;
3544
- signal?: AbortSignal;
3545
- redirect?: RequestRedirect;
3546
- }): Promise<ArrayBuffer>;
3541
+ load(url: string, init: RequestInit_2): Promise<ArrayBuffer>;
3542
+ loadWithMetadata(url: string, init: RequestInit_2): Promise<ModelBufferResult>;
3543
+ private loadBytes;
3547
3544
  private key;
3548
3545
  private mutate;
3549
3546
  clear(): Promise<void>;
3550
3547
  }
3551
3548
 
3549
+ declare interface ModelBufferResult {
3550
+ buffer: ArrayBuffer;
3551
+ /** Hashed request identity; never a URL or credential. */
3552
+ cacheKey: string | null;
3553
+ cacheable: boolean;
3554
+ forbidPersistence: boolean;
3555
+ isCurrent: () => boolean;
3556
+ }
3557
+
3552
3558
  /** Cache diagnostics never contain resource URLs, headers or exception messages. */
3553
3559
  export declare interface ModelCacheDiagnostic {
3554
3560
  key: string;
@@ -3728,8 +3734,12 @@ export declare class ModelResources {
3728
3734
  private urls;
3729
3735
  private gltfLoader;
3730
3736
  private bufferCache;
3737
+ private parsedCacheOptions;
3738
+ private parsedCache;
3731
3739
  /** Borrow a host-configured loader; its decoder workers remain host-owned. */
3732
- setGLTFLoader(loader: GLTFLoader, bufferCache?: ModelBufferCache): void;
3740
+ setGLTFLoader(loader: GLTFLoader, bufferCache?: ModelBufferCache, parsedOptions?: () => ParsedModelCacheOptions & {
3741
+ profile?: string;
3742
+ }): void;
3733
3743
  readonly materials: {
3734
3744
  register: (material: Material, options: {
3735
3745
  ownership: "transfer";
@@ -3873,6 +3883,26 @@ export declare type OrbitControlsProperties = Required<Omit<OrbitControlsOptions
3873
3883
 
3874
3884
  export declare type OrbitControlsType = 'orbit';
3875
3885
 
3886
+ /** Parsed-cache evidence is bounded and contains no URLs, headers or exception text. */
3887
+ export declare interface ParsedModelCacheDiagnostic {
3888
+ key: string;
3889
+ operation: 'read' | 'write' | 'skip' | 'evict' | 'clear';
3890
+ reason: 'storage-error' | 'invalid-entry' | 'entry-too-large' | 'capacity';
3891
+ maxBytes: number;
3892
+ maxEntryBytes: number;
3893
+ maxEntries: number;
3894
+ bytes?: number;
3895
+ errorName?: string;
3896
+ }
3897
+
3898
+ declare interface ParsedModelCacheOptions {
3899
+ enabled?: boolean;
3900
+ maxBytes?: number;
3901
+ maxEntryBytes?: number;
3902
+ maxEntries?: number;
3903
+ onDiagnostic?: (event: ParsedModelCacheDiagnostic) => void;
3904
+ }
3905
+
3876
3906
  declare const parseFilePath: (url: string) => string;
3877
3907
 
3878
3908
  /**
@@ -4290,6 +4320,13 @@ export declare function renderLoop(frameFun: (time: DOMHighResTimeStamp) => void
4290
4320
  /** Default headers for SDK-owned HTTP(S) resource requests. */
4291
4321
  export declare const RequestHeaders: Record<string, string>;
4292
4322
 
4323
+ declare type RequestInit_2 = {
4324
+ headers: Headers;
4325
+ credentials: RequestCredentials;
4326
+ signal?: AbortSignal;
4327
+ redirect?: RequestRedirect;
4328
+ };
4329
+
4293
4330
  export declare class ResourceLease<T> {
4294
4331
  readonly registry: ModelResources;
4295
4332
  private record;
@@ -4308,6 +4345,7 @@ declare interface ResourceRecord<T> {
4308
4345
  dead: boolean;
4309
4346
  gpu: Set<BufferGeometry | Material | Texture>;
4310
4347
  dependencies: Set<ResourceRecord<Material>>;
4348
+ imageReleases: Set<() => void>;
4311
4349
  }
4312
4350
 
4313
4351
  declare const rgbeLoader: HDRLoader;
@@ -4598,6 +4636,8 @@ export declare interface SignalsState {
4598
4636
  sceneRendered: Signal;
4599
4637
  /** Dispatches ModelCacheDiagnostic when persistent model caching fails or skips a size limit. */
4600
4638
  modelCacheDiagnostic: Signal;
4639
+ /** Dispatches redacted ParsedModelCacheDiagnostic for storage/capacity failures. */
4640
+ parsedModelCacheDiagnostic: Signal;
4601
4641
  tweenUpdate: Signal;
4602
4642
  hover: Signal;
4603
4643
  click: Signal;
@@ -6852,6 +6892,14 @@ export declare interface ViewportOptions {
6852
6892
  useIndexedDB?: boolean;
6853
6893
  /** Maximum bytes per persistent model resource; default 1 GiB, zero disables persistence. */
6854
6894
  modelCacheMaxEntryBytes?: number;
6895
+ /** Cache decoded static Entity model resources when useIndexedDB is enabled; default true. */
6896
+ useParsedModelCache?: boolean;
6897
+ /** Parsed cache logical total budget; default 512 MiB. Zero disables and trims this cache. */
6898
+ parsedModelCacheMaxBytes?: number;
6899
+ /** Maximum logical parsed resource size; default 256 MiB. */
6900
+ parsedModelCacheMaxEntryBytes?: number;
6901
+ /** Maximum persistent parsed resources; default 256. */
6902
+ parsedModelCacheMaxEntries?: number;
6855
6903
  }
6856
6904
 
6857
6905
  export declare interface ViewportState {