@3driseai/3drise-viewer 0.1.39 → 0.1.41
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/dist/animationsV2/ClipsRuntime.d.ts +30 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +185 -14
- package/dist/animationsV2/clipUtils.d.ts +15 -0
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +39 -2
- package/dist/animationsV2/normalize.d.ts.map +1 -1
- package/dist/animationsV2/normalize.js +4 -0
- package/dist/animationsV2/types.d.ts +12 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/api/sceneHandle.d.ts +40 -3
- package/dist/api/sceneHandle.d.ts.map +1 -1
- package/dist/api/sceneHandle.js +40 -0
- package/dist/components/AnimatedObject.d.ts.map +1 -1
- package/dist/components/AnimatedObject.js +6 -2
- package/dist/components/EnabledContext.d.ts +12 -0
- package/dist/components/EnabledContext.d.ts.map +1 -0
- package/dist/components/EnabledContext.js +12 -0
- package/dist/components/GalleryObject.d.ts +13 -0
- package/dist/components/GalleryObject.d.ts.map +1 -0
- package/dist/components/GalleryObject.js +46 -0
- package/dist/components/ImageObject.d.ts +9 -0
- package/dist/components/ImageObject.d.ts.map +1 -0
- package/dist/components/ImageObject.js +26 -0
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +17 -6
- package/dist/components/ObjectsRenderer.d.ts.map +1 -1
- package/dist/components/ObjectsRenderer.js +9 -0
- package/dist/components/ProjectLoader.d.ts +2 -0
- package/dist/components/ProjectLoader.d.ts.map +1 -1
- package/dist/components/ProjectLoader.js +2 -2
- package/dist/components/SceneBuilder.d.ts +10 -0
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SceneBuilder.js +3 -2
- package/dist/components/gallery/BasicCarouselGallery.d.ts +18 -0
- package/dist/components/gallery/BasicCarouselGallery.d.ts.map +1 -0
- package/dist/components/gallery/BasicCarouselGallery.js +9 -0
- package/dist/components/gallery/ContourLinesGallery.d.ts +18 -0
- package/dist/components/gallery/ContourLinesGallery.d.ts.map +1 -0
- package/dist/components/gallery/ContourLinesGallery.js +9 -0
- package/dist/components/gallery/DepthLayersGallery.d.ts +18 -0
- package/dist/components/gallery/DepthLayersGallery.d.ts.map +1 -0
- package/dist/components/gallery/DepthLayersGallery.js +9 -0
- package/dist/components/gallery/EngravingGallery.d.ts +18 -0
- package/dist/components/gallery/EngravingGallery.d.ts.map +1 -0
- package/dist/components/gallery/EngravingGallery.js +9 -0
- package/dist/components/gallery/FlowLinesGallery.d.ts +18 -0
- package/dist/components/gallery/FlowLinesGallery.d.ts.map +1 -0
- package/dist/components/gallery/FlowLinesGallery.js +9 -0
- package/dist/components/gallery/FoldGallery.d.ts +18 -0
- package/dist/components/gallery/FoldGallery.d.ts.map +1 -0
- package/dist/components/gallery/FoldGallery.js +9 -0
- package/dist/components/gallery/GlassPanesGallery.d.ts +18 -0
- package/dist/components/gallery/GlassPanesGallery.d.ts.map +1 -0
- package/dist/components/gallery/GlassPanesGallery.js +9 -0
- package/dist/components/gallery/HaloGallery.d.ts +18 -0
- package/dist/components/gallery/HaloGallery.d.ts.map +1 -0
- package/dist/components/gallery/HaloGallery.js +9 -0
- package/dist/components/gallery/LightThreadsGallery.d.ts +18 -0
- package/dist/components/gallery/LightThreadsGallery.d.ts.map +1 -0
- package/dist/components/gallery/LightThreadsGallery.js +9 -0
- package/dist/components/gallery/LoomGallery.d.ts +18 -0
- package/dist/components/gallery/LoomGallery.d.ts.map +1 -0
- package/dist/components/gallery/LoomGallery.js +9 -0
- package/dist/components/gallery/PaperLanternsGallery.d.ts +18 -0
- package/dist/components/gallery/PaperLanternsGallery.d.ts.map +1 -0
- package/dist/components/gallery/PaperLanternsGallery.js +9 -0
- package/dist/components/gallery/ParticleShiftGallery.d.ts +18 -0
- package/dist/components/gallery/ParticleShiftGallery.d.ts.map +1 -0
- package/dist/components/gallery/ParticleShiftGallery.js +9 -0
- package/dist/components/gallery/PinscreenGallery.d.ts +18 -0
- package/dist/components/gallery/PinscreenGallery.d.ts.map +1 -0
- package/dist/components/gallery/PinscreenGallery.js +9 -0
- package/dist/components/gallery/PopUpGallery.d.ts +18 -0
- package/dist/components/gallery/PopUpGallery.d.ts.map +1 -0
- package/dist/components/gallery/PopUpGallery.js +9 -0
- package/dist/components/gallery/PrismSplitGallery.d.ts +18 -0
- package/dist/components/gallery/PrismSplitGallery.d.ts.map +1 -0
- package/dist/components/gallery/PrismSplitGallery.js +9 -0
- package/dist/components/gallery/RidgelinesGallery.d.ts +18 -0
- package/dist/components/gallery/RidgelinesGallery.d.ts.map +1 -0
- package/dist/components/gallery/RidgelinesGallery.js +9 -0
- package/dist/components/gallery/ShadowBoxGallery.d.ts +18 -0
- package/dist/components/gallery/ShadowBoxGallery.d.ts.map +1 -0
- package/dist/components/gallery/ShadowBoxGallery.js +9 -0
- package/dist/components/gallery/SilkGallery.d.ts +18 -0
- package/dist/components/gallery/SilkGallery.d.ts.map +1 -0
- package/dist/components/gallery/SilkGallery.js +9 -0
- package/dist/components/gallery/SlatsGallery.d.ts +18 -0
- package/dist/components/gallery/SlatsGallery.d.ts.map +1 -0
- package/dist/components/gallery/SlatsGallery.js +9 -0
- package/dist/components/gallery/StrataGallery.d.ts +18 -0
- package/dist/components/gallery/StrataGallery.d.ts.map +1 -0
- package/dist/components/gallery/StrataGallery.js +9 -0
- package/dist/components/gallery/TerracesGallery.d.ts +18 -0
- package/dist/components/gallery/TerracesGallery.d.ts.map +1 -0
- package/dist/components/gallery/TerracesGallery.js +9 -0
- package/dist/components/gallery/WireReliefGallery.d.ts +18 -0
- package/dist/components/gallery/WireReliefGallery.d.ts.map +1 -0
- package/dist/components/gallery/WireReliefGallery.js +9 -0
- package/dist/components/gallery/index.d.ts +46 -0
- package/dist/components/gallery/index.d.ts.map +1 -0
- package/dist/components/gallery/index.js +22 -0
- package/dist/components/gallery/kit/GalleryVariant.d.ts +68 -0
- package/dist/components/gallery/kit/GalleryVariant.d.ts.map +1 -0
- package/dist/components/gallery/kit/GalleryVariant.js +231 -0
- package/dist/components/gallery/kit/feeds.d.ts +7 -0
- package/dist/components/gallery/kit/feeds.d.ts.map +1 -0
- package/dist/components/gallery/kit/feeds.js +83 -0
- package/dist/components/gallery/kit/galleryKit.d.ts +118 -0
- package/dist/components/gallery/kit/galleryKit.d.ts.map +1 -0
- package/dist/components/gallery/kit/galleryKit.js +298 -0
- package/dist/components/gallery/kit/lookBase.d.ts +157 -0
- package/dist/components/gallery/kit/lookBase.d.ts.map +1 -0
- package/dist/components/gallery/kit/lookBase.js +211 -0
- package/dist/components/gallery/kit/pictures.d.ts +14 -0
- package/dist/components/gallery/kit/pictures.d.ts.map +1 -0
- package/dist/components/gallery/kit/pictures.js +81 -0
- package/dist/components/gallery/looks/basicCarousel.d.ts +177 -0
- package/dist/components/gallery/looks/basicCarousel.d.ts.map +1 -0
- package/dist/components/gallery/looks/basicCarousel.js +315 -0
- package/dist/components/gallery/looks/contourLines.d.ts +153 -0
- package/dist/components/gallery/looks/contourLines.d.ts.map +1 -0
- package/dist/components/gallery/looks/contourLines.js +91 -0
- package/dist/components/gallery/looks/depthLayers.d.ts +155 -0
- package/dist/components/gallery/looks/depthLayers.d.ts.map +1 -0
- package/dist/components/gallery/looks/depthLayers.js +87 -0
- package/dist/components/gallery/looks/engraving.d.ts +162 -0
- package/dist/components/gallery/looks/engraving.d.ts.map +1 -0
- package/dist/components/gallery/looks/engraving.js +96 -0
- package/dist/components/gallery/looks/flowLines.d.ts +180 -0
- package/dist/components/gallery/looks/flowLines.d.ts.map +1 -0
- package/dist/components/gallery/looks/flowLines.js +113 -0
- package/dist/components/gallery/looks/fold.d.ts +209 -0
- package/dist/components/gallery/looks/fold.d.ts.map +1 -0
- package/dist/components/gallery/looks/fold.js +155 -0
- package/dist/components/gallery/looks/glassPanes.d.ts +133 -0
- package/dist/components/gallery/looks/glassPanes.d.ts.map +1 -0
- package/dist/components/gallery/looks/glassPanes.js +208 -0
- package/dist/components/gallery/looks/halo.d.ts +100 -0
- package/dist/components/gallery/looks/halo.d.ts.map +1 -0
- package/dist/components/gallery/looks/halo.js +119 -0
- package/dist/components/gallery/looks/lightThreads.d.ts +199 -0
- package/dist/components/gallery/looks/lightThreads.d.ts.map +1 -0
- package/dist/components/gallery/looks/lightThreads.js +246 -0
- package/dist/components/gallery/looks/loom.d.ts +238 -0
- package/dist/components/gallery/looks/loom.d.ts.map +1 -0
- package/dist/components/gallery/looks/loom.js +256 -0
- package/dist/components/gallery/looks/paperLanterns.d.ts +181 -0
- package/dist/components/gallery/looks/paperLanterns.d.ts.map +1 -0
- package/dist/components/gallery/looks/paperLanterns.js +399 -0
- package/dist/components/gallery/looks/particleShift.d.ts +193 -0
- package/dist/components/gallery/looks/particleShift.d.ts.map +1 -0
- package/dist/components/gallery/looks/particleShift.js +282 -0
- package/dist/components/gallery/looks/pinscreen.d.ts +175 -0
- package/dist/components/gallery/looks/pinscreen.d.ts.map +1 -0
- package/dist/components/gallery/looks/pinscreen.js +96 -0
- package/dist/components/gallery/looks/popUp.d.ts +206 -0
- package/dist/components/gallery/looks/popUp.d.ts.map +1 -0
- package/dist/components/gallery/looks/popUp.js +132 -0
- package/dist/components/gallery/looks/prismSplit.d.ts +151 -0
- package/dist/components/gallery/looks/prismSplit.d.ts.map +1 -0
- package/dist/components/gallery/looks/prismSplit.js +84 -0
- package/dist/components/gallery/looks/ridgelines.d.ts +179 -0
- package/dist/components/gallery/looks/ridgelines.d.ts.map +1 -0
- package/dist/components/gallery/looks/ridgelines.js +111 -0
- package/dist/components/gallery/looks/shadowBox.d.ts +152 -0
- package/dist/components/gallery/looks/shadowBox.d.ts.map +1 -0
- package/dist/components/gallery/looks/shadowBox.js +82 -0
- package/dist/components/gallery/looks/silk.d.ts +140 -0
- package/dist/components/gallery/looks/silk.d.ts.map +1 -0
- package/dist/components/gallery/looks/silk.js +346 -0
- package/dist/components/gallery/looks/slats.d.ts +176 -0
- package/dist/components/gallery/looks/slats.d.ts.map +1 -0
- package/dist/components/gallery/looks/slats.js +93 -0
- package/dist/components/gallery/looks/strata.d.ts +172 -0
- package/dist/components/gallery/looks/strata.d.ts.map +1 -0
- package/dist/components/gallery/looks/strata.js +88 -0
- package/dist/components/gallery/looks/terraces.d.ts +168 -0
- package/dist/components/gallery/looks/terraces.d.ts.map +1 -0
- package/dist/components/gallery/looks/terraces.js +91 -0
- package/dist/components/gallery/looks/wireRelief.d.ts +153 -0
- package/dist/components/gallery/looks/wireRelief.d.ts.map +1 -0
- package/dist/components/gallery/looks/wireRelief.js +128 -0
- package/dist/components/image/ContourImage.d.ts +7 -0
- package/dist/components/image/ContourImage.d.ts.map +1 -0
- package/dist/components/image/ContourImage.js +6 -0
- package/dist/components/image/EngravingImage.d.ts +7 -0
- package/dist/components/image/EngravingImage.d.ts.map +1 -0
- package/dist/components/image/EngravingImage.js +6 -0
- package/dist/components/image/FrostImage.d.ts +7 -0
- package/dist/components/image/FrostImage.d.ts.map +1 -0
- package/dist/components/image/FrostImage.js +6 -0
- package/dist/components/image/LenticularImage.d.ts +7 -0
- package/dist/components/image/LenticularImage.d.ts.map +1 -0
- package/dist/components/image/LenticularImage.js +6 -0
- package/dist/components/image/PinscreenImage.d.ts +7 -0
- package/dist/components/image/PinscreenImage.d.ts.map +1 -0
- package/dist/components/image/PinscreenImage.js +6 -0
- package/dist/components/image/PrismImage.d.ts +7 -0
- package/dist/components/image/PrismImage.d.ts.map +1 -0
- package/dist/components/image/PrismImage.js +6 -0
- package/dist/components/image/ProjectorImage.d.ts +7 -0
- package/dist/components/image/ProjectorImage.d.ts.map +1 -0
- package/dist/components/image/ProjectorImage.js +6 -0
- package/dist/components/image/ReliefImage.d.ts +7 -0
- package/dist/components/image/ReliefImage.d.ts.map +1 -0
- package/dist/components/image/ReliefImage.js +6 -0
- package/dist/components/image/RollImage.d.ts +7 -0
- package/dist/components/image/RollImage.d.ts.map +1 -0
- package/dist/components/image/RollImage.js +6 -0
- package/dist/components/image/ShardsImage.d.ts +126 -0
- package/dist/components/image/ShardsImage.d.ts.map +1 -0
- package/dist/components/image/ShardsImage.js +470 -0
- package/dist/components/image/core/contour.d.ts +126 -0
- package/dist/components/image/core/contour.d.ts.map +1 -0
- package/dist/components/image/core/contour.js +123 -0
- package/dist/components/image/core/engraving.d.ts +135 -0
- package/dist/components/image/core/engraving.d.ts.map +1 -0
- package/dist/components/image/core/engraving.js +163 -0
- package/dist/components/image/core/frost.d.ts +126 -0
- package/dist/components/image/core/frost.d.ts.map +1 -0
- package/dist/components/image/core/frost.js +156 -0
- package/dist/components/image/core/imageCore.d.ts +110 -0
- package/dist/components/image/core/imageCore.d.ts.map +1 -0
- package/dist/components/image/core/imageCore.js +269 -0
- package/dist/components/image/core/lenticular.d.ts +129 -0
- package/dist/components/image/core/lenticular.d.ts.map +1 -0
- package/dist/components/image/core/lenticular.js +132 -0
- package/dist/components/image/core/pinscreen.d.ts +126 -0
- package/dist/components/image/core/pinscreen.d.ts.map +1 -0
- package/dist/components/image/core/pinscreen.js +147 -0
- package/dist/components/image/core/prism.d.ts +120 -0
- package/dist/components/image/core/prism.d.ts.map +1 -0
- package/dist/components/image/core/prism.js +164 -0
- package/dist/components/image/core/projector.d.ts +135 -0
- package/dist/components/image/core/projector.d.ts.map +1 -0
- package/dist/components/image/core/projector.js +225 -0
- package/dist/components/image/core/relief.d.ts +111 -0
- package/dist/components/image/core/relief.d.ts.map +1 -0
- package/dist/components/image/core/relief.js +94 -0
- package/dist/components/image/core/roll.d.ts +114 -0
- package/dist/components/image/core/roll.d.ts.map +1 -0
- package/dist/components/image/core/roll.js +116 -0
- package/dist/components/image/imageVariant.d.ts +46 -0
- package/dist/components/image/imageVariant.d.ts.map +1 -0
- package/dist/components/image/imageVariant.js +128 -0
- package/dist/components/image/index.d.ts +22 -0
- package/dist/components/image/index.d.ts.map +1 -0
- package/dist/components/image/index.js +10 -0
- package/dist/components/image/pictureCycle.d.ts +15 -0
- package/dist/components/image/pictureCycle.d.ts.map +1 -0
- package/dist/components/image/pictureCycle.js +82 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +9 -7
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
- package/dist/components/volumetricClouds/VolumetricCloudsPass.js +39 -27
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +18 -5
- package/dist/galleryRuntime.d.ts +57 -0
- package/dist/galleryRuntime.d.ts.map +1 -0
- package/dist/galleryRuntime.js +105 -0
- package/dist/hooks/useConfigLive.d.ts +1 -1
- package/dist/hooks/useConfigLive.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/keyPad/KeyPadControls.d.ts +16 -0
- package/dist/keyPad/KeyPadControls.d.ts.map +1 -0
- package/dist/keyPad/KeyPadControls.js +176 -0
- package/dist/keyPad/index.d.ts +16 -0
- package/dist/keyPad/index.d.ts.map +1 -0
- package/dist/keyPad/index.js +8 -0
- package/dist/keyPad/keyBindings.d.ts +43 -0
- package/dist/keyPad/keyBindings.d.ts.map +1 -0
- package/dist/keyPad/keyBindings.js +92 -0
- package/dist/keyPad/keyPadAnimation.d.ts +28 -0
- package/dist/keyPad/keyPadAnimation.d.ts.map +1 -0
- package/dist/keyPad/keyPadAnimation.js +131 -0
- package/dist/keyPad/keyPadMotion.d.ts +68 -0
- package/dist/keyPad/keyPadMotion.d.ts.map +1 -0
- package/dist/keyPad/keyPadMotion.js +283 -0
- package/dist/keyPad/keyPadStore.d.ts +25 -0
- package/dist/keyPad/keyPadStore.d.ts.map +1 -0
- package/dist/keyPad/keyPadStore.js +63 -0
- package/dist/keyPad/types.d.ts +23 -0
- package/dist/keyPad/types.d.ts.map +1 -0
- package/dist/keyPad/types.js +9 -0
- package/dist/operations/catalogue/motionTrail.d.ts.map +1 -1
- package/dist/operations/catalogue/motionTrail.js +8 -1
- package/dist/operations/catalogue/visibility.d.ts.map +1 -1
- package/dist/operations/catalogue/visibility.js +23 -1
- package/dist/shaders/clouds/CloudResolveMaterial.d.ts +2 -1
- package/dist/shaders/clouds/CloudResolveMaterial.d.ts.map +1 -1
- package/dist/shaders/clouds/CloudResolveMaterial.js +37 -12
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +4 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -1
- package/dist/shaders/clouds/CloudVolumeMaterial.js +15 -3
- package/dist/triggers/kinds/gallery.d.ts +2 -0
- package/dist/triggers/kinds/gallery.d.ts.map +1 -0
- package/dist/triggers/kinds/gallery.js +39 -0
- package/dist/triggers/kinds/index.d.ts +1 -0
- package/dist/triggers/kinds/index.d.ts.map +1 -1
- package/dist/triggers/kinds/index.js +1 -0
- package/dist/ui/UiAnchorUpdater.d.ts.map +1 -1
- package/dist/ui/UiAnchorUpdater.js +2 -1
- package/dist/utils/cursorPicking.d.ts.map +1 -1
- package/dist/utils/cursorPicking.js +2 -1
- package/dist/utils/shownInScene.d.ts +13 -0
- package/dist/utils/shownInScene.d.ts.map +1 -0
- package/dist/utils/shownInScene.js +16 -0
- package/package.json +2 -2
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// The approved lab module, verbatim but for its import paths and the lab's picture loader (Claude outputs/gallery-lab/
|
|
2
|
+
// carousel.mjs). Plain JS-shaped code (the viewer compiles non-strict); typed at its one door, kit/GalleryVariant.tsx. Its own DEFAULTS only fill knobs the
|
|
3
|
+
// core defaults (DEFAULT_GALLERY_OBJECTS.basicCarousel) do not carry; its own autoplay is never used.
|
|
4
|
+
// carousel — a gallery variant for 3drise (type 'gallery', config.type 'carousel').
|
|
5
|
+
//
|
|
6
|
+
// Construction: the pictures sit on a conveyor of frames, one InstancedMesh (+ its
|
|
7
|
+
// reflection, a second draw). One number drives everything — the scroll position
|
|
8
|
+
// `s`, a float index — and every frame's place is a function of its offset
|
|
9
|
+
// d = i - s (wrapped, so the set is a ring): position along an arc that blends
|
|
10
|
+
// from a flat row to a circle (`curve`), a coverflow yaw toward the centre
|
|
11
|
+
// (`tilt`) growing with |d|, recession in depth, a lift + scale for the frame at
|
|
12
|
+
// d ≈ 0 (`focusScale`, `focusLift`), dimming and fade-out with distance. `s`
|
|
13
|
+
// is a damped spring toward the target index: next/prev/goTo set the target; a
|
|
14
|
+
// drag moves `s` directly and the release velocity throws it, then it snaps to
|
|
15
|
+
// the nearest frame — so motion is one continuous law, never a tween per frame.
|
|
16
|
+
// Idle: a slow breathing float with a phase per frame (zero net motion).
|
|
17
|
+
// The cursor: `tilt` yaws the nearby frames toward it, `lift` raises the frame
|
|
18
|
+
// under it; nothing is drawn at the cursor. Clicking the centre frame focuses it
|
|
19
|
+
// (it comes forward); clicking a neighbour scrolls to it.
|
|
20
|
+
import * as THREE from 'three';
|
|
21
|
+
import { withLean } from '../kit/galleryKit.js';
|
|
22
|
+
export const catalog = {
|
|
23
|
+
key: 'carousel',
|
|
24
|
+
name: 'Carousel',
|
|
25
|
+
description: 'A coverflow ring of framed pictures driven by one damped scroll position — next, prev, drag with inertia and snap, a lifted focus frame and a floor reflection; the cursor tilts or lifts the frames. Use for portfolios, product lines, photo showcases.',
|
|
26
|
+
tags: ['gallery', 'carousel', 'coverflow', 'ring', 'reflection', 'navigation', 'interactive'],
|
|
27
|
+
camera: { position: [0, 0.35, 4.6], target: [0, -0.1, 0] },
|
|
28
|
+
};
|
|
29
|
+
export const DEFAULTS = {
|
|
30
|
+
type: 'carousel',
|
|
31
|
+
enabled: true, lean: 1,
|
|
32
|
+
imageUrls: [],
|
|
33
|
+
autoplay: 0,
|
|
34
|
+
intensity: 1,
|
|
35
|
+
opacity: 1,
|
|
36
|
+
// --- structural ---
|
|
37
|
+
aspect: 1.5, // frame width / height
|
|
38
|
+
frameWidth: 1.6, // width of a frame (gallery units)
|
|
39
|
+
// --- layout ---
|
|
40
|
+
spacing: 1.15, // distance between neighbours, in frame widths
|
|
41
|
+
curve: 0.6, // 0 = flat row, 1 = a circle
|
|
42
|
+
tilt: 0.95, // coverflow yaw of the neighbours (rad)
|
|
43
|
+
depth: 0.9, // how far neighbours recede
|
|
44
|
+
visible: 3.2, // frames each side before they fade out
|
|
45
|
+
focusScale: 1.25, // scale of the centre frame
|
|
46
|
+
focusLift: 0.35, // how far the centre frame comes forward
|
|
47
|
+
focusAmount: 0.8, // extra forward travel when the centre frame is clicked (focused)
|
|
48
|
+
dim: 0.55, // darkening of the neighbours
|
|
49
|
+
// --- motion ---
|
|
50
|
+
stiffness: 60, // spring toward the target (1/s²)
|
|
51
|
+
damping: 12, // spring damping (1/s)
|
|
52
|
+
throwing: 0.18, // how far a drag release throws (s of velocity)
|
|
53
|
+
breathe: 0.5, // idle float
|
|
54
|
+
// --- look ---
|
|
55
|
+
reflection: 0.45,
|
|
56
|
+
floorGap: 0.12,
|
|
57
|
+
border: 0.02, // frame border, in frame units
|
|
58
|
+
borderColor: '#f3e6cf',
|
|
59
|
+
backColor: '#1a1d26',
|
|
60
|
+
// --- pointer ---
|
|
61
|
+
pointerMode: 'tilt',
|
|
62
|
+
pointerStrength: 1,
|
|
63
|
+
pointerRadius: 1.6,
|
|
64
|
+
pointerColor: '#ffd9a6',
|
|
65
|
+
};
|
|
66
|
+
export const STRUCTURAL = ['imageUrls', 'aspect', 'frameWidth'];
|
|
67
|
+
export const POINTER_MODES = ['tilt', 'lift'];
|
|
68
|
+
export const GUI = [
|
|
69
|
+
{ key: 'lean', min: 0, max: 3, step: 0.01, tip: 'The gallery turns toward the cursor' },
|
|
70
|
+
{ key: 'aspect', min: 0.5, max: 2.5, step: 0.01, tip: 'Frame width / height (rebuild)' },
|
|
71
|
+
{ key: 'frameWidth', min: 0.5, max: 3, step: 0.01, tip: 'Frame width (rebuild)' },
|
|
72
|
+
{ key: 'spacing', min: 0.4, max: 2.5, step: 0.01 }, { key: 'curve', min: 0, max: 1, step: 0.01 }, { key: 'tilt', min: 0, max: 1.5, step: 0.01 },
|
|
73
|
+
{ key: 'depth', min: 0, max: 2, step: 0.01 }, { key: 'visible', min: 1, max: 8, step: 0.1 },
|
|
74
|
+
{ key: 'focusScale', min: 1, max: 2, step: 0.01 }, { key: 'focusLift', min: 0, max: 1.5, step: 0.01 }, { key: 'focusAmount', min: 0, max: 3, step: 0.01 }, { key: 'dim', min: 0, max: 1, step: 0.01 },
|
|
75
|
+
{ key: 'stiffness', min: 5, max: 200, step: 1 }, { key: 'damping', min: 2, max: 40, step: 0.1 }, { key: 'throwing', min: 0, max: 0.6, step: 0.01 }, { key: 'breathe', min: 0, max: 2, step: 0.01 },
|
|
76
|
+
{ key: 'reflection', min: 0, max: 1, step: 0.01 }, { key: 'floorGap', min: 0, max: 0.6, step: 0.01 }, { key: 'border', min: 0, max: 0.08, step: 0.001 },
|
|
77
|
+
{ key: 'autoplay', min: 0, max: 20, step: 0.5 },
|
|
78
|
+
{ key: 'pointerMode', options: ['none', ...POINTER_MODES] }, { key: 'pointerStrength', min: 0, max: 3, step: 0.01 }, { key: 'pointerRadius', min: 0.2, max: 4, step: 0.01 },
|
|
79
|
+
{ key: 'intensity', min: 0, max: 2, step: 0.01 }, { key: 'opacity', min: 0, max: 1, step: 0.01 },
|
|
80
|
+
{ key: 'borderColor', color: true }, { key: 'backColor', color: true }, { key: 'pointerColor', color: true },
|
|
81
|
+
];
|
|
82
|
+
export const PRESETS = [
|
|
83
|
+
{ name: 'Coverflow', description: 'The default: a tilted ring with a lifted centre.', patch: {} },
|
|
84
|
+
{ name: 'Flat row', description: 'A straight strip, no tilt, soft focus.', patch: { curve: 0, tilt: 0, depth: 0.3, spacing: 1.08, focusScale: 1.12, focusLift: 0.15, dim: 0.35, reflection: 0.3 } },
|
|
85
|
+
{ name: 'Wheel', description: 'A tight circle: the neighbours wrap away behind.', patch: { curve: 1, tilt: 0.2, depth: 2, spacing: 0.8, visible: 5, focusScale: 1.15, focusLift: 0.25, dim: 0.7 } },
|
|
86
|
+
{ name: 'Deck', description: 'Frames stacked close, heavy tilt, quick snap.', patch: { spacing: 0.45, tilt: 1.3, depth: 1.2, curve: 0.2, focusScale: 1.3, dim: 0.65, stiffness: 120, damping: 16 } },
|
|
87
|
+
];
|
|
88
|
+
function col(c) { return new THREE.Color(c); }
|
|
89
|
+
const smooth = (a, b, x) => { const t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); };
|
|
90
|
+
export function createUniforms() {
|
|
91
|
+
return {
|
|
92
|
+
uTex: { value: null },
|
|
93
|
+
uBorder: { value: 0.02 }, uBorderColor: { value: col('#f3e6cf') }, uBackColor: { value: col('#1a1d26') },
|
|
94
|
+
uPointerColor: { value: col('#ffd9a6') },
|
|
95
|
+
uIntensity: { value: 1 }, uOpacity: { value: 1 }, uReflection: { value: 0.45 }, uAspect: { value: 1.5 },
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function applyConfig(u, c) {
|
|
99
|
+
const set = (k, v) => { if (v === undefined)
|
|
100
|
+
return; if (u[k].value && u[k].value.isColor) {
|
|
101
|
+
if (v.isColor)
|
|
102
|
+
u[k].value.copy(v);
|
|
103
|
+
else
|
|
104
|
+
u[k].value.set(v);
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
u[k].value = v; };
|
|
108
|
+
set('uBorder', c.border);
|
|
109
|
+
set('uBorderColor', c.borderColor);
|
|
110
|
+
set('uBackColor', c.backColor);
|
|
111
|
+
set('uPointerColor', c.pointerColor);
|
|
112
|
+
set('uIntensity', c.intensity);
|
|
113
|
+
set('uOpacity', c.opacity);
|
|
114
|
+
set('uReflection', c.reflection);
|
|
115
|
+
}
|
|
116
|
+
const fragHead = /* glsl */ `
|
|
117
|
+
layout(location = 0) out highp vec4 pc_fragColor;
|
|
118
|
+
#define gl_FragColor pc_fragColor
|
|
119
|
+
`;
|
|
120
|
+
const vert = /* glsl */ `
|
|
121
|
+
attribute float aIdx;
|
|
122
|
+
attribute vec4 aState; // focus, alpha, hover, dim
|
|
123
|
+
varying vec2 vUv; varying float vLayer; varying vec4 vState; varying vec3 vN; varying vec3 vV; varying float vBack;
|
|
124
|
+
void main(){
|
|
125
|
+
vUv = uv; vLayer = aIdx; vState = aState;
|
|
126
|
+
vec4 wp = instanceMatrix * vec4(position, 1.0);
|
|
127
|
+
vec4 mv = modelViewMatrix * wp;
|
|
128
|
+
vN = normalize(normalMatrix * mat3(instanceMatrix) * vec3(0.0, 0.0, 1.0));
|
|
129
|
+
vV = -mv.xyz;
|
|
130
|
+
gl_Position = projectionMatrix * mv;
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
const frag = (reflect) => /* glsl */ `
|
|
134
|
+
${fragHead}
|
|
135
|
+
precision highp sampler2DArray;
|
|
136
|
+
uniform sampler2DArray uTex;
|
|
137
|
+
uniform float uBorder, uIntensity, uOpacity, uReflection, uAspect;
|
|
138
|
+
uniform vec3 uBorderColor, uBackColor, uPointerColor;
|
|
139
|
+
varying vec2 vUv; varying float vLayer; varying vec4 vState; varying vec3 vN; varying vec3 vV;
|
|
140
|
+
void main(){
|
|
141
|
+
float focus = vState.x, alpha = vState.y, hover = vState.z, dim = vState.w;
|
|
142
|
+
bool front = ${reflect ? '!gl_FrontFacing' : 'gl_FrontFacing'}; // the mirrored copy has its winding flipped
|
|
143
|
+
vec3 c = front ? texture(uTex, vec3(vUv, vLayer)).rgb : uBackColor;
|
|
144
|
+
// border: a thin frame, brighter on the focused / hovered one
|
|
145
|
+
vec2 e = min(vUv, 1.0 - vUv) * vec2(1.0, uAspect);
|
|
146
|
+
float dm = min(e.x, e.y);
|
|
147
|
+
float fw = fwidth(dm) * 1.5;
|
|
148
|
+
float border = 1.0 - smoothstep(uBorder, uBorder + fw, dm);
|
|
149
|
+
vec3 bc = mix(uBorderColor * (0.45 + 0.55 * focus), uPointerColor, hover * 0.8);
|
|
150
|
+
c = mix(c, bc, border);
|
|
151
|
+
// neighbours dim; a soft lambert on the yawed faces so the ring reads as 3d
|
|
152
|
+
vec3 N = normalize(vN); vec3 V = normalize(vV);
|
|
153
|
+
float lam = 0.78 + 0.22 * max(dot(N, V), 0.0);
|
|
154
|
+
c *= lam * (1.0 - dim) + hover * 0.1;
|
|
155
|
+
float a = alpha * uOpacity;
|
|
156
|
+
${reflect ? 'a *= uReflection * pow(1.0 - vUv.y, 1.6) * 0.8; c *= 0.85;' : ''}
|
|
157
|
+
if (a < 0.003) discard;
|
|
158
|
+
gl_FragColor = vec4(c * uIntensity * a, a);
|
|
159
|
+
#include <tonemapping_fragment>
|
|
160
|
+
#include <colorspace_fragment>
|
|
161
|
+
}
|
|
162
|
+
`;
|
|
163
|
+
// ---------------------------------------------------------------- images (shared with shards: cover-fit array texture)
|
|
164
|
+
export const TEX_W = 1024;
|
|
165
|
+
// ---------------------------------------------------------------- build
|
|
166
|
+
export function build(u, c) { return withLean(buildGallery(u, c), c); }
|
|
167
|
+
function buildGallery(u, c) {
|
|
168
|
+
const MAX = 32;
|
|
169
|
+
const fw = c.frameWidth, fh = c.frameWidth / c.aspect;
|
|
170
|
+
u.uAspect.value = c.aspect;
|
|
171
|
+
const geo = new THREE.PlaneGeometry(fw, fh);
|
|
172
|
+
const aIdx = new Float32Array(MAX);
|
|
173
|
+
for (let i = 0; i < MAX; i++)
|
|
174
|
+
aIdx[i] = i;
|
|
175
|
+
geo.setAttribute('aIdx', new THREE.InstancedBufferAttribute(aIdx, 1));
|
|
176
|
+
const state = new Float32Array(MAX * 4);
|
|
177
|
+
const aState = new THREE.InstancedBufferAttribute(state, 4);
|
|
178
|
+
aState.setUsage(THREE.DynamicDrawUsage);
|
|
179
|
+
geo.setAttribute('aState', aState);
|
|
180
|
+
const mat = new THREE.ShaderMaterial({ uniforms: u, vertexShader: vert, fragmentShader: frag(false), glslVersion: THREE.GLSL3, side: THREE.DoubleSide, transparent: true, depthWrite: true, premultipliedAlpha: true });
|
|
181
|
+
const rmat = new THREE.ShaderMaterial({ uniforms: u, vertexShader: vert, fragmentShader: frag(true), glslVersion: THREE.GLSL3, side: THREE.DoubleSide, transparent: true, depthWrite: false, premultipliedAlpha: true });
|
|
182
|
+
const frames = new THREE.InstancedMesh(geo, mat, MAX);
|
|
183
|
+
frames.count = 0;
|
|
184
|
+
frames.frustumCulled = false;
|
|
185
|
+
frames.userData.pick = 'frames';
|
|
186
|
+
const refl = new THREE.InstancedMesh(geo, rmat, MAX);
|
|
187
|
+
refl.count = 0;
|
|
188
|
+
refl.frustumCulled = false;
|
|
189
|
+
refl.raycast = () => { };
|
|
190
|
+
refl.renderOrder = -1;
|
|
191
|
+
const object = new THREE.Group();
|
|
192
|
+
object.add(refl, frames);
|
|
193
|
+
const st = {
|
|
194
|
+
count: 0, s: 0, v: 0, target: 0, dragging: false, dragS0: 0, dragX0: 0, lastDx: 0, focused: 0, focusT: 0,
|
|
195
|
+
time: 0, autoT: 0, hover: -1, hoverT: new Float32Array(MAX), pointer: null,
|
|
196
|
+
cfg: { ...c },
|
|
197
|
+
};
|
|
198
|
+
const M = new THREE.Matrix4(), P = new THREE.Vector3(), Q = new THREE.Quaternion(), S = new THREE.Vector3(), E = new THREE.Euler();
|
|
199
|
+
const floorY = -fh / 2 - c.floorGap;
|
|
200
|
+
const wrap = (d, n) => n > 1 ? ((d + n / 2) % n + n) % n - n / 2 : d;
|
|
201
|
+
function layout(dt) {
|
|
202
|
+
const k = st.cfg, n = st.count;
|
|
203
|
+
if (!n)
|
|
204
|
+
return;
|
|
205
|
+
const pitch = fw * k.spacing;
|
|
206
|
+
const gap = k.floorGap;
|
|
207
|
+
for (let i = 0; i < n; i++) {
|
|
208
|
+
const d = wrap(i - st.s, n);
|
|
209
|
+
const ad = Math.abs(d);
|
|
210
|
+
const w = smooth(0, 1.2, ad); // 0 at the centre, 1 past a neighbour
|
|
211
|
+
// arc: a flat row bent toward a circle of radius R = pitch * n / 2π
|
|
212
|
+
const R = Math.max(pitch * n / (2 * Math.PI), pitch * 1.5);
|
|
213
|
+
const a = (d * pitch) / R;
|
|
214
|
+
const x = (1 - k.curve) * d * pitch + k.curve * R * Math.sin(a);
|
|
215
|
+
const zArc = k.curve * (R * Math.cos(a) - R);
|
|
216
|
+
const z = zArc - k.depth * w * 0.9 * (1 - k.curve) - k.depth * ad * 0.12;
|
|
217
|
+
const focus = 1 - smooth(0, 0.9, ad);
|
|
218
|
+
// the focused frame comes forward and up
|
|
219
|
+
const lift = k.focusLift * focus + st.focusT * k.focusAmount * focus;
|
|
220
|
+
const yBreathe = k.breathe * 0.025 * Math.sin(st.time * 0.7 + i * 1.9);
|
|
221
|
+
let yaw = -Math.sign(d) * k.tilt * w - k.curve * a * 0.5;
|
|
222
|
+
let sc = 1 + (k.focusScale - 1) * focus + st.focusT * 0.15 * focus;
|
|
223
|
+
// pointer
|
|
224
|
+
const ht = st.hoverT[i];
|
|
225
|
+
if (st.pointer && k.pointerMode !== 'none') {
|
|
226
|
+
const dx = st.pointer.x - x, dy = st.pointer.y - 0;
|
|
227
|
+
const dist = Math.hypot(dx, dy);
|
|
228
|
+
const pw = (1 - smooth(0, k.pointerRadius, dist)) * k.pointerStrength;
|
|
229
|
+
if (k.pointerMode === 'tilt')
|
|
230
|
+
yaw += Math.atan2(dx, 2.5) * 0.35 * pw;
|
|
231
|
+
else
|
|
232
|
+
sc *= 1 + 0.08 * ht;
|
|
233
|
+
}
|
|
234
|
+
const ly = yBreathe + (k.pointerMode === 'lift' ? 0.12 * ht : 0);
|
|
235
|
+
P.set(x, ly, z + lift);
|
|
236
|
+
E.set(0, yaw, 0);
|
|
237
|
+
Q.setFromEuler(E);
|
|
238
|
+
S.set(sc, sc, 1);
|
|
239
|
+
M.compose(P, Q, S);
|
|
240
|
+
frames.setMatrixAt(i, M);
|
|
241
|
+
// reflection: mirror across the floor plane y = floorY - gap offset
|
|
242
|
+
const fy = -fh / 2 - gap;
|
|
243
|
+
P.set(x, 2 * fy - ly, z + lift);
|
|
244
|
+
S.set(sc, -sc, 1);
|
|
245
|
+
M.compose(P, Q, S);
|
|
246
|
+
refl.setMatrixAt(i, M);
|
|
247
|
+
const alpha = 1 - smooth(k.visible - 0.8, k.visible, ad);
|
|
248
|
+
state[i * 4] = focus;
|
|
249
|
+
state[i * 4 + 1] = alpha;
|
|
250
|
+
state[i * 4 + 2] = ht;
|
|
251
|
+
state[i * 4 + 3] = k.dim * w;
|
|
252
|
+
}
|
|
253
|
+
frames.count = n;
|
|
254
|
+
refl.count = n;
|
|
255
|
+
frames.instanceMatrix.needsUpdate = true;
|
|
256
|
+
refl.instanceMatrix.needsUpdate = true;
|
|
257
|
+
aState.needsUpdate = true;
|
|
258
|
+
}
|
|
259
|
+
const controls = {
|
|
260
|
+
next() { st.target = Math.round(st.target) + 1; st.focused = 0; st.autoT = 0; },
|
|
261
|
+
prev() { st.target = Math.round(st.target) - 1; st.focused = 0; st.autoT = 0; },
|
|
262
|
+
goTo(i) { const n = st.count; if (!n)
|
|
263
|
+
return; const cur = ((Math.round(st.s) % n) + n) % n; st.target = Math.round(st.s) + wrap(i - cur, n); st.focused = 0; st.autoT = 0; },
|
|
264
|
+
jump(i) { st.s = st.target = i; st.v = 0; },
|
|
265
|
+
focus(on) { st.focused = on === undefined ? 1 - st.focused : (on ? 1 : 0); },
|
|
266
|
+
get index() { const n = st.count; return n ? ((Math.round(st.s) % n) + n) % n : 0; },
|
|
267
|
+
get count() { return st.count; },
|
|
268
|
+
get busy() { return Math.abs(st.target - st.s) > 0.02 || Math.abs(st.v) > 0.05; },
|
|
269
|
+
setTexture(tex, count) { if (u.uTex.value)
|
|
270
|
+
u.uTex.value.dispose(); u.uTex.value = tex; st.count = Math.min(count, MAX); layout(0); },
|
|
271
|
+
/** drag in gallery x units: begin(x) / move(x) / end() — the release velocity throws, then it snaps */
|
|
272
|
+
dragBegin(x) { st.dragging = true; st.dragS0 = st.s; st.dragX0 = x; st.v = 0; st.lastDx = 0; },
|
|
273
|
+
dragMove(x) { if (!st.dragging)
|
|
274
|
+
return; const pitch = fw * st.cfg.spacing; const ns = st.dragS0 - (x - st.dragX0) / pitch; st.lastDx = ns - st.s; st.s = ns; },
|
|
275
|
+
dragEnd(dt) { if (!st.dragging)
|
|
276
|
+
return; st.dragging = false; st.v = st.lastDx / Math.max(dt, 1 / 120); st.target = Math.round(st.s + st.v * st.cfg.throwing); st.autoT = 0; },
|
|
277
|
+
get dragging() { return st.dragging; },
|
|
278
|
+
hover(i) { st.hover = i; },
|
|
279
|
+
};
|
|
280
|
+
object.userData.gallery = controls;
|
|
281
|
+
return {
|
|
282
|
+
object, materials: [mat, rmat], controls, frames,
|
|
283
|
+
apply(cfg) { Object.assign(st.cfg, cfg); applyConfig(u, cfg); },
|
|
284
|
+
update(dt, pointer) {
|
|
285
|
+
dt = Math.min(dt, 0.05);
|
|
286
|
+
st.time += dt;
|
|
287
|
+
st.pointer = pointer;
|
|
288
|
+
const k = st.cfg;
|
|
289
|
+
if (!st.dragging) {
|
|
290
|
+
// damped spring toward the target index (semi-implicit Euler, substepped)
|
|
291
|
+
const sub = 4, h = dt / sub;
|
|
292
|
+
for (let q = 0; q < sub; q++) {
|
|
293
|
+
const acc = k.stiffness * (st.target - st.s) - k.damping * st.v;
|
|
294
|
+
st.v += acc * h;
|
|
295
|
+
st.s += st.v * h;
|
|
296
|
+
}
|
|
297
|
+
if (Math.abs(st.target - st.s) < 1e-4 && Math.abs(st.v) < 1e-3) {
|
|
298
|
+
st.s = st.target;
|
|
299
|
+
st.v = 0;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (k.autoplay > 0 && st.count > 1 && !pointer && !st.dragging) {
|
|
303
|
+
st.autoT += dt;
|
|
304
|
+
if (st.autoT >= k.autoplay)
|
|
305
|
+
controls.next();
|
|
306
|
+
}
|
|
307
|
+
st.focusT += ((st.focused ? 1 : 0) - st.focusT) * (1 - Math.exp(-dt * 7));
|
|
308
|
+
for (let i = 0; i < st.count; i++)
|
|
309
|
+
st.hoverT[i] += ((st.hover === i ? 1 : 0) - st.hoverT[i]) * (1 - Math.exp(-dt * 9));
|
|
310
|
+
layout(dt);
|
|
311
|
+
},
|
|
312
|
+
dispose() { geo.dispose(); mat.dispose(); rmat.dispose(); if (u.uTex.value)
|
|
313
|
+
u.uTex.value.dispose(); },
|
|
314
|
+
};
|
|
315
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
export declare const catalog: {
|
|
3
|
+
key: string;
|
|
4
|
+
name: string;
|
|
5
|
+
camera: {
|
|
6
|
+
position: number[];
|
|
7
|
+
target: number[];
|
|
8
|
+
};
|
|
9
|
+
description: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULTS: {
|
|
13
|
+
type: string;
|
|
14
|
+
aspect: number;
|
|
15
|
+
width: number;
|
|
16
|
+
levels: number;
|
|
17
|
+
sparse: number;
|
|
18
|
+
lineWidth: number;
|
|
19
|
+
smoothing: number;
|
|
20
|
+
changeTime: number;
|
|
21
|
+
dim: number;
|
|
22
|
+
pointerMode: string;
|
|
23
|
+
pointerRadius: number;
|
|
24
|
+
lift: number;
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
lean: number;
|
|
27
|
+
imageUrls: any[];
|
|
28
|
+
autoplay: number;
|
|
29
|
+
intensity: number;
|
|
30
|
+
opacity: number;
|
|
31
|
+
layout: string;
|
|
32
|
+
spacing: number;
|
|
33
|
+
depth: number;
|
|
34
|
+
visible: number;
|
|
35
|
+
shape: number;
|
|
36
|
+
stiffness: number;
|
|
37
|
+
damping: number;
|
|
38
|
+
throwing: number;
|
|
39
|
+
wave: number;
|
|
40
|
+
slant: number;
|
|
41
|
+
pointerStrength: number;
|
|
42
|
+
};
|
|
43
|
+
export declare const STRUCTURAL: string[];
|
|
44
|
+
export declare const POINTER_MODES: string[];
|
|
45
|
+
export declare const GUI: ({
|
|
46
|
+
key: string;
|
|
47
|
+
options: string[];
|
|
48
|
+
tip: string;
|
|
49
|
+
min?: undefined;
|
|
50
|
+
max?: undefined;
|
|
51
|
+
step?: undefined;
|
|
52
|
+
} | {
|
|
53
|
+
key: string;
|
|
54
|
+
min: number;
|
|
55
|
+
max: number;
|
|
56
|
+
step: number;
|
|
57
|
+
} | {
|
|
58
|
+
key: string;
|
|
59
|
+
options: string[];
|
|
60
|
+
})[];
|
|
61
|
+
export declare const PRESETS: ({
|
|
62
|
+
name: string;
|
|
63
|
+
description: string;
|
|
64
|
+
patch: {
|
|
65
|
+
levels?: undefined;
|
|
66
|
+
sparse?: undefined;
|
|
67
|
+
lineWidth?: undefined;
|
|
68
|
+
smoothing?: undefined;
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
patch: {
|
|
74
|
+
levels: number;
|
|
75
|
+
sparse: number;
|
|
76
|
+
lineWidth: number;
|
|
77
|
+
smoothing: number;
|
|
78
|
+
};
|
|
79
|
+
})[];
|
|
80
|
+
export declare function createUniforms(): {
|
|
81
|
+
uLevels: {
|
|
82
|
+
value: number;
|
|
83
|
+
};
|
|
84
|
+
uSparse: {
|
|
85
|
+
value: number;
|
|
86
|
+
};
|
|
87
|
+
uLine: {
|
|
88
|
+
value: number;
|
|
89
|
+
};
|
|
90
|
+
uSmooth: {
|
|
91
|
+
value: number;
|
|
92
|
+
};
|
|
93
|
+
uLift: {
|
|
94
|
+
value: number;
|
|
95
|
+
};
|
|
96
|
+
uTex: {
|
|
97
|
+
value: any;
|
|
98
|
+
};
|
|
99
|
+
uS: {
|
|
100
|
+
value: number;
|
|
101
|
+
};
|
|
102
|
+
uCount: {
|
|
103
|
+
value: number;
|
|
104
|
+
};
|
|
105
|
+
uTime: {
|
|
106
|
+
value: number;
|
|
107
|
+
};
|
|
108
|
+
uAct: {
|
|
109
|
+
value: Float32Array<ArrayBuffer>;
|
|
110
|
+
};
|
|
111
|
+
uW: {
|
|
112
|
+
value: number;
|
|
113
|
+
};
|
|
114
|
+
uH: {
|
|
115
|
+
value: number;
|
|
116
|
+
};
|
|
117
|
+
uWave: {
|
|
118
|
+
value: number;
|
|
119
|
+
};
|
|
120
|
+
uSlant: {
|
|
121
|
+
value: number;
|
|
122
|
+
};
|
|
123
|
+
uDim: {
|
|
124
|
+
value: number;
|
|
125
|
+
};
|
|
126
|
+
uIntensity: {
|
|
127
|
+
value: number;
|
|
128
|
+
};
|
|
129
|
+
uOpacity: {
|
|
130
|
+
value: number;
|
|
131
|
+
};
|
|
132
|
+
uPointer: {
|
|
133
|
+
value: THREE.Vector3;
|
|
134
|
+
};
|
|
135
|
+
uPointerActive: {
|
|
136
|
+
value: number;
|
|
137
|
+
};
|
|
138
|
+
uPointerMode: {
|
|
139
|
+
value: number;
|
|
140
|
+
};
|
|
141
|
+
uPointerStrength: {
|
|
142
|
+
value: number;
|
|
143
|
+
};
|
|
144
|
+
uPointerRadius: {
|
|
145
|
+
value: number;
|
|
146
|
+
};
|
|
147
|
+
uPlace: {
|
|
148
|
+
value: THREE.Matrix4[];
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
export declare function applyConfig(u: any, c: any): void;
|
|
152
|
+
export declare function build(u: any, c: any): any;
|
|
153
|
+
//# sourceMappingURL=contourLines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contourLines.d.ts","sourceRoot":"","sources":["../../../../src/components/gallery/looks/contourLines.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,eAAO,MAAM,OAAO;;;;;;;;;CAEiE,CAAC;AAEtF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIpB,CAAC;AACF,eAAO,MAAM,UAAU,UAAmC,CAAC;AAC3D,eAAO,MAAM,aAAa,UAAW,CAAC;AACtC,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;IAQf,CAAC;AACF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;IAInB,CAAC;AACF,wBAAgB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA4J;AAC1L,wBAAgB,WAAW,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,QAAmL;AA2CnN,wBAAgB,KAAK,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,OAA6C"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// The approved lab module, verbatim but for its import paths and the lab's picture loader (Claude outputs/gallery-lab/
|
|
2
|
+
// contours.mjs). Plain JS-shaped code (the viewer compiles non-strict); typed at its one door, kit/GalleryVariant.tsx. Its own DEFAULTS only fill knobs the
|
|
3
|
+
// core defaults (DEFAULT_GALLERY_OBJECTS.contourLines) do not carry; its own autoplay is never used.
|
|
4
|
+
// contours — "Contour Lines". Every picture is drawn as the contour lines of its own brightness, like a
|
|
5
|
+
// topographic map of the image: level sets of a softened luminance field, anti-aliased with fwidth so every line
|
|
6
|
+
// is a clean hairline at any distance. An inactive picture shows only every fourth level, thin and grey. When it
|
|
7
|
+
// becomes the active one a soft wave crosses it: behind the wave the missing levels appear, every line thickens
|
|
8
|
+
// and takes the picture's colour, until the lines meet and close into the solid picture. Leaving runs it back.
|
|
9
|
+
// The cursor lifts the contours near it into a soft relief (the picture's own brightness as height). Self-coloured.
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
import { BASE_DEFAULTS, BASE_GUI_MOTION, BASE_GUI_TAIL, LAYOUT_GUI, baseUniforms, applyBase, baseGlsl, instanced, shaderMaterial, makeGallery, withLean, fragHead } from '../kit/lookBase.js';
|
|
12
|
+
export const catalog = { key: 'contourLines', name: 'Contour Lines', camera: { position: [0.3, 0.15, 4.6], target: [0, 0, 0] },
|
|
13
|
+
description: 'Pictures drawn as the contour lines of their own brightness, like a topographic map: inactive ones are a few thin grey lines, the active one fills in as a soft wave thickens the lines into the solid picture; the cursor lifts the contours into relief. Use for architecture, data and graphic showcases.',
|
|
14
|
+
tags: ['gallery', 'contours', 'lines', 'topographic', 'graphic', 'interactive'] };
|
|
15
|
+
export const DEFAULTS = {
|
|
16
|
+
...BASE_DEFAULTS, type: 'contourLines', aspect: 1.4, width: 2.2,
|
|
17
|
+
levels: 22, sparse: 3, lineWidth: 0.08, smoothing: 3.6, changeTime: 2.2, dim: 0.55,
|
|
18
|
+
pointerMode: 'lift', pointerRadius: 0.6, lift: 0.18,
|
|
19
|
+
};
|
|
20
|
+
export const STRUCTURAL = ['imageUrls', 'aspect', 'width'];
|
|
21
|
+
export const POINTER_MODES = ['lift'];
|
|
22
|
+
export const GUI = [
|
|
23
|
+
{ key: 'lean', min: 0, max: 3, step: 0.01, tip: 'The gallery turns toward the cursor' },
|
|
24
|
+
{ key: 'aspect', min: 0.6, max: 2.5, step: 0.01 }, { key: 'width', min: 1, max: 4, step: 0.01 },
|
|
25
|
+
...LAYOUT_GUI, ...BASE_GUI_MOTION,
|
|
26
|
+
{ key: 'levels', min: 6, max: 60, step: 1, tip: 'Contour levels over the full brightness range' }, { key: 'sparse', min: 1, max: 8, step: 1, tip: 'An inactive picture shows every n-th level' },
|
|
27
|
+
{ key: 'lineWidth', min: 0.02, max: 0.4, step: 0.005, tip: 'Width of an inactive line, as a share of the level spacing' },
|
|
28
|
+
{ key: 'smoothing', min: 0, max: 5, step: 0.1, tip: 'How much the brightness is smoothed before the contours are drawn' },
|
|
29
|
+
{ key: 'pointerMode', options: ['none', ...POINTER_MODES] }, ...BASE_GUI_TAIL, { key: 'lift', min: 0, max: 0.6, step: 0.01, tip: 'Height of the cursor’s relief' },
|
|
30
|
+
];
|
|
31
|
+
export const PRESETS = [
|
|
32
|
+
{ name: 'Contours', description: 'The default.', patch: {} },
|
|
33
|
+
{ name: 'Survey', description: 'Many fine levels.', patch: { levels: 48, sparse: 6, lineWidth: 0.05, smoothing: 1.5 } },
|
|
34
|
+
{ name: 'Bold', description: 'Few broad bands.', patch: { levels: 12, sparse: 2, lineWidth: 0.16, smoothing: 3.2 } },
|
|
35
|
+
];
|
|
36
|
+
export function createUniforms() { return { ...baseUniforms(), uLevels: { value: 28 }, uSparse: { value: 4 }, uLine: { value: 0.09 }, uSmooth: { value: 2.2 }, uLift: { value: 0.18 } }; }
|
|
37
|
+
export function applyConfig(u, c) { const set = applyBase(u, c, POINTER_MODES); set('uLevels', c.levels); set('uSparse', c.sparse); set('uLine', c.lineWidth); set('uSmooth', c.smoothing); set('uLift', c.lift); }
|
|
38
|
+
const vert = /* glsl */ `
|
|
39
|
+
precision highp sampler2DArray;
|
|
40
|
+
uniform sampler2DArray uTex;
|
|
41
|
+
attribute vec4 aI;
|
|
42
|
+
${baseGlsl}
|
|
43
|
+
uniform float uLift, uSmooth;
|
|
44
|
+
varying vec2 vUv; varying float vImg; varying float vAct; varying float vAlpha;
|
|
45
|
+
void main(){
|
|
46
|
+
float img = aI.x; vec2 g = position.xy + 0.5;
|
|
47
|
+
vec2 p = vec2(position.x * uW, position.y * uH);
|
|
48
|
+
float L = lumOf(textureLod(uTex, vec3(g, img), uSmooth + 1.0).rgb);
|
|
49
|
+
float z = uLift * L * maskAt(p);
|
|
50
|
+
vUv = g; vImg = img; vAct = actOf(img); vAlpha = fadeAt(img);
|
|
51
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(placeAt(img, vec3(p, z)), 1.0);
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
const frag = /* glsl */ `
|
|
55
|
+
${fragHead}
|
|
56
|
+
precision highp sampler2DArray;
|
|
57
|
+
uniform sampler2DArray uTex;
|
|
58
|
+
${baseGlsl}
|
|
59
|
+
uniform float uLevels, uSparse, uLine, uSmooth;
|
|
60
|
+
varying vec2 vUv; varying float vImg; varying float vAct; varying float vAlpha;
|
|
61
|
+
void main(){
|
|
62
|
+
vec3 pic = texture(uTex, vec3(vUv, vImg)).rgb;
|
|
63
|
+
float L = lumOf(textureLod(uTex, vec3(vUv, vImg), uSmooth).rgb);
|
|
64
|
+
float s = waveAt(vAct, vUv);
|
|
65
|
+
float f = L * uLevels, idx = floor(f + 0.5);
|
|
66
|
+
float dist = abs(f - idx); // 0 on a level, 0.5 half-way between two
|
|
67
|
+
float px = max(fwidth(f), 1e-4);
|
|
68
|
+
float keep = mix(step(mod(idx, uSparse), 0.5), 1.0, smoothstep(0.0, 0.5, s));
|
|
69
|
+
float width = mix(uLine, 0.56, s * s); // the lines meet (0.5) and close the picture
|
|
70
|
+
float line = 1.0 - smoothstep(width - px, width + px, dist);
|
|
71
|
+
vec3 c = mix(fadedOf(pic) * 1.4, pic, s);
|
|
72
|
+
float a = line * keep * vAlpha * uOpacity;
|
|
73
|
+
if (a < 0.003) discard;
|
|
74
|
+
gl_FragColor = vec4(c * uIntensity * a, a);
|
|
75
|
+
#include <tonemapping_fragment>
|
|
76
|
+
#include <colorspace_fragment>
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
export function build(u, c) { return withLean(buildGallery(u, c), c); }
|
|
80
|
+
function buildGallery(u, c) {
|
|
81
|
+
const W = c.width, H = W / c.aspect;
|
|
82
|
+
const geo = instanced(new THREE.PlaneGeometry(1, 1, 64, 44), 1, () => [0, 0]);
|
|
83
|
+
const mat = shaderMaterial(u, vert, frag);
|
|
84
|
+
const mesh = new THREE.Mesh(geo, mat);
|
|
85
|
+
mesh.frustumCulled = false;
|
|
86
|
+
mesh.raycast = () => { };
|
|
87
|
+
const g = makeGallery(u, c, { W, H, meshes: [mesh], setCount: (n) => { geo.instanceCount = n; } });
|
|
88
|
+
const apply = g.apply;
|
|
89
|
+
g.apply = (k) => { apply(k); applyConfig(u, k); };
|
|
90
|
+
return g;
|
|
91
|
+
}
|