soonspacejs 2.16.8 → 3.0.0-alpha.1

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,8 +1,8 @@
1
1
  {
2
2
  "name": "soonspacejs",
3
- "version": "2.16.8",
3
+ "version": "3.0.0-alpha.1",
4
4
  "homepage": "https://www.xwbuilders.com/soonspacejs/",
5
- "description": "soonspacejs 2.x",
5
+ "description": "SoonSpace.js 3.0 alpha",
6
6
  "module": "./dist/index.esm.js",
7
7
  "main": "./dist/index.esm.js",
8
8
  "types": "./types/index.d.ts",
@@ -25,11 +25,15 @@
25
25
  ],
26
26
  "author": "xunwei",
27
27
  "license": "UNLICENSED",
28
+ "dependencies": {
29
+ "@robotlegsjs/signals": "^2.1.0",
30
+ "localforage": "1.10.0"
31
+ },
28
32
  "peerDependencies": {
29
- "@types/three": ">=0.185.4",
33
+ "@types/three": ">=0.186.0",
30
34
  "camera-controls": ">=3.1.2",
31
- "postprocessing": ">=6.39.4",
32
- "three": ">=0.185.1",
35
+ "postprocessing": ">=6.39.5",
36
+ "three": ">=0.186.1",
33
37
  "three-mesh-bvh": ">=0.9.9"
34
38
  },
35
39
  "gitHead": "4a87dd85050651088e11c3da777c49fab3db7e5d"
@@ -0,0 +1,38 @@
1
+ import { BatchedMesh, Matrix4, BufferGeometry } from 'three';
2
+ /** Entity-owned batches reuse only the commands left by the immediately preceding pass. */
3
+ export declare class CachedBatchedMesh extends BatchedMesh {
4
+ private commandRevision;
5
+ private cachedRevision;
6
+ private cachedCamera?;
7
+ private cachedGeometry?;
8
+ private cachedPosition?;
9
+ private cachedPositionVersion;
10
+ private cachedIndex?;
11
+ private cachedIndexVersion;
12
+ private cachedIndexArray?;
13
+ private cachedCoordinateSystem?;
14
+ private cachedReversedDepth?;
15
+ private cachedSort?;
16
+ private cachedCull?;
17
+ private cachedTransparent?;
18
+ private cachedWireframe?;
19
+ private readonly cachedWorld;
20
+ private readonly cachedCameraWorld;
21
+ private readonly cachedView;
22
+ private readonly cachedProjection;
23
+ invalidateDrawCommands(): void;
24
+ onBeforeRender(...args: Parameters<BatchedMesh['onBeforeRender']>): void;
25
+ private rebuildDrawCommands;
26
+ setMatrixAt(instanceId: number, matrix: Matrix4): this;
27
+ setVisibleAt(instanceId: number, visible: boolean): this;
28
+ setGeometryIdAt(instanceId: number, geometryId: number): this;
29
+ addInstance(geometryId: number): number;
30
+ deleteInstance(instanceId: number): this;
31
+ addGeometry(geometry: BufferGeometry, reservedVertices?: number, reservedIndices?: number): number;
32
+ setGeometryAt(geometryId: number, geometry: BufferGeometry): number;
33
+ deleteGeometry(geometryId: number): this;
34
+ optimize(): this;
35
+ setGeometrySize(maxVertices: number, maxIndices: number): void;
36
+ setInstanceCount(maxInstances: number): void;
37
+ copy(source: this): this;
38
+ }
@@ -0,0 +1,41 @@
1
+ import { Matrix4, Object3D, Quaternion, Vector3 } from 'three';
2
+ import { ModelLease, ModelLoadOptions } from './ModelResources';
3
+ import { EntityCollection } from './EntityCollection';
4
+ export type EntityChange = 'transform' | 'visibility';
5
+ export interface EntityOptions {
6
+ id: string;
7
+ model?: ModelLease;
8
+ parent?: Entity | null;
9
+ owner?: string;
10
+ name?: string;
11
+ position?: readonly [number, number, number];
12
+ quaternion?: readonly [number, number, number, number];
13
+ scale?: readonly [number, number, number];
14
+ visible?: boolean;
15
+ /** Own model and native attachments only; descendants keep their hierarchical visibility. */
16
+ contentVisible?: boolean;
17
+ }
18
+ /** Logical identity. Editable fields are drafts; notifications capture snapshots. */
19
+ export declare class Entity {
20
+ private collection;
21
+ readonly position: Vector3;
22
+ readonly quaternion: Quaternion;
23
+ readonly scale: Vector3;
24
+ visible: boolean;
25
+ /** Draft value committed together with visible by notifyChange( 'visibility' ). */
26
+ contentVisible: boolean;
27
+ name: string;
28
+ readonly id: string;
29
+ readonly owner: string;
30
+ constructor(collection: EntityCollection, options: EntityOptions);
31
+ get parent(): Entity | null;
32
+ get children(): readonly Entity[];
33
+ get isShowing(): boolean;
34
+ get loadState(): "error" | "idle" | "loading" | "ready";
35
+ get loadError(): unknown;
36
+ replaceModel(source: ModelLease | string | null, options?: ModelLoadOptions): Promise<void>;
37
+ notifyChange(type: EntityChange): void;
38
+ getWorldMatrix(): Matrix4;
39
+ attachObject3D(object: Object3D): void;
40
+ detachObject3D(object: Object3D): void;
41
+ }
@@ -0,0 +1,62 @@
1
+ import { Box3, Matrix4, Object3D, Raycaster, Scene } from 'three';
2
+ import { Entity, EntityChange, EntityOptions } from './Entity';
3
+ import { EntityHit } from './EntityRenderer';
4
+ import { ModelResources, ModelLease, ModelLoadOptions } from './ModelResources';
5
+ import { TransparentSideVariants } from './TransparentSideVariants';
6
+ export declare class EntityCollection {
7
+ private scene;
8
+ private requestRender;
9
+ private models;
10
+ private nodes;
11
+ private ids;
12
+ private pending;
13
+ private structureDirty;
14
+ private attachmentOwners;
15
+ private renderer;
16
+ private disposed;
17
+ private batchDepth;
18
+ private updatedEntities;
19
+ private pendingModels;
20
+ private selected;
21
+ private selectionDirty;
22
+ constructor(scene: Scene, requestRender: () => void, models: ModelResources, sideVariants?: Pick<TransparentSideVariants, 'register' | 'unregister'>);
23
+ get roots(): readonly Entity[];
24
+ getById(id: string): Entity | undefined;
25
+ parentOf(entity: Entity): Entity | null;
26
+ childrenOf(entity: Entity): readonly Entity[];
27
+ showing(entity: Entity): boolean;
28
+ worldOf(entity: Entity): Matrix4;
29
+ private node;
30
+ add(options: EntityOptions): Entity;
31
+ notify(entity: Entity, type: EntityChange): void;
32
+ private schedule;
33
+ getLoadState(entity: Entity): "error" | "idle" | "loading" | "ready";
34
+ getLoadError(entity: Entity): unknown;
35
+ /** Resolve a candidate without releasing or modifying the currently drawn model. */
36
+ replaceModel(entity: Entity, source: ModelLease | string | null, options?: ModelLoadOptions): Promise<void>;
37
+ setParent(entity: Entity, parent: Entity | null): void;
38
+ remove(entity: Entity): void;
39
+ private deferredReleases;
40
+ batch(callback: () => void): void;
41
+ flushUpdates(): void;
42
+ attach(entity: Entity, object: Object3D): void;
43
+ detach(entity: Entity, object: Object3D): void;
44
+ pick(raycaster: Raycaster): EntityHit[];
45
+ /** Fresh world bounds from committed transforms, including hidden content. */
46
+ getBounds(entity: Entity, options?: {
47
+ includeDescendants?: boolean;
48
+ }): Box3;
49
+ getStats(): {
50
+ updatedEntities: number;
51
+ entities: number;
52
+ instancedBatches: number;
53
+ batchedBatches: number;
54
+ independentObjects: number;
55
+ rebuilds: number;
56
+ };
57
+ setSelection(entities: readonly Entity[]): void;
58
+ getSelection(): readonly Entity[];
59
+ setInstancingEnabled(enabled: boolean): void;
60
+ setBatchedEnabled(enabled: boolean): void;
61
+ dispose(): void;
62
+ }
@@ -0,0 +1,58 @@
1
+ import { Box3, Group, Matrix4, Raycaster, Intersection } from 'three';
2
+ import { Entity } from './Entity';
3
+ import { RegisteredPart } from './ModelResources';
4
+ import { TransparentSideVariants } from './TransparentSideVariants';
5
+ export interface EntityRenderInput {
6
+ entity: Entity;
7
+ parts: readonly RegisteredPart[];
8
+ world: Matrix4;
9
+ visible: boolean;
10
+ contentVisible: boolean;
11
+ }
12
+ export interface EntityHit extends Intersection {
13
+ entity: Entity;
14
+ partIndex?: number;
15
+ attachment?: boolean;
16
+ }
17
+ export declare class EntityRenderer {
18
+ private readonly sideVariants?;
19
+ readonly root: Group<import('three').Object3DEventMap>;
20
+ private entries;
21
+ private batches;
22
+ private mappings;
23
+ private groups;
24
+ private groupBatches;
25
+ private dirtyGroups;
26
+ private policyDirty;
27
+ private bounds;
28
+ private enabled;
29
+ private batchedEnabled;
30
+ private rebuilds;
31
+ private selection;
32
+ private selectionDirty;
33
+ private highlights;
34
+ private highlightMaterial;
35
+ constructor(sideVariants?: Pick<TransparentSideVariants, "register" | "unregister"> | undefined);
36
+ add(input: EntityRenderInput): void;
37
+ remove(entity: Entity): void;
38
+ setEnabled(enabled: boolean): void;
39
+ setBatchedEnabled(enabled: boolean): void;
40
+ setSelection(selection: ReadonlySet<Entity>): void;
41
+ private removeHighlight;
42
+ private updateHighlight;
43
+ update(changed: readonly Entity[]): void;
44
+ private assignGroup;
45
+ private rebuildGroup;
46
+ private createBatch;
47
+ private updateBatch;
48
+ pick(raycaster: Raycaster): EntityHit[];
49
+ getBounds(entity: Entity): Box3;
50
+ getStats(): {
51
+ instancedBatches: number;
52
+ batchedBatches: number;
53
+ independentObjects: number;
54
+ rebuilds: number;
55
+ };
56
+ private clearBatches;
57
+ dispose(): void;
58
+ }
@@ -0,0 +1,83 @@
1
+ import { BufferGeometry, Material, Matrix4, Texture } from 'three';
2
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
3
+ export interface ModelPart {
4
+ geometry: BufferGeometry;
5
+ material: Material | MaterialLease;
6
+ matrix: Matrix4;
7
+ visible?: boolean;
8
+ name?: string;
9
+ castShadow?: boolean;
10
+ receiveShadow?: boolean;
11
+ renderOrder?: number;
12
+ layersMask?: number;
13
+ frustumCulled?: boolean;
14
+ /** Explicitly accept batch-local transparent sorting; cross-batch order is not preserved. */
15
+ transparentBatch?: 'sorted';
16
+ /** Linear RGB multiplier, applied without modifying the shared material. */
17
+ color?: readonly [number, number, number];
18
+ }
19
+ export interface RegisteredPart extends Omit<ModelPart, 'material'> {
20
+ material: Material;
21
+ }
22
+ interface ResourceRecord<T> {
23
+ value: T;
24
+ refs: number;
25
+ dead: boolean;
26
+ gpu: Set<BufferGeometry | Material | Texture>;
27
+ dependencies: Set<ResourceRecord<Material>>;
28
+ }
29
+ export declare class ResourceLease<T> {
30
+ readonly registry: ModelResources;
31
+ private record;
32
+ private released;
33
+ constructor(registry: ModelResources, record: ResourceRecord<T>);
34
+ /** Internal ownership boundary; callers cannot retain a released lease. */
35
+ retain(): ResourceLease<T>;
36
+ get value(): T;
37
+ release(): void;
38
+ assertActive(): void;
39
+ }
40
+ export type ModelLease = ResourceLease<readonly RegisteredPart[]>;
41
+ export type MaterialLease = ResourceLease<Material>;
42
+ export interface ModelLoadOptions {
43
+ signal?: AbortSignal;
44
+ }
45
+ export type UnsupportedModelReason = 'animation-clips' | 'material-array' | 'skinning' | 'morph-targets' | 'instanced-mesh' | 'batched-mesh' | 'line-or-points';
46
+ /** A decoded resource that cannot be faithfully represented by static model parts. */
47
+ export declare class ModelResourceUnsupportedError extends Error {
48
+ readonly url: string;
49
+ readonly code = "MODEL_RESOURCE_UNSUPPORTED";
50
+ readonly reasons: readonly UnsupportedModelReason[];
51
+ constructor(url: string, reasons: readonly UnsupportedModelReason[]);
52
+ }
53
+ export declare function entityAbortError(): DOMException;
54
+ /** Owns transferred GPU graphs. Does not add loaded source trees to the Scene. */
55
+ export declare class ModelResources {
56
+ isDisposed: boolean;
57
+ private records;
58
+ private gpuRefs;
59
+ private transferred;
60
+ private pending;
61
+ private urls;
62
+ private gltfLoader;
63
+ /** Borrow a host-configured loader; its decoder workers remain host-owned. */
64
+ setGLTFLoader(loader: GLTFLoader): void;
65
+ readonly materials: {
66
+ register: (material: Material, options: {
67
+ ownership: "transfer";
68
+ }) => MaterialLease;
69
+ };
70
+ register(input: {
71
+ parts: readonly ModelPart[];
72
+ }, options: {
73
+ ownership: 'transfer';
74
+ }): ModelLease;
75
+ load(url: string, options?: ModelLoadOptions): Promise<ModelLease>;
76
+ private resolveLoad;
77
+ private create;
78
+ lease<T>(record: ResourceRecord<T>): ResourceLease<T>;
79
+ release(record: ResourceRecord<unknown>): void;
80
+ private assertLive;
81
+ dispose(): void;
82
+ }
83
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Mesh, WebGLRenderer } from 'three';
2
+ /** Reuse immutable side-specific programs for Entity-owned Standard materials.
3
+ * Only reuse materials with at least two registered supported users. Registration
4
+ * count is not visible draw count: a hidden/culled second user still enables reuse.
5
+ * Three still chooses each object's two passes and the complete render-list order.
6
+ */
7
+ export declare class TransparentSideVariants {
8
+ private readonly renderer;
9
+ private readonly objects;
10
+ private readonly records;
11
+ private sequence;
12
+ private epoch;
13
+ private enabled;
14
+ private disposed;
15
+ private readonly render;
16
+ private readonly direct;
17
+ private readonly wrappedRender;
18
+ private readonly wrappedDirect;
19
+ constructor(renderer: WebGLRenderer);
20
+ private supported;
21
+ register(mesh: Mesh): void;
22
+ unregister(mesh: Mesh): void;
23
+ private sync;
24
+ setEnabled(enabled: boolean): void;
25
+ private release;
26
+ dispose(): void;
27
+ }
@@ -0,0 +1,6 @@
1
+ export { Entity, } from './Entity';
2
+ export type { EntityOptions, EntityChange, } from './Entity';
3
+ export { EntityCollection, } from './EntityCollection';
4
+ export { ModelResources, ResourceLease, ModelResourceUnsupportedError, } from './ModelResources';
5
+ export type { ModelLease, MaterialLease, ModelPart, ModelLoadOptions, UnsupportedModelReason, } from './ModelResources';
6
+ export type { EntityHit, } from './EntityRenderer';
@@ -0,0 +1,3 @@
1
+ import { Intersection, Plane } from 'three';
2
+ /** Test world-space hit points using the submitted material's clipping policy. */
3
+ export declare function isEntityHitUnclipped(hit: Intersection, worldPlanes?: readonly Plane[]): boolean;
@@ -0,0 +1,12 @@
1
+ import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
+ interface RequestScope {
3
+ rootURL: string;
4
+ headers: HeadersInit;
5
+ signal?: AbortSignal;
6
+ }
7
+ /** Each standard GLTFLoader parse constructs its parser synchronously, before any await. */
8
+ export declare function parseScopedGLTF(loader: GLTFLoader, data: ArrayBuffer, path: string, scope: RequestScope): Promise<{
9
+ gltf: GLTF;
10
+ dependencyError?: unknown;
11
+ }>;
12
+ export {};
@@ -7,7 +7,7 @@ declare function IVector3ToEuler(val: IVector3 | Euler): Euler;
7
7
  * @param object
8
8
  * @returns
9
9
  */
10
- declare function getBoundingBox(object: Object3D, precise?: boolean, cachedBounds?: Box3 | null): Box3;
10
+ declare function getBoundingBox(object: Object3D, precise?: boolean): Box3;
11
11
  declare function rotationAxisFix(axis: AxisType, source: Euler, target: Euler): Euler;
12
12
  declare function rotationAFix(source: Euler, target: Euler): Euler;
13
13
  declare function deg2Euler(deg: number): number;
@@ -25,7 +25,9 @@ declare class Scener {
25
25
  constructor(signals: SignalsState, viewportState: ViewportState);
26
26
  addObject(object: Object3D, parent?: Object3D | null): void;
27
27
  attachObject(object: Object3D, parent?: Object3D | null): void;
28
- removeObject(object: Object3D): void;
28
+ removeObject(object: Object3D, options?: {
29
+ dispose?: boolean;
30
+ }): void;
29
31
  openSceneFog(options?: FogOptions): void;
30
32
  closeSceneFog(): void;
31
33
  edgeShow(object: Object3D | Object3D[], options?: EdgeSelectOptions): Promise<void>;
@@ -16,7 +16,7 @@ import { default as EventHandler } from './EventHandler';
16
16
  import { default as Info } from './Info';
17
17
  import { ViewHelper } from './ViewHelper';
18
18
  import { ObjectsCache } from '../Cache';
19
- import { default as AutoInstancingManager, AutoInstancingOptions, AutoInstancingStats } from './AutoInstancingManager';
19
+ import { EntityCollection, ModelResources } from '../Entity';
20
20
  export declare const innerRenderState: {
21
21
  needsUpdate: boolean;
22
22
  };
@@ -36,7 +36,9 @@ declare class Viewport {
36
36
  renderer: WebGLRenderer;
37
37
  rendererCSS2D: CSS2DRenderer;
38
38
  rendererCSS3D: CSS3DRenderer;
39
- autoInstancingManager: AutoInstancingManager;
39
+ readonly models: ModelResources;
40
+ readonly entities: EntityCollection;
41
+ private readonly transparentSideVariants;
40
42
  pmremGenerator: PMREMGenerator;
41
43
  info: Info;
42
44
  stats: Stats;
@@ -59,14 +61,11 @@ declare class Viewport {
59
61
  */
60
62
  postRender: Map<string | number, () => void>;
61
63
  private _loop;
62
- private outlineSelection;
63
64
  private pendingRenderResolvers;
64
65
  resizeObserver: ResizeObserver;
65
66
  constructor(options: ViewportOptions, signals: SignalsState, cache: ObjectsCache);
66
67
  _initInfo(): void;
67
68
  _initStats(): void;
68
- setAutoInstancing(enabled: boolean, root?: Object3D, options?: AutoInstancingOptions): void;
69
- getAutoInstancingStats(root?: Object3D): AutoInstancingStats | AutoInstancingStats[] | null;
70
69
  /**
71
70
  ***************************** post-processing ***************************
72
71
  */
@@ -116,7 +115,6 @@ declare class Viewport {
116
115
  * effect passes
117
116
  */
118
117
  _passesObserver(): void;
119
- private _syncAutoInstancingOutlineSelection;
120
118
  /**
121
119
  * 每帧都会被执行
122
120
  * @param time