@opsydyn/effect-three 0.3.0 → 0.6.4
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 +56 -0
- package/README.md +15 -1
- package/dist/{index-8cf8t6by.js → index-re3rrfwd.js} +2935 -104
- package/dist/index-re3rrfwd.js.map +56 -0
- package/dist/index-ttwy0znv.js +145 -0
- package/dist/index-ttwy0znv.js.map +12 -0
- package/dist/index.js +557 -147
- package/dist/index.js.map +8 -6
- package/dist/kernel/bodies.d.ts +20 -1
- package/dist/kernel/bodies.d.ts.map +1 -1
- package/dist/kernel/boxSelect.d.ts +22 -0
- package/dist/kernel/boxSelect.d.ts.map +1 -0
- package/dist/kernel/build.d.ts +165 -7
- package/dist/kernel/build.d.ts.map +1 -1
- package/dist/kernel/cameraShake.d.ts.map +1 -1
- package/dist/kernel/describeScene.d.ts +50 -0
- package/dist/kernel/describeScene.d.ts.map +1 -0
- package/dist/kernel/description.d.ts +223 -1
- package/dist/kernel/description.d.ts.map +1 -1
- package/dist/kernel/diff.d.ts +15 -0
- package/dist/kernel/diff.d.ts.map +1 -1
- package/dist/kernel/equality.d.ts +11 -1
- package/dist/kernel/equality.d.ts.map +1 -1
- package/dist/kernel/gizmo.d.ts +69 -0
- package/dist/kernel/gizmo.d.ts.map +1 -0
- package/dist/kernel/history.d.ts +61 -0
- package/dist/kernel/history.d.ts.map +1 -0
- package/dist/kernel/index.d.ts +19 -6
- package/dist/kernel/index.d.ts.map +1 -1
- package/dist/kernel/index.js +124 -3
- package/dist/kernel/index.js.map +1 -1
- package/dist/kernel/inspect.d.ts +85 -0
- package/dist/kernel/inspect.d.ts.map +1 -0
- package/dist/kernel/lineGeometry.d.ts +25 -0
- package/dist/kernel/lineGeometry.d.ts.map +1 -0
- package/dist/kernel/lockstep.d.ts +114 -0
- package/dist/kernel/lockstep.d.ts.map +1 -0
- package/dist/kernel/loop.d.ts.map +1 -1
- package/dist/kernel/materials.d.ts.map +1 -1
- package/dist/kernel/paintOrder.d.ts +53 -0
- package/dist/kernel/paintOrder.d.ts.map +1 -0
- package/dist/kernel/physics.d.ts +39 -0
- package/dist/kernel/physics.d.ts.map +1 -1
- package/dist/kernel/pivot.d.ts +54 -0
- package/dist/kernel/pivot.d.ts.map +1 -0
- package/dist/kernel/pointBuffers.d.ts +17 -0
- package/dist/kernel/pointBuffers.d.ts.map +1 -0
- package/dist/kernel/pointer.d.ts +31 -1
- package/dist/kernel/pointer.d.ts.map +1 -1
- package/dist/kernel/preview.d.ts +32 -0
- package/dist/kernel/preview.d.ts.map +1 -0
- package/dist/kernel/renderKit.d.ts +21 -1
- package/dist/kernel/renderKit.d.ts.map +1 -1
- package/dist/kernel/renderer.d.ts +6 -0
- package/dist/kernel/renderer.d.ts.map +1 -1
- package/dist/kernel/sceneChanges.d.ts +87 -0
- package/dist/kernel/sceneChanges.d.ts.map +1 -0
- package/dist/kernel/sceneGraph.d.ts +9 -1
- package/dist/kernel/sceneGraph.d.ts.map +1 -1
- package/dist/kernel/sceneIndex.d.ts +5 -0
- package/dist/kernel/sceneIndex.d.ts.map +1 -1
- package/dist/kernel/seeded.d.ts +9 -0
- package/dist/kernel/seeded.d.ts.map +1 -0
- package/dist/kernel/shots.d.ts +26 -0
- package/dist/kernel/shots.d.ts.map +1 -0
- package/dist/kernel/tape.d.ts +38 -0
- package/dist/kernel/tape.d.ts.map +1 -0
- package/dist/kernel/timeline.d.ts +60 -0
- package/dist/kernel/timeline.d.ts.map +1 -0
- package/dist/kernel/trail.d.ts +31 -0
- package/dist/kernel/trail.d.ts.map +1 -0
- package/dist/kernel/viewportGizmo.d.ts +25 -0
- package/dist/kernel/viewportGizmo.d.ts.map +1 -0
- package/dist/runtime/Inspector.d.ts +20 -0
- package/dist/runtime/Inspector.d.ts.map +1 -0
- package/dist/runtime/SceneFile.d.ts +462 -0
- package/dist/runtime/SceneFile.d.ts.map +1 -0
- package/dist/runtime/SceneSchema.d.ts +404 -0
- package/dist/runtime/SceneSchema.d.ts.map +1 -1
- package/dist/runtime/errors.d.ts +9 -0
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/webgl/index.d.ts.map +1 -1
- package/dist/webgl/index.js +228 -3
- package/dist/webgl/index.js.map +6 -4
- package/dist/webgl/line.d.ts +4 -0
- package/dist/webgl/line.d.ts.map +1 -0
- package/dist/webgl/points.d.ts +4 -0
- package/dist/webgl/points.d.ts.map +1 -0
- package/dist/webgpu/index.d.ts.map +1 -1
- package/dist/webgpu/index.js +206 -26
- package/dist/webgpu/index.js.map +6 -4
- package/dist/webgpu/line.d.ts +4 -0
- package/dist/webgpu/line.d.ts.map +1 -0
- package/dist/webgpu/points.d.ts +4 -0
- package/dist/webgpu/points.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/kernel/bodies.ts +299 -17
- package/src/kernel/boxSelect.ts +73 -0
- package/src/kernel/build.ts +374 -1
- package/src/kernel/cameraShake.ts +3 -13
- package/src/kernel/describeScene.ts +224 -0
- package/src/kernel/description.ts +243 -0
- package/src/kernel/diff.ts +39 -0
- package/src/kernel/equality.ts +123 -0
- package/src/kernel/gizmo.ts +478 -0
- package/src/kernel/history.ts +118 -0
- package/src/kernel/index.ts +110 -1
- package/src/kernel/inspect.ts +214 -0
- package/src/kernel/lineGeometry.ts +75 -0
- package/src/kernel/lockstep.ts +237 -0
- package/src/kernel/loop.ts +7 -0
- package/src/kernel/materials.ts +3 -0
- package/src/kernel/paintOrder.ts +274 -0
- package/src/kernel/physics.ts +86 -1
- package/src/kernel/pivot.ts +418 -0
- package/src/kernel/pointBuffers.ts +115 -0
- package/src/kernel/pointer.ts +98 -17
- package/src/kernel/preview.ts +467 -0
- package/src/kernel/renderKit.ts +23 -1
- package/src/kernel/renderer.ts +6 -0
- package/src/kernel/sceneChanges.ts +265 -0
- package/src/kernel/sceneGraph.ts +354 -11
- package/src/kernel/sceneIndex.ts +8 -0
- package/src/kernel/seeded.ts +18 -0
- package/src/kernel/shots.ts +167 -0
- package/src/kernel/tape.ts +124 -0
- package/src/kernel/timeline.ts +93 -0
- package/src/kernel/trail.ts +170 -0
- package/src/kernel/viewportGizmo.ts +194 -0
- package/src/runtime/Inspector.ts +43 -0
- package/src/runtime/SceneFile.ts +46 -0
- package/src/runtime/SceneSchema.ts +319 -0
- package/src/runtime/errors.ts +6 -0
- package/src/runtime/index.ts +3 -1
- package/src/webgl/index.ts +4 -0
- package/src/webgl/line.ts +66 -0
- package/src/webgl/points.ts +205 -0
- package/src/webgpu/index.ts +4 -0
- package/src/webgpu/line.ts +67 -0
- package/src/webgpu/points.ts +193 -0
- package/dist/index-8cf8t6by.js.map +0 -41
package/src/kernel/build.ts
CHANGED
|
@@ -3,8 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
+
import { CatmullRomCurve3, Color, CubicBezierCurve3, QuadraticBezierCurve3, Vector3 } from 'three';
|
|
7
|
+
|
|
6
8
|
import type {
|
|
9
|
+
Asset,
|
|
7
10
|
AmbientLightNode,
|
|
11
|
+
LineNode,
|
|
12
|
+
PointLook,
|
|
13
|
+
PointsNode,
|
|
14
|
+
Edges,
|
|
15
|
+
Trail,
|
|
8
16
|
Animation,
|
|
9
17
|
CameraShake,
|
|
10
18
|
Detail,
|
|
@@ -18,6 +26,8 @@ import type {
|
|
|
18
26
|
ContactShadows,
|
|
19
27
|
Environment,
|
|
20
28
|
Gestures,
|
|
29
|
+
Hud,
|
|
30
|
+
HudAlignment,
|
|
21
31
|
GridNode,
|
|
22
32
|
Sky,
|
|
23
33
|
Xr,
|
|
@@ -344,6 +354,7 @@ export const basic = (options: Partial<Omit<BasicMaterial, '_tag'>> = {}): Basic
|
|
|
344
354
|
transparent: options.transparent ?? false,
|
|
345
355
|
side: options.side ?? 'front',
|
|
346
356
|
wireframe: options.wireframe ?? false,
|
|
357
|
+
depthTest: options.depthTest ?? true,
|
|
347
358
|
});
|
|
348
359
|
|
|
349
360
|
/**
|
|
@@ -539,6 +550,7 @@ export const group = (
|
|
|
539
550
|
readonly body?: Body | null;
|
|
540
551
|
readonly follow?: XrSpace | null;
|
|
541
552
|
readonly detail?: Detail | null;
|
|
553
|
+
readonly trail?: Trail | null;
|
|
542
554
|
},
|
|
543
555
|
): GroupNode => ({
|
|
544
556
|
_tag: 'Group',
|
|
@@ -553,6 +565,7 @@ export const group = (
|
|
|
553
565
|
body: options.body ?? null,
|
|
554
566
|
follow: options.follow ?? null,
|
|
555
567
|
detail: options.detail ?? null,
|
|
568
|
+
trail: options.trail ?? null,
|
|
556
569
|
});
|
|
557
570
|
|
|
558
571
|
/**
|
|
@@ -566,6 +579,272 @@ export const detailed = (options: {
|
|
|
566
579
|
readonly hysteresis?: number;
|
|
567
580
|
}): Detail => ({ distances: options.distances, hysteresis: options.hysteresis ?? 0 });
|
|
568
581
|
|
|
582
|
+
/**
|
|
583
|
+
* A line through `points`, as Drei's `Line` (`bf6f4ad`, `src/core/Line.tsx`), with its
|
|
584
|
+
* defaults: white, 1 pixel wide, solid, opaque. three's `LineMaterial` defaults the dashes:
|
|
585
|
+
* size 1, gap 1, scale 1, offset 0. `segments: true` is Drei's `Segments`: pairs of points.
|
|
586
|
+
*/
|
|
587
|
+
export const line = (
|
|
588
|
+
options: TransformOptions & {
|
|
589
|
+
readonly points: ReadonlyArray<Vec3>;
|
|
590
|
+
readonly segments?: boolean;
|
|
591
|
+
readonly color?: Rgb;
|
|
592
|
+
readonly vertexColors?: ReadonlyArray<Rgb> | null;
|
|
593
|
+
readonly width?: number;
|
|
594
|
+
readonly worldUnits?: boolean;
|
|
595
|
+
readonly dashed?: boolean;
|
|
596
|
+
readonly dashSize?: number;
|
|
597
|
+
readonly gapSize?: number;
|
|
598
|
+
readonly dashScale?: number;
|
|
599
|
+
readonly dashOffset?: number;
|
|
600
|
+
readonly opacity?: number;
|
|
601
|
+
readonly transparent?: boolean;
|
|
602
|
+
readonly interactive?: boolean;
|
|
603
|
+
},
|
|
604
|
+
): LineNode => ({
|
|
605
|
+
_tag: 'Line',
|
|
606
|
+
key: options.key,
|
|
607
|
+
position: options.position ?? origin,
|
|
608
|
+
rotation: options.rotation ?? noRotation,
|
|
609
|
+
scale: options.scale ?? unitScale,
|
|
610
|
+
transition: options.transition ?? instantTransition,
|
|
611
|
+
behaviour: options.behaviour ?? null,
|
|
612
|
+
interactive: options.interactive ?? false,
|
|
613
|
+
points: options.points,
|
|
614
|
+
segments: options.segments ?? false,
|
|
615
|
+
color: options.color ?? 0xffffff,
|
|
616
|
+
vertexColors: options.vertexColors ?? null,
|
|
617
|
+
width: options.width ?? 1,
|
|
618
|
+
worldUnits: options.worldUnits ?? false,
|
|
619
|
+
dashed: options.dashed ?? false,
|
|
620
|
+
dashSize: options.dashSize ?? 1,
|
|
621
|
+
gapSize: options.gapSize ?? 1,
|
|
622
|
+
dashScale: options.dashScale ?? 1,
|
|
623
|
+
dashOffset: options.dashOffset ?? 0,
|
|
624
|
+
opacity: options.opacity ?? 1,
|
|
625
|
+
transparent: options.transparent ?? false,
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
const asVector = (point: Vec3): Vector3 => new Vector3(point[0], point[1], point[2]);
|
|
629
|
+
const asVec3 = (point: Vector3): Vec3 => [point.x, point.y, point.z];
|
|
630
|
+
|
|
631
|
+
/** Where a points node sits, as the other placed nodes. */
|
|
632
|
+
type Placing = Pick<
|
|
633
|
+
TransformOptions,
|
|
634
|
+
'key' | 'position' | 'rotation' | 'scale' | 'transition' | 'behaviour'
|
|
635
|
+
>;
|
|
636
|
+
|
|
637
|
+
const placed = (options: Placing, look: PointLook): PointsNode => ({
|
|
638
|
+
_tag: 'Points',
|
|
639
|
+
key: options.key,
|
|
640
|
+
position: options.position ?? origin,
|
|
641
|
+
rotation: options.rotation ?? noRotation,
|
|
642
|
+
scale: options.scale ?? unitScale,
|
|
643
|
+
transition: options.transition ?? instantTransition,
|
|
644
|
+
behaviour: options.behaviour ?? null,
|
|
645
|
+
look,
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Dots at `positions`, as Drei's `Points` (`bf6f4ad`, `src/core/Points.tsx`) with its
|
|
650
|
+
* `PointMaterial`: round, white, 1 pixel (three's `PointsMaterial` size), smaller with
|
|
651
|
+
* distance. `colors` gives each its own colour, `sizes` a factor on `size`.
|
|
652
|
+
*/
|
|
653
|
+
export const points = (
|
|
654
|
+
options: Placing & {
|
|
655
|
+
readonly positions: ReadonlyArray<Vec3>;
|
|
656
|
+
readonly colors?: ReadonlyArray<Rgb> | null;
|
|
657
|
+
readonly sizes?: ReadonlyArray<number> | null;
|
|
658
|
+
readonly color?: Rgb;
|
|
659
|
+
readonly size?: number;
|
|
660
|
+
readonly sizeAttenuation?: boolean;
|
|
661
|
+
readonly round?: boolean;
|
|
662
|
+
readonly opacity?: number;
|
|
663
|
+
readonly transparent?: boolean;
|
|
664
|
+
},
|
|
665
|
+
): PointsNode =>
|
|
666
|
+
placed(options, {
|
|
667
|
+
_tag: 'Dots',
|
|
668
|
+
positions: options.positions,
|
|
669
|
+
colors: options.colors ?? null,
|
|
670
|
+
sizes: options.sizes ?? null,
|
|
671
|
+
color: options.color ?? 0xffffff,
|
|
672
|
+
size: options.size ?? 1,
|
|
673
|
+
sizeAttenuation: options.sizeAttenuation ?? true,
|
|
674
|
+
round: options.round ?? true,
|
|
675
|
+
opacity: options.opacity ?? 1,
|
|
676
|
+
transparent: options.transparent ?? false,
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Glowing motes drifting in a box, as Drei's `Sparkles` (`src/core/Sparkles.tsx`), with
|
|
681
|
+
* its defaults: 100 of them, speed 1, opaque, a unit box (`spread`, Drei's `scale`),
|
|
682
|
+
* random sizes up to 1, white, noise 1. Drei scatters them with `Math.random`; `seed`
|
|
683
|
+
* scatters them the same way every time.
|
|
684
|
+
*/
|
|
685
|
+
export const sparkles = (
|
|
686
|
+
options: Placing & {
|
|
687
|
+
readonly count?: number;
|
|
688
|
+
readonly speed?: number;
|
|
689
|
+
readonly opacity?: number;
|
|
690
|
+
readonly size?: number | null;
|
|
691
|
+
readonly color?: Rgb;
|
|
692
|
+
readonly spread?: number | Vec3;
|
|
693
|
+
readonly noise?: number | Vec3;
|
|
694
|
+
readonly seed?: number;
|
|
695
|
+
},
|
|
696
|
+
): PointsNode => {
|
|
697
|
+
const spread = options.spread ?? 1;
|
|
698
|
+
const noise = options.noise ?? 1;
|
|
699
|
+
return placed(options, {
|
|
700
|
+
_tag: 'Sparkles',
|
|
701
|
+
count: options.count ?? 100,
|
|
702
|
+
speed: options.speed ?? 1,
|
|
703
|
+
opacity: options.opacity ?? 1,
|
|
704
|
+
scale: typeof spread === 'number' ? [spread, spread, spread] : spread,
|
|
705
|
+
size: options.size ?? null,
|
|
706
|
+
color: options.color ?? 0xffffff,
|
|
707
|
+
noise: typeof noise === 'number' ? [noise, noise, noise] : noise,
|
|
708
|
+
seed: options.seed ?? 1,
|
|
709
|
+
});
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* A starfield, as Drei's `Stars` (`src/core/Stars.tsx`), with its defaults: 5000 stars
|
|
714
|
+
* from radius 100 to 150, size factor 4, white (saturation 0), hard-edged, twinkling at
|
|
715
|
+
* speed 1. `seed` places them the same way every time.
|
|
716
|
+
*/
|
|
717
|
+
export const stars = (
|
|
718
|
+
options: Placing & {
|
|
719
|
+
readonly radius?: number;
|
|
720
|
+
readonly depth?: number;
|
|
721
|
+
readonly count?: number;
|
|
722
|
+
readonly factor?: number;
|
|
723
|
+
readonly saturation?: number;
|
|
724
|
+
readonly fade?: boolean;
|
|
725
|
+
readonly speed?: number;
|
|
726
|
+
readonly seed?: number;
|
|
727
|
+
},
|
|
728
|
+
): PointsNode =>
|
|
729
|
+
placed(options, {
|
|
730
|
+
_tag: 'Stars',
|
|
731
|
+
radius: options.radius ?? 100,
|
|
732
|
+
depth: options.depth ?? 50,
|
|
733
|
+
count: options.count ?? 5000,
|
|
734
|
+
factor: options.factor ?? 4,
|
|
735
|
+
saturation: options.saturation ?? 0,
|
|
736
|
+
fade: options.fade ?? false,
|
|
737
|
+
speed: options.speed ?? 1,
|
|
738
|
+
seed: options.seed ?? 1,
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Points along a Catmull-Rom curve through `points`, as Drei's `CatmullRomLine`, with its
|
|
743
|
+
* defaults: open, centripetal, tension 0.5, 20 segments (so 21 points).
|
|
744
|
+
*/
|
|
745
|
+
export const catmullRomPoints = (
|
|
746
|
+
points: ReadonlyArray<Vec3>,
|
|
747
|
+
options: {
|
|
748
|
+
readonly closed?: boolean;
|
|
749
|
+
readonly curveType?: 'centripetal' | 'chordal' | 'catmullrom';
|
|
750
|
+
readonly tension?: number;
|
|
751
|
+
readonly segments?: number;
|
|
752
|
+
} = {},
|
|
753
|
+
): ReadonlyArray<Vec3> =>
|
|
754
|
+
new CatmullRomCurve3(
|
|
755
|
+
points.map(asVector),
|
|
756
|
+
options.closed ?? false,
|
|
757
|
+
options.curveType ?? 'centripetal',
|
|
758
|
+
options.tension ?? 0.5,
|
|
759
|
+
)
|
|
760
|
+
.getPoints(options.segments ?? 20)
|
|
761
|
+
.map(asVec3);
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* The point `t` of the way along a Catmull-Rom curve through `points` (0 its start, 1 its
|
|
765
|
+
* end; three's `getPoint`, by parameter rather than arc length), with
|
|
766
|
+
* `catmullRomPoints`'s defaults: for something that rides the curve, a behaviour say.
|
|
767
|
+
*/
|
|
768
|
+
export const catmullRomPointAt = (
|
|
769
|
+
points: ReadonlyArray<Vec3>,
|
|
770
|
+
t: number,
|
|
771
|
+
options: {
|
|
772
|
+
readonly closed?: boolean;
|
|
773
|
+
readonly curveType?: 'centripetal' | 'chordal' | 'catmullrom';
|
|
774
|
+
readonly tension?: number;
|
|
775
|
+
} = {},
|
|
776
|
+
): Vec3 =>
|
|
777
|
+
asVec3(
|
|
778
|
+
new CatmullRomCurve3(
|
|
779
|
+
points.map(asVector),
|
|
780
|
+
options.closed ?? false,
|
|
781
|
+
options.curveType ?? 'centripetal',
|
|
782
|
+
options.tension ?? 0.5,
|
|
783
|
+
).getPoint(Math.min(1, Math.max(0, t))),
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Colours for a Catmull-Rom line's points from a few along it, as Drei's
|
|
788
|
+
* `CatmullRomLine` spreads `vertexColors` over its segments (blended in linear colour).
|
|
789
|
+
*/
|
|
790
|
+
export const catmullRomColors = (
|
|
791
|
+
colors: ReadonlyArray<Rgb>,
|
|
792
|
+
options: { readonly segments?: number; readonly closed?: boolean } = {},
|
|
793
|
+
): ReadonlyArray<Rgb> => {
|
|
794
|
+
const segments = options.segments ?? 20;
|
|
795
|
+
if (colors.length < 2 || colors.length === segments + 1) return colors;
|
|
796
|
+
const stops = colors.map((color) => new Color(color));
|
|
797
|
+
const first = stops[0];
|
|
798
|
+
if (options.closed === true && first !== undefined) stops.push(first.clone());
|
|
799
|
+
const divisions = segments / (stops.length - 1);
|
|
800
|
+
// The colour at point `index`: between the two stops either side of it.
|
|
801
|
+
const at = (index: number): Rgb =>
|
|
802
|
+
(stops[Math.floor(index / divisions)] ?? new Color())
|
|
803
|
+
.clone()
|
|
804
|
+
.lerp(
|
|
805
|
+
stops[Math.floor(index / divisions) + 1] ?? new Color(),
|
|
806
|
+
(index % divisions) / divisions,
|
|
807
|
+
)
|
|
808
|
+
.getHex();
|
|
809
|
+
const blended = Array.from({ length: segments - 1 }, (_, step) => at(step + 1));
|
|
810
|
+
return [colors[0] ?? 0, ...blended, stops.at(-1)?.getHex() ?? 0];
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
/** Points along a cubic Bézier curve, as Drei's `CubicBezierLine` (20 segments). */
|
|
814
|
+
export const cubicBezierPoints = (options: {
|
|
815
|
+
readonly start: Vec3;
|
|
816
|
+
readonly midA: Vec3;
|
|
817
|
+
readonly midB: Vec3;
|
|
818
|
+
readonly end: Vec3;
|
|
819
|
+
readonly segments?: number;
|
|
820
|
+
}): ReadonlyArray<Vec3> =>
|
|
821
|
+
new CubicBezierCurve3(
|
|
822
|
+
asVector(options.start),
|
|
823
|
+
asVector(options.midA),
|
|
824
|
+
asVector(options.midB),
|
|
825
|
+
asVector(options.end),
|
|
826
|
+
)
|
|
827
|
+
.getPoints(options.segments ?? 20)
|
|
828
|
+
.map(asVec3);
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Points along a quadratic Bézier curve, as Drei's `QuadraticBezierLine` (20 segments).
|
|
832
|
+
* Without `mid`, Drei's default: level with `start`, above or below `end`.
|
|
833
|
+
*/
|
|
834
|
+
export const quadraticBezierPoints = (options: {
|
|
835
|
+
readonly start: Vec3;
|
|
836
|
+
readonly end: Vec3;
|
|
837
|
+
readonly mid?: Vec3;
|
|
838
|
+
readonly segments?: number;
|
|
839
|
+
}): ReadonlyArray<Vec3> => {
|
|
840
|
+
const [, startY] = options.start;
|
|
841
|
+
const [endX, , endZ] = options.end;
|
|
842
|
+
const mid = options.mid ?? [endX, startY, endZ];
|
|
843
|
+
return new QuadraticBezierCurve3(asVector(options.start), asVector(mid), asVector(options.end))
|
|
844
|
+
.getPoints(options.segments ?? 20)
|
|
845
|
+
.map(asVec3);
|
|
846
|
+
};
|
|
847
|
+
|
|
569
848
|
/** The head (the viewer), for content that stays in view. */
|
|
570
849
|
export const headSpace = (): XrSpace => ({ _tag: 'Head' });
|
|
571
850
|
|
|
@@ -620,6 +899,8 @@ export const mesh = (
|
|
|
620
899
|
readonly castShadow?: boolean;
|
|
621
900
|
readonly receiveShadow?: boolean;
|
|
622
901
|
readonly body?: Body | null;
|
|
902
|
+
readonly edges?: Edges | null;
|
|
903
|
+
readonly trail?: Trail | null;
|
|
623
904
|
},
|
|
624
905
|
): MeshNode => ({
|
|
625
906
|
_tag: 'Mesh',
|
|
@@ -635,6 +916,42 @@ export const mesh = (
|
|
|
635
916
|
castShadow: options.castShadow ?? false,
|
|
636
917
|
receiveShadow: options.receiveShadow ?? false,
|
|
637
918
|
body: options.body ?? null,
|
|
919
|
+
edges: options.edges ?? null,
|
|
920
|
+
trail: options.trail ?? null,
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* A trail behind a moving node, as Drei's `Trail` (`bf6f4ad`, `src/core/Trail.tsx`), with
|
|
925
|
+
* its defaults: width 0.2, length 1, decay 1, world positions, no stride, every step, hot
|
|
926
|
+
* pink; no taper or fade (Drei's `attenuation` and `meshline` options).
|
|
927
|
+
*/
|
|
928
|
+
export const trail = (options: Partial<Trail> = {}): Trail => ({
|
|
929
|
+
width: options.width ?? 0.2,
|
|
930
|
+
length: options.length ?? 1,
|
|
931
|
+
decay: options.decay ?? 1,
|
|
932
|
+
local: options.local ?? false,
|
|
933
|
+
stride: options.stride ?? 0,
|
|
934
|
+
interval: options.interval ?? 1,
|
|
935
|
+
color: options.color ?? 0xff69b4,
|
|
936
|
+
taper: options.taper ?? 'none',
|
|
937
|
+
fade: options.fade ?? false,
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Lines along a mesh's hard edges, as Drei's `Edges` (`bf6f4ad`, `src/core/Edges.tsx`),
|
|
942
|
+
* with its defaults: faces meeting at more than 15 degrees, a white line 1 pixel wide
|
|
943
|
+
* (Drei's `Line` defaults). `mesh({ edges: edges({ color: 0x000000 }) })`.
|
|
944
|
+
*/
|
|
945
|
+
export const edges = (options: Partial<Edges> = {}): Edges => ({
|
|
946
|
+
threshold: options.threshold ?? 15,
|
|
947
|
+
color: options.color ?? 0xffffff,
|
|
948
|
+
width: options.width ?? 1,
|
|
949
|
+
worldUnits: options.worldUnits ?? false,
|
|
950
|
+
dashed: options.dashed ?? false,
|
|
951
|
+
dashSize: options.dashSize ?? 1,
|
|
952
|
+
gapSize: options.gapSize ?? 1,
|
|
953
|
+
opacity: options.opacity ?? 1,
|
|
954
|
+
transparent: options.transparent ?? false,
|
|
638
955
|
});
|
|
639
956
|
|
|
640
957
|
/**
|
|
@@ -751,13 +1068,19 @@ const noJoints: ReadonlyArray<Joint> = [];
|
|
|
751
1068
|
|
|
752
1069
|
/**
|
|
753
1070
|
* A physics world. Defaults as react-three-rapier's `Physics`: Earth gravity
|
|
754
|
-
* `[0, -9.81, 0]`, running, fixed steps of 1/60 s, interpolated; no joints
|
|
1071
|
+
* `[0, -9.81, 0]`, running, fixed steps of 1/60 s, interpolated; no joints; on scene
|
|
1072
|
+
* time rather than `until` a step the Model sets.
|
|
755
1073
|
*/
|
|
756
1074
|
export const physics = (options: Partial<Physics> = {}): Physics => ({
|
|
757
1075
|
gravity: options.gravity ?? [0, -9.81, 0],
|
|
758
1076
|
paused: options.paused ?? false,
|
|
759
1077
|
timeStep: options.timeStep ?? 1 / 60,
|
|
760
1078
|
interpolate: options.interpolate ?? true,
|
|
1079
|
+
until: options.until ?? null,
|
|
1080
|
+
run: options.run ?? 0,
|
|
1081
|
+
snapshotAt: options.snapshotAt ?? null,
|
|
1082
|
+
from: options.from ?? null,
|
|
1083
|
+
keep: options.keep ?? 0,
|
|
761
1084
|
debug: options.debug ?? false,
|
|
762
1085
|
joints: options.joints ?? noJoints,
|
|
763
1086
|
});
|
|
@@ -1358,6 +1681,38 @@ export const contactShadows = (
|
|
|
1358
1681
|
|
|
1359
1682
|
const noOverlays: ReadonlyArray<Overlay> = [];
|
|
1360
1683
|
const noMeasures: ReadonlyArray<string> = [];
|
|
1684
|
+
const noAssets: ReadonlyArray<Asset> = [];
|
|
1685
|
+
|
|
1686
|
+
/** What an asset builder takes: an id, the finest URL, and coarser ones to show first. */
|
|
1687
|
+
type AssetOptions = {
|
|
1688
|
+
readonly id: string;
|
|
1689
|
+
readonly url: string;
|
|
1690
|
+
readonly levels?: ReadonlyArray<string>;
|
|
1691
|
+
};
|
|
1692
|
+
|
|
1693
|
+
const noLevels: ReadonlyArray<string> = [];
|
|
1694
|
+
|
|
1695
|
+
const assetOf =
|
|
1696
|
+
(kind: Asset['kind']) =>
|
|
1697
|
+
({ id, url, levels }: AssetOptions): Asset => ({ kind, id, url, levels: levels ?? noLevels });
|
|
1698
|
+
|
|
1699
|
+
/** A glTF or GLB model for `scene({ assets })`, lent under `id` for `borrowed({ id })`. */
|
|
1700
|
+
export const modelAsset = assetOf('model');
|
|
1701
|
+
|
|
1702
|
+
/** A colour texture (sRGB) for `scene({ assets })`, lent under `id` for a material's `map`. */
|
|
1703
|
+
export const textureAsset = assetOf('texture');
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* An equirectangular HDR panorama (`.hdr`) for `scene({ assets })`, lent under `id` for
|
|
1707
|
+
* `environment({ map: id })`.
|
|
1708
|
+
*/
|
|
1709
|
+
export const environmentAsset = assetOf('environment');
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* A typeface JSON font (three.js's `FontLoader` format) for `scene({ assets })`, lent under
|
|
1713
|
+
* `id` for `text({ font: id })`.
|
|
1714
|
+
*/
|
|
1715
|
+
export const fontAsset = assetOf('font');
|
|
1361
1716
|
|
|
1362
1717
|
/** Drei's `zIndexRange` default: near points on top, far ones at 0. */
|
|
1363
1718
|
const defaultZIndexRange: readonly [number, number] = [16777271, 0];
|
|
@@ -1386,11 +1741,26 @@ export const overlay = (options: {
|
|
|
1386
1741
|
view: options.view ?? null,
|
|
1387
1742
|
});
|
|
1388
1743
|
|
|
1744
|
+
/**
|
|
1745
|
+
* Nodes drawn over the scene (Drei's `Hud`), with Drei's `GizmoHelper` defaults: the
|
|
1746
|
+
* origin 80 CSS pixels in from the bottom right.
|
|
1747
|
+
*/
|
|
1748
|
+
export const hud = (options: {
|
|
1749
|
+
readonly alignment?: HudAlignment;
|
|
1750
|
+
readonly margin?: readonly [number, number];
|
|
1751
|
+
readonly children?: ReadonlyArray<SceneNode>;
|
|
1752
|
+
}): Hud => ({
|
|
1753
|
+
alignment: options.alignment ?? 'bottom-right',
|
|
1754
|
+
margin: options.margin ?? [80, 80],
|
|
1755
|
+
children: options.children ?? [],
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1389
1758
|
export const scene = (options: {
|
|
1390
1759
|
readonly camera?: Camera;
|
|
1391
1760
|
readonly gestures?: Gestures;
|
|
1392
1761
|
readonly views?: ReadonlyArray<View>;
|
|
1393
1762
|
readonly renderTextures?: ReadonlyArray<RenderTexture>;
|
|
1763
|
+
readonly hud?: Hud | null;
|
|
1394
1764
|
readonly overlays?: ReadonlyArray<Overlay>;
|
|
1395
1765
|
/** Optional staging: leave out or pass `null` for none, so a Model can switch it off. */
|
|
1396
1766
|
readonly environment?: Environment | null;
|
|
@@ -1399,6 +1769,7 @@ export const scene = (options: {
|
|
|
1399
1769
|
readonly physics?: Physics | null;
|
|
1400
1770
|
readonly xr?: Xr | null;
|
|
1401
1771
|
readonly measure?: ReadonlyArray<string>;
|
|
1772
|
+
readonly assets?: ReadonlyArray<Asset>;
|
|
1402
1773
|
readonly render?: RenderSettings;
|
|
1403
1774
|
readonly resources?: Partial<ResourceDefinitions>;
|
|
1404
1775
|
readonly children?: ReadonlyArray<SceneNode>;
|
|
@@ -1407,6 +1778,7 @@ export const scene = (options: {
|
|
|
1407
1778
|
gestures: options.gestures ?? 'page',
|
|
1408
1779
|
views: options.views ?? noViews,
|
|
1409
1780
|
renderTextures: options.renderTextures ?? noRenderTextures,
|
|
1781
|
+
hud: options.hud ?? null,
|
|
1410
1782
|
overlays: options.overlays ?? noOverlays,
|
|
1411
1783
|
environment: options.environment ?? null,
|
|
1412
1784
|
sky: options.sky ?? null,
|
|
@@ -1414,6 +1786,7 @@ export const scene = (options: {
|
|
|
1414
1786
|
physics: options.physics ?? null,
|
|
1415
1787
|
xr: options.xr ?? null,
|
|
1416
1788
|
measure: options.measure ?? noMeasures,
|
|
1789
|
+
assets: options.assets ?? noAssets,
|
|
1417
1790
|
render: options.render ?? defaultRenderSettings,
|
|
1418
1791
|
resources: {
|
|
1419
1792
|
geometries: options.resources?.geometries ?? noResources.geometries,
|
|
@@ -15,20 +15,10 @@ import { SimplexNoise } from 'three/addons/math/SimplexNoise.js';
|
|
|
15
15
|
|
|
16
16
|
import type { CameraShake } from './description.ts';
|
|
17
17
|
import { cameraShakeEquals } from './equality.ts';
|
|
18
|
+
import { seededRandom } from './seeded.ts';
|
|
18
19
|
|
|
19
|
-
/**
|
|
20
|
-
const seeded = (seed: number)
|
|
21
|
-
let state = seed >>> 0;
|
|
22
|
-
return {
|
|
23
|
-
random: () => {
|
|
24
|
-
state = (state + 0x6d2b79f5) >>> 0;
|
|
25
|
-
let t = state;
|
|
26
|
-
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
27
|
-
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
28
|
-
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
};
|
|
20
|
+
/** Each axis's noise, seeded so the shake is the same on every page load. */
|
|
21
|
+
const seeded = (seed: number) => ({ random: seededRandom(seed) });
|
|
32
22
|
|
|
33
23
|
const yawNoise = new SimplexNoise(seeded(1));
|
|
34
24
|
const pitchNoise = new SimplexNoise(seeded(2));
|