@3driseai/3drise-viewer 0.1.40 → 0.1.42
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.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +9 -5
- package/dist/animationsV2/clipUtils.d.ts +9 -0
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +11 -2
- package/dist/animationsV2/normalize.d.ts.map +1 -1
- package/dist/animationsV2/normalize.js +2 -0
- package/dist/animationsV2/types.d.ts +4 -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/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 +11 -5
- 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.map +1 -1
- package/dist/constants.js +2 -0
- 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/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/UiLayers.d.ts +17 -1
- package/dist/ui/UiLayers.d.ts.map +1 -1
- package/dist/ui/UiLayers.js +76 -3
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// The approved lab module, verbatim but for its import paths and the lab's picture loader (Claude outputs/gallery-lab/
|
|
2
|
+
// shift.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.particleShift) do not carry; its own autoplay is never used.
|
|
4
|
+
// shift — "Particle Shift". An inactive picture is a grey halftone on its own surface (one dot per cell, sized by
|
|
5
|
+
// the picture's brightness, anti-aliased, foreshortening with the surface), so it reads clearly from any angle. When a picture becomes the
|
|
6
|
+
// active one a small soft wave moves across it; where the wave passes, the particles rise very slightly off the
|
|
7
|
+
// surface, swell, take their colour and settle back fused into the solid picture. Leaving runs the wave back.
|
|
8
|
+
//
|
|
9
|
+
// One quantity drives it all, per particle: s = wave(act, place) × (1 − cursor mask). act is the picture's own
|
|
10
|
+
// active value (0 → 1 at a constant rate, so the change never jumps and reverses cleanly half-way); the wave turns
|
|
11
|
+
// it into a soft front crossing the picture; the cursor mask turns the area under the cursor (pointerRadius) of an
|
|
12
|
+
// active picture back toward its particle state, with the same soft edge. Self-coloured: no lighting of its own.
|
|
13
|
+
import * as THREE from 'three';
|
|
14
|
+
import { fragHead, mulberry32, createScroll, focusAt, approach, withLean } from '../kit/galleryKit.js';
|
|
15
|
+
import { createLayout, layoutUniforms, fillLayout, layoutGlsl, LAYOUT_GUI } from '../kit/galleryKit.js';
|
|
16
|
+
export const catalog = { key: 'particleShift', name: 'Particle Shift', camera: { position: [0.2, 0.15, 4.8], target: [0, 0, 0] },
|
|
17
|
+
description: 'Pictures made of particles: inactive ones are a crisp grey halftone; on the active one a small soft wave crosses the picture, its particles rising slightly, swelling and fusing into the solid picture in full colour; the cursor turns the area it passes back into particles. Use for art, tech and dreamy showcases.',
|
|
18
|
+
tags: ['gallery', 'particles', 'stipple', 'transform', 'dissolve', 'navigation', 'interactive'] };
|
|
19
|
+
export const DEFAULTS = {
|
|
20
|
+
type: 'particleShift', enabled: true, lean: 1, imageUrls: [], autoplay: 0, intensity: 1, opacity: 1,
|
|
21
|
+
aspect: 1.4, width: 2.2, grains: 150, // structural: particles across
|
|
22
|
+
layout: 'row', spacing: 1.35, depth: 1.0, visible: 2.4, shape: 1,
|
|
23
|
+
stiffness: 22, damping: 8, throwing: 0.1,
|
|
24
|
+
changeTime: 1.8, wave: 0.3, slant: 0.3, lift: 0.05,
|
|
25
|
+
particleSize: 0.5, faded: 0.35, grain: 1.0,
|
|
26
|
+
pointerMode: 'shift', pointerStrength: 1, pointerRadius: 0.45,
|
|
27
|
+
};
|
|
28
|
+
export const STRUCTURAL = ['imageUrls', 'aspect', 'width', 'grains'];
|
|
29
|
+
export const POINTER_MODES = ['shift'];
|
|
30
|
+
export const GUI = [
|
|
31
|
+
{ key: 'lean', min: 0, max: 3, step: 0.01, tip: 'The gallery turns toward the cursor' },
|
|
32
|
+
{ key: 'aspect', min: 0.6, max: 2.5, step: 0.01 }, { key: 'width', min: 1, max: 4, step: 0.01 }, { key: 'grains', min: 60, max: 260, step: 2 },
|
|
33
|
+
...LAYOUT_GUI,
|
|
34
|
+
{ key: 'stiffness', min: 5, max: 120, step: 1 }, { key: 'damping', min: 2, max: 30, step: 0.1 },
|
|
35
|
+
{ key: 'changeTime', min: 0.6, max: 6, step: 0.1 }, { key: 'wave', min: 0.05, max: 1, step: 0.01, tip: 'Width of the soft wave' }, { key: 'slant', min: 0, max: 1, step: 0.01, tip: 'How diagonal the wave is' }, { key: 'lift', min: 0, max: 0.3, step: 0.005, tip: 'How far the particles rise as the wave passes' },
|
|
36
|
+
{ key: 'particleSize', min: 0.1, max: 1, step: 0.01, tip: 'Size of the halftone dots of the waiting pictures' }, { key: 'faded', min: 0, max: 1, step: 0.01, tip: 'Brightness of the waiting pictures' }, { key: 'grain', min: 0.4, max: 2.5, step: 0.01 },
|
|
37
|
+
{ key: 'autoplay', min: 0, max: 20, step: 0.5 },
|
|
38
|
+
{ key: 'pointerMode', options: ['none', ...POINTER_MODES] }, { key: 'pointerStrength', min: 0, max: 1, step: 0.01 }, { key: 'pointerRadius', min: 0.1, max: 2, step: 0.01, tip: 'Radius of the area the cursor turns back into particles' },
|
|
39
|
+
{ key: 'intensity', min: 0, max: 3, step: 0.01 }, { key: 'opacity', min: 0, max: 1, step: 0.01 },
|
|
40
|
+
];
|
|
41
|
+
export const PRESETS = [
|
|
42
|
+
{ name: 'Shift', description: 'The default.', patch: {} },
|
|
43
|
+
{ name: 'Breath', description: 'A wide, very soft wave; the particles barely rise.', patch: { wave: 0.7, lift: 0.02, changeTime: 2.4 } },
|
|
44
|
+
{ name: 'Fine', description: 'Fine particles at rest, a narrow straight wave.', patch: { particleSize: 0.36, grains: 200, wave: 0.18, slant: 0 } },
|
|
45
|
+
];
|
|
46
|
+
const MAXI = 32;
|
|
47
|
+
export function createUniforms() {
|
|
48
|
+
return {
|
|
49
|
+
...layoutUniforms(), uTex: { value: null }, uS: { value: 0 }, uCount: { value: 1 }, uTime: { value: 0 },
|
|
50
|
+
uAct: { value: new Float32Array(MAXI).fill(0) },
|
|
51
|
+
uSpacing: { value: 1.35 }, uDepth: { value: 1 }, uVisible: { value: 2.4 },
|
|
52
|
+
uWave: { value: 0.3 }, uSlant: { value: 0.3 }, uLift: { value: 0.05 }, uSize: { value: 0.5 }, uFaded: { value: 0.35 }, uGrain: { value: 1 },
|
|
53
|
+
uIntensity: { value: 1 }, uOpacity: { value: 1 },
|
|
54
|
+
uW: { value: 2.2 }, uH: { value: 1.57 }, uGx: { value: 150 }, uGy: { value: 107 }, uDpr: { value: 1 }, uVh: { value: 560 },
|
|
55
|
+
uPointer: { value: new THREE.Vector3() }, uPointerActive: { value: 0 }, uPointerMode: { value: 0 }, uPointerStrength: { value: 1 }, uPointerRadius: { value: 0.45 },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function applyConfig(u, c) {
|
|
59
|
+
const set = (k, v) => { if (v !== undefined)
|
|
60
|
+
u[k].value = v; };
|
|
61
|
+
set('uSpacing', c.spacing);
|
|
62
|
+
set('uDepth', c.depth);
|
|
63
|
+
set('uVisible', c.visible);
|
|
64
|
+
set('uWave', c.wave);
|
|
65
|
+
set('uSlant', c.slant);
|
|
66
|
+
set('uLift', c.lift);
|
|
67
|
+
set('uSize', c.particleSize);
|
|
68
|
+
set('uFaded', c.faded);
|
|
69
|
+
set('uGrain', c.grain);
|
|
70
|
+
set('uIntensity', c.intensity);
|
|
71
|
+
set('uOpacity', c.opacity);
|
|
72
|
+
set('uPointerStrength', c.pointerStrength);
|
|
73
|
+
set('uPointerRadius', c.pointerRadius);
|
|
74
|
+
if (c.pointerMode !== undefined)
|
|
75
|
+
u.uPointerMode.value = POINTER_MODES.indexOf(c.pointerMode);
|
|
76
|
+
}
|
|
77
|
+
const common = /* glsl */ `
|
|
78
|
+
uniform float uS, uCount, uTime, uSpacing, uDepth, uVisible, uW, uH, uWave, uSlant;
|
|
79
|
+
uniform float uAct[${MAXI}];
|
|
80
|
+
uniform vec3 uPointer; uniform float uPointerActive, uPointerMode, uPointerStrength, uPointerRadius;
|
|
81
|
+
${layoutGlsl}
|
|
82
|
+
float wrapd(float d, float n){ return n > 1.0 ? mod(d + n * 0.5, n) - n * 0.5 : d; }
|
|
83
|
+
// the wave: a soft front crossing the picture from the left (slightly diagonal); 1 behind it, 0 ahead of it
|
|
84
|
+
float waveAt(float act, vec2 g){
|
|
85
|
+
float pos = mix(g.x, 1.0 - g.y, uSlant * 0.5);
|
|
86
|
+
float front = act * (1.0 + uWave) - uWave * 0.5;
|
|
87
|
+
float w = smoothstep(front + uWave * 0.5, front - uWave * 0.5, pos);
|
|
88
|
+
return w * w * (3.0 - 2.0 * w);
|
|
89
|
+
}
|
|
90
|
+
// the cursor's area turns back into particles (soft edge)
|
|
91
|
+
float maskAt(vec2 p){ if (uPointerMode < -0.5) return 0.0; float d = length(p - uPointer.xy); return uPointerActive * uPointerStrength * (1.0 - smoothstep(uPointerRadius * 0.45, uPointerRadius, d)); }
|
|
92
|
+
vec3 plateAt(float img, vec2 g, out float focus, out float act){
|
|
93
|
+
float d = wrapd(img - uS, uCount); focus = 1.0 - smoothstep(0.0, 1.0, abs(d));
|
|
94
|
+
act = uAct[int(img + 0.5)];
|
|
95
|
+
return placeAt(img, vec3((g.x - 0.5) * uW, (g.y - 0.5) * uH, 0.0));
|
|
96
|
+
}
|
|
97
|
+
float alphaAt(float img){ return fadeAt(img); }
|
|
98
|
+
`;
|
|
99
|
+
// ---- the solid picture: shown only where s is near 1 (an active, settled picture outside the cursor's area)
|
|
100
|
+
const plateVert = /* glsl */ `
|
|
101
|
+
attribute float aImg;
|
|
102
|
+
${common}
|
|
103
|
+
varying vec2 vUv; varying float vImg; varying float vAct; varying float vAlpha; varying vec2 vP;
|
|
104
|
+
void main(){
|
|
105
|
+
float focus, act; vec3 p = plateAt(aImg, uv, focus, act);
|
|
106
|
+
vUv = uv; vImg = aImg; vAct = act; vAlpha = alphaAt(aImg); vP = p.xy;
|
|
107
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
const plateFrag = /* glsl */ `
|
|
111
|
+
${fragHead}
|
|
112
|
+
precision highp sampler2DArray;
|
|
113
|
+
${common}
|
|
114
|
+
uniform sampler2DArray uTex; uniform float uIntensity, uOpacity, uSize, uFaded, uGx, uGy;
|
|
115
|
+
varying vec2 vUv; varying float vImg; varying float vAct; varying float vAlpha; varying vec2 vP;
|
|
116
|
+
void main(){
|
|
117
|
+
float mk = maskAt(vP);
|
|
118
|
+
float s = waveAt(vAct, vUv) * (1.0 - mk);
|
|
119
|
+
vec3 pic = texture(uTex, vec3(vUv, vImg)).rgb;
|
|
120
|
+
// the settled picture
|
|
121
|
+
float solid = smoothstep(0.55, 0.95, s);
|
|
122
|
+
// the waiting picture: a halftone on the picture's own surface — one dot per cell, its size set by the
|
|
123
|
+
// brightness there, so the picture reads clearly in grey and the dots foreshorten with the surface at any angle
|
|
124
|
+
vec2 c = vUv * vec2(uGx, uGy);
|
|
125
|
+
vec2 cellUv = (floor(c) + 0.5) / vec2(uGx, uGy);
|
|
126
|
+
float L = dot(textureLod(uTex, vec3(cellUv, vImg), 1.5).rgb, vec3(0.299, 0.587, 0.114));
|
|
127
|
+
float r = 0.5 * mix(0.35, 1.0, uSize) * sqrt(mix(0.06, 1.0, L)); // dot radius, in cells
|
|
128
|
+
float d = length(fract(c) - 0.5);
|
|
129
|
+
float aa = max(length(fwidth(c)) * 0.7, 1e-4); // one pixel, in cells
|
|
130
|
+
float dotA = 1.0 - smoothstep(r - aa, r + aa, d);
|
|
131
|
+
// cells smaller than a pixel: the dots blend into their average coverage instead of shimmering
|
|
132
|
+
dotA = mix(dotA, min(3.1416 * r * r, 1.0), smoothstep(0.35, 0.9, aa));
|
|
133
|
+
// it stays under the wave until the settled picture takes over (no gap between the two), dimmed while the
|
|
134
|
+
// particles lift off it
|
|
135
|
+
float hdot = dotA * (1.0 - 0.5 * smoothstep(0.05, 0.4, s));
|
|
136
|
+
// grey on a waiting picture; under the cursor on the active one the halftone keeps the picture's colour
|
|
137
|
+
vec3 grey = mix(vec3(0.35 + 0.65 * L) * uFaded, textureLod(uTex, vec3(cellUv, vImg), 1.5).rgb, vAct * mk);
|
|
138
|
+
float a = (solid + (1.0 - solid) * hdot) * vAlpha * uOpacity;
|
|
139
|
+
if (a < 0.003) discard;
|
|
140
|
+
vec3 col = (pic * solid + grey * (1.0 - solid) * hdot) / max(solid + (1.0 - solid) * hdot, 1e-4);
|
|
141
|
+
gl_FragColor = vec4(col * uIntensity * a, a);
|
|
142
|
+
#include <tonemapping_fragment>
|
|
143
|
+
#include <colorspace_fragment>
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
146
|
+
// ---- the particles: always there below s = 1 — small and grey at 0, swelling, drifting and colouring as s rises
|
|
147
|
+
const grainVert = /* glsl */ `
|
|
148
|
+
attribute vec4 aG; // image, u, v, hash
|
|
149
|
+
${common}
|
|
150
|
+
uniform float uLift, uSize, uFaded, uGrain, uGx, uGy, uDpr, uVh;
|
|
151
|
+
varying vec2 vUv; varying float vImg; varying float vS; varying float vAlpha;
|
|
152
|
+
void main(){
|
|
153
|
+
float img = aG.x, h = aG.w;
|
|
154
|
+
// each particle jittered inside its own cell: no regular grid, so no moiré when the picture is seen at an angle
|
|
155
|
+
vec2 g = aG.yz + (vec2(h, fract(h * 97.131)) - 0.5) * 0.8 / vec2(uGx, uGy);
|
|
156
|
+
float focus, act; vec3 plate = plateAt(img, g, focus, act);
|
|
157
|
+
float s = waveAt(act, g) * (1.0 - maskAt(plate.xy));
|
|
158
|
+
// the crest of the wave: the particles rise a little off the surface and settle back (0 before and after)
|
|
159
|
+
float crest = 4.0 * s * (1.0 - s);
|
|
160
|
+
// (the rise is along the picture's own normal, whatever the layout turns it to)
|
|
161
|
+
vec3 p = placeAt(img, vec3((g.x - 0.5) * uW, (g.y - 0.5) * uH, uLift * crest * (0.8 + 0.4 * h) + 0.004 * sin(uTime * 0.9 + h * 40.0) * (1.0 - s)));
|
|
162
|
+
vUv = g; vImg = img; vS = s; vAlpha = alphaAt(img);
|
|
163
|
+
vec4 mv = modelViewMatrix * vec4(p, 1.0);
|
|
164
|
+
gl_Position = projectionMatrix * mv;
|
|
165
|
+
float size = mix(uSize, 1.0, smoothstep(0.0, 0.8, s)) * (1.0 + 0.15 * crest);
|
|
166
|
+
// a point sprite always faces the camera, but the picture does not: seen at an angle the same particles crowd
|
|
167
|
+
// into less screen area. Shrink each sprite's area by how much the picture faces the camera, so the stipple
|
|
168
|
+
// keeps its density at any angle
|
|
169
|
+
vec3 o = placeAt(img, vec3(0.0)), nz = placeAt(img, vec3(0.0, 0.0, 1.0)) - o;
|
|
170
|
+
float facing = abs(dot(normalize((modelViewMatrix * vec4(nz, 0.0)).xyz), normalize(-mv.xyz)));
|
|
171
|
+
float px = uGrain * (uW / uGx) * 3.0 * uVh * 0.5 / max(-mv.z, 0.1) * uDpr * size * sqrt(max(facing, 0.05));
|
|
172
|
+
// never below 1 px (a smaller sprite still rasterises as one pixel and flickers): it fades instead
|
|
173
|
+
float pxC = max(px, 1.0);
|
|
174
|
+
vAlpha *= px / pxC;
|
|
175
|
+
gl_PointSize = pxC;
|
|
176
|
+
}
|
|
177
|
+
`;
|
|
178
|
+
const grainFrag = /* glsl */ `
|
|
179
|
+
${fragHead}
|
|
180
|
+
precision highp sampler2DArray;
|
|
181
|
+
uniform sampler2DArray uTex; uniform float uFaded, uIntensity, uOpacity;
|
|
182
|
+
varying vec2 vUv; varying float vImg; varying float vS; varying float vAlpha;
|
|
183
|
+
void main(){
|
|
184
|
+
vec2 q = gl_PointCoord - 0.5; float r2 = dot(q, q); if (r2 > 0.25) discard;
|
|
185
|
+
float soft = 1.0 - smoothstep(0.05, 0.25, r2);
|
|
186
|
+
vec3 pic = texture(uTex, vec3(vUv, vImg)).rgb;
|
|
187
|
+
float lum = dot(pic, vec3(0.299, 0.587, 0.114));
|
|
188
|
+
float colour = smoothstep(0.1, 0.8, vS);
|
|
189
|
+
vec3 c = mix(vec3(0.18 + 0.82 * lum) * uFaded, pic, colour);
|
|
190
|
+
// the particles hand over to the solid picture as they settle; faint at rest, fuller as they colour
|
|
191
|
+
// swollen particles overlap: thin them as they grow so the wave's crest never flares
|
|
192
|
+
// (they cross-fade with the solid picture so the sum stays even — no bright band on the wave)
|
|
193
|
+
float a = soft * vAlpha * uOpacity * smoothstep(0.02, 0.25, vS) * (1.0 - smoothstep(0.55, 0.95, vS)) * mix(0.75, 0.9, colour);
|
|
194
|
+
if (a < 0.003) discard;
|
|
195
|
+
gl_FragColor = vec4(c * uIntensity * a, a);
|
|
196
|
+
#include <tonemapping_fragment>
|
|
197
|
+
#include <colorspace_fragment>
|
|
198
|
+
}
|
|
199
|
+
`;
|
|
200
|
+
export function build(u, c) { return withLean(buildGallery(u, c), c); }
|
|
201
|
+
function buildGallery(u, c) {
|
|
202
|
+
const W = c.width, H = W / c.aspect, gx = Math.max(20, c.grains | 0), gy = Math.max(12, Math.round(gx / c.aspect)), per = gx * gy;
|
|
203
|
+
u.uW.value = W;
|
|
204
|
+
u.uH.value = H;
|
|
205
|
+
u.uGx.value = gx;
|
|
206
|
+
u.uGy.value = gy;
|
|
207
|
+
const rnd = mulberry32(9);
|
|
208
|
+
const quad = new THREE.PlaneGeometry(1, 1, 24, 16);
|
|
209
|
+
const pgeo = new THREE.InstancedBufferGeometry();
|
|
210
|
+
pgeo.index = quad.index;
|
|
211
|
+
pgeo.attributes.position = quad.attributes.position;
|
|
212
|
+
pgeo.attributes.uv = quad.attributes.uv;
|
|
213
|
+
const pi = new Float32Array(MAXI);
|
|
214
|
+
for (let i = 0; i < MAXI; i++)
|
|
215
|
+
pi[i] = i;
|
|
216
|
+
pgeo.setAttribute('aImg', new THREE.InstancedBufferAttribute(pi, 1));
|
|
217
|
+
pgeo.instanceCount = 0;
|
|
218
|
+
pgeo.boundingSphere = new THREE.Sphere(new THREE.Vector3(), 30);
|
|
219
|
+
const pmat = new THREE.ShaderMaterial({ uniforms: u, vertexShader: plateVert, fragmentShader: plateFrag, glslVersion: THREE.GLSL3, side: THREE.DoubleSide, transparent: true, depthWrite: true, premultipliedAlpha: true });
|
|
220
|
+
const plates = new THREE.Mesh(pgeo, pmat);
|
|
221
|
+
plates.frustumCulled = false;
|
|
222
|
+
plates.raycast = () => { };
|
|
223
|
+
const geo = new THREE.BufferGeometry();
|
|
224
|
+
const a = new Float32Array(MAXI * per * 4);
|
|
225
|
+
for (let i = 0; i < MAXI; i++)
|
|
226
|
+
for (let j = 0; j < gy; j++)
|
|
227
|
+
for (let k = 0; k < gx; k++)
|
|
228
|
+
a.set([i, (k + 0.5) / gx, (j + 0.5) / gy, rnd()], ((i * gy + j) * gx + k) * 4);
|
|
229
|
+
geo.setAttribute('aG', new THREE.BufferAttribute(a, 4));
|
|
230
|
+
geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(MAXI * per * 3), 3));
|
|
231
|
+
geo.setDrawRange(0, 0);
|
|
232
|
+
geo.boundingSphere = new THREE.Sphere(new THREE.Vector3(), 30);
|
|
233
|
+
const gmat = new THREE.ShaderMaterial({ uniforms: u, vertexShader: grainVert, fragmentShader: grainFrag, glslVersion: THREE.GLSL3, transparent: true, depthWrite: false, premultipliedAlpha: true });
|
|
234
|
+
const points = new THREE.Points(geo, gmat);
|
|
235
|
+
points.frustumCulled = false;
|
|
236
|
+
points.raycast = () => { };
|
|
237
|
+
points.renderOrder = 1;
|
|
238
|
+
const pick = new THREE.Mesh(new THREE.PlaneGeometry(W, H), new THREE.MeshBasicMaterial({ visible: false }));
|
|
239
|
+
const object = new THREE.Group();
|
|
240
|
+
object.add(plates, points, pick);
|
|
241
|
+
const cfg = { ...c };
|
|
242
|
+
const scroll = createScroll(cfg, () => { });
|
|
243
|
+
scroll.st.pitch = W * c.spacing;
|
|
244
|
+
const layout = createLayout(W, H);
|
|
245
|
+
const st = { time: 0 };
|
|
246
|
+
const act = u.uAct.value;
|
|
247
|
+
const _inv = new THREE.Matrix4(), _p = new THREE.Vector3();
|
|
248
|
+
const controls = Object.assign(scroll.controls, {
|
|
249
|
+
setTexture(tex, count) { if (u.uTex.value)
|
|
250
|
+
u.uTex.value.dispose(); u.uTex.value = tex; scroll.st.count = Math.min(count, MAXI); u.uCount.value = scroll.st.count; pgeo.instanceCount = scroll.st.count; geo.setDrawRange(0, scroll.st.count * per); act.fill(0); act[controls.index] = 1; },
|
|
251
|
+
});
|
|
252
|
+
object.userData.gallery = controls;
|
|
253
|
+
return {
|
|
254
|
+
object, controls, pickMesh: pick, materials: [pmat, gmat],
|
|
255
|
+
apply(k) { Object.assign(cfg, k); applyConfig(u, k); scroll.st.pitch = W * cfg.spacing; },
|
|
256
|
+
update(dt, pointer, state) {
|
|
257
|
+
dt = Math.min(dt, 0.05);
|
|
258
|
+
st.time += dt;
|
|
259
|
+
u.uTime.value = st.time;
|
|
260
|
+
if (state) {
|
|
261
|
+
u.uDpr.value = state.dpr;
|
|
262
|
+
u.uVh.value = state.h;
|
|
263
|
+
}
|
|
264
|
+
scroll.step(dt, pointer);
|
|
265
|
+
u.uS.value = scroll.st.s;
|
|
266
|
+
const n = scroll.st.count;
|
|
267
|
+
fillLayout(layout, u, scroll.st.s, n, cfg);
|
|
268
|
+
for (let i = 0; i < n; i++)
|
|
269
|
+
act[i] = approach(act[i], focusAt(i, scroll.st.s, n) > 0.5 ? 1 : 0, dt, cfg.changeTime);
|
|
270
|
+
// the cursor in the gallery's own frame (the lean turns the gallery; the mask must turn with it)
|
|
271
|
+
if (pointer) {
|
|
272
|
+
plates.parent.updateMatrix();
|
|
273
|
+
_inv.copy(plates.parent.matrix).invert(); /* the cursor arrives in the gallery's own frame; undo the lean */
|
|
274
|
+
_p.set(pointer.x, pointer.y, 0).applyMatrix4(_inv);
|
|
275
|
+
u.uPointer.value.set(_p.x, _p.y, 0);
|
|
276
|
+
}
|
|
277
|
+
u.uPointerActive.value += ((pointer ? 1 : 0) - u.uPointerActive.value) * (1 - Math.exp(-dt * 5));
|
|
278
|
+
},
|
|
279
|
+
dispose() { geo.dispose(); pgeo.dispose(); quad.dispose(); pmat.dispose(); gmat.dispose(); pick.geometry.dispose(); if (u.uTex.value)
|
|
280
|
+
u.uTex.value.dispose(); },
|
|
281
|
+
};
|
|
282
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
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
|
+
pins: number;
|
|
17
|
+
relief: number;
|
|
18
|
+
pinSize: number;
|
|
19
|
+
base: number;
|
|
20
|
+
roughness: number;
|
|
21
|
+
metalness: number;
|
|
22
|
+
boardColor: string;
|
|
23
|
+
changeTime: number;
|
|
24
|
+
dim: number;
|
|
25
|
+
pointerMode: string;
|
|
26
|
+
pointerRadius: number;
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
lean: number;
|
|
29
|
+
imageUrls: any[];
|
|
30
|
+
autoplay: number;
|
|
31
|
+
intensity: number;
|
|
32
|
+
opacity: number;
|
|
33
|
+
layout: string;
|
|
34
|
+
spacing: number;
|
|
35
|
+
depth: number;
|
|
36
|
+
visible: number;
|
|
37
|
+
shape: number;
|
|
38
|
+
stiffness: number;
|
|
39
|
+
damping: number;
|
|
40
|
+
throwing: number;
|
|
41
|
+
wave: number;
|
|
42
|
+
slant: number;
|
|
43
|
+
pointerStrength: number;
|
|
44
|
+
};
|
|
45
|
+
export declare const STRUCTURAL: string[];
|
|
46
|
+
export declare const POINTER_MODES: string[];
|
|
47
|
+
export declare const GUI: ({
|
|
48
|
+
key: string;
|
|
49
|
+
options: string[];
|
|
50
|
+
tip: string;
|
|
51
|
+
min?: undefined;
|
|
52
|
+
max?: undefined;
|
|
53
|
+
step?: undefined;
|
|
54
|
+
} | {
|
|
55
|
+
key: string;
|
|
56
|
+
min: number;
|
|
57
|
+
max: number;
|
|
58
|
+
step: number;
|
|
59
|
+
} | {
|
|
60
|
+
key: string;
|
|
61
|
+
options: string[];
|
|
62
|
+
color?: undefined;
|
|
63
|
+
} | {
|
|
64
|
+
key: string;
|
|
65
|
+
color: boolean;
|
|
66
|
+
options?: undefined;
|
|
67
|
+
})[];
|
|
68
|
+
export declare const PRESETS: ({
|
|
69
|
+
name: string;
|
|
70
|
+
description: string;
|
|
71
|
+
patch: {
|
|
72
|
+
pins?: undefined;
|
|
73
|
+
metalness?: undefined;
|
|
74
|
+
roughness?: undefined;
|
|
75
|
+
relief?: undefined;
|
|
76
|
+
pinSize?: undefined;
|
|
77
|
+
base?: undefined;
|
|
78
|
+
};
|
|
79
|
+
} | {
|
|
80
|
+
name: string;
|
|
81
|
+
description: string;
|
|
82
|
+
patch: {
|
|
83
|
+
pins: number;
|
|
84
|
+
metalness: number;
|
|
85
|
+
roughness: number;
|
|
86
|
+
relief: number;
|
|
87
|
+
pinSize?: undefined;
|
|
88
|
+
base?: undefined;
|
|
89
|
+
};
|
|
90
|
+
} | {
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
patch: {
|
|
94
|
+
pins: number;
|
|
95
|
+
pinSize: number;
|
|
96
|
+
relief: number;
|
|
97
|
+
base: number;
|
|
98
|
+
metalness?: undefined;
|
|
99
|
+
roughness?: undefined;
|
|
100
|
+
};
|
|
101
|
+
})[];
|
|
102
|
+
export declare function createUniforms(): {
|
|
103
|
+
uRelief: {
|
|
104
|
+
value: number;
|
|
105
|
+
};
|
|
106
|
+
uBase: {
|
|
107
|
+
value: number;
|
|
108
|
+
};
|
|
109
|
+
uPin: {
|
|
110
|
+
value: number;
|
|
111
|
+
};
|
|
112
|
+
uPitch: {
|
|
113
|
+
value: number;
|
|
114
|
+
};
|
|
115
|
+
uGy: {
|
|
116
|
+
value: number;
|
|
117
|
+
};
|
|
118
|
+
uTex: {
|
|
119
|
+
value: any;
|
|
120
|
+
};
|
|
121
|
+
uS: {
|
|
122
|
+
value: number;
|
|
123
|
+
};
|
|
124
|
+
uCount: {
|
|
125
|
+
value: number;
|
|
126
|
+
};
|
|
127
|
+
uTime: {
|
|
128
|
+
value: number;
|
|
129
|
+
};
|
|
130
|
+
uAct: {
|
|
131
|
+
value: Float32Array<ArrayBuffer>;
|
|
132
|
+
};
|
|
133
|
+
uW: {
|
|
134
|
+
value: number;
|
|
135
|
+
};
|
|
136
|
+
uH: {
|
|
137
|
+
value: number;
|
|
138
|
+
};
|
|
139
|
+
uWave: {
|
|
140
|
+
value: number;
|
|
141
|
+
};
|
|
142
|
+
uSlant: {
|
|
143
|
+
value: number;
|
|
144
|
+
};
|
|
145
|
+
uDim: {
|
|
146
|
+
value: number;
|
|
147
|
+
};
|
|
148
|
+
uIntensity: {
|
|
149
|
+
value: number;
|
|
150
|
+
};
|
|
151
|
+
uOpacity: {
|
|
152
|
+
value: number;
|
|
153
|
+
};
|
|
154
|
+
uPointer: {
|
|
155
|
+
value: THREE.Vector3;
|
|
156
|
+
};
|
|
157
|
+
uPointerActive: {
|
|
158
|
+
value: number;
|
|
159
|
+
};
|
|
160
|
+
uPointerMode: {
|
|
161
|
+
value: number;
|
|
162
|
+
};
|
|
163
|
+
uPointerStrength: {
|
|
164
|
+
value: number;
|
|
165
|
+
};
|
|
166
|
+
uPointerRadius: {
|
|
167
|
+
value: number;
|
|
168
|
+
};
|
|
169
|
+
uPlace: {
|
|
170
|
+
value: THREE.Matrix4[];
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
export declare function applyConfig(u: any, c: any): void;
|
|
174
|
+
export declare function build(u: any, c: any): any;
|
|
175
|
+
//# sourceMappingURL=pinscreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinscreen.d.ts","sourceRoot":"","sources":["../../../../src/components/gallery/looks/pinscreen.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,eAAO,MAAM,OAAO;;;;;;;;;CAE4D,CAAC;AAEjF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKpB,CAAC;AACF,eAAO,MAAM,UAAU,UAA2C,CAAC;AACnE,eAAO,MAAM,aAAa,UAAY,CAAC;AACvC,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;IASf,CAAC;AACF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAInB,CAAC;AACF,wBAAgB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE7B;AACD,wBAAgB,WAAW,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,QAG/B;AA6BD,wBAAgB,KAAK,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,OAA6C"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// The approved lab module, verbatim but for its import paths and the lab's picture loader (Claude outputs/gallery-lab/
|
|
2
|
+
// pinscreen.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.pinscreen) do not carry; its own autoplay is never used.
|
|
4
|
+
// pinscreen — every picture is a bed of fine square pins, lit by the scene. Each pin's height follows the
|
|
5
|
+
// picture's brightness at its place; its head carries the picture's colour. An inactive picture is a flat grey bed
|
|
6
|
+
// of pin heads flush with the board. When it becomes the active one a soft wave crosses it and pushes the pins out
|
|
7
|
+
// into a real relief in full colour; leaving lets them sink back. The cursor presses the pins in, like a hand on a
|
|
8
|
+
// pin toy. Scene-lit (standard material): the studio's lights draw the relief; the gallery adds none.
|
|
9
|
+
import * as THREE from 'three';
|
|
10
|
+
import { BASE_DEFAULTS, BASE_GUI_MOTION, BASE_GUI_TAIL, LAYOUT_GUI, baseUniforms, applyBase, instanced, litMaterial, makeGallery, withLean } from '../kit/lookBase.js';
|
|
11
|
+
export const catalog = { key: 'pinscreen', name: 'Pinscreen', camera: { position: [0.9, 0.35, 4.6], target: [0, 0, 0] },
|
|
12
|
+
description: 'Pictures as beds of fine pins lit by the scene: inactive ones are a flat grey bed, the active one is pushed out by a soft wave into a relief in full colour; the cursor presses the pins in. Use for product, tech and tactile showcases.',
|
|
13
|
+
tags: ['gallery', 'pins', 'relief', 'tactile', 'scene-lit', 'interactive'] };
|
|
14
|
+
export const DEFAULTS = {
|
|
15
|
+
...BASE_DEFAULTS, type: 'pinscreen', aspect: 1.4, width: 2.2, pins: 64, // structural: pins across
|
|
16
|
+
relief: 0.16, pinSize: 0.84, base: 0.12, roughness: 0.45, metalness: 0.15, boardColor: '#15161b',
|
|
17
|
+
changeTime: 2.0, dim: 0.42,
|
|
18
|
+
pointerMode: 'press', pointerRadius: 0.4,
|
|
19
|
+
};
|
|
20
|
+
export const STRUCTURAL = ['imageUrls', 'aspect', 'width', 'pins'];
|
|
21
|
+
export const POINTER_MODES = ['press'];
|
|
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 }, { key: 'pins', min: 24, max: 110, step: 1, tip: 'Pins across a picture' },
|
|
25
|
+
...LAYOUT_GUI, ...BASE_GUI_MOTION,
|
|
26
|
+
{ key: 'relief', min: 0, max: 0.5, step: 0.005, tip: 'How far the brightest pins stand out' }, { key: 'base', min: 0, max: 0.6, step: 0.01, tip: 'Relief of the darkest pins, as a share of the brightest' },
|
|
27
|
+
{ key: 'pinSize', min: 0.3, max: 1, step: 0.01, tip: 'Pin width, as a share of the spacing' },
|
|
28
|
+
{ key: 'roughness', min: 0, max: 1, step: 0.01 }, { key: 'metalness', min: 0, max: 1, step: 0.01 },
|
|
29
|
+
{ key: 'pointerMode', options: ['none', ...POINTER_MODES] }, ...BASE_GUI_TAIL,
|
|
30
|
+
{ key: 'boardColor', color: true },
|
|
31
|
+
];
|
|
32
|
+
export const PRESETS = [
|
|
33
|
+
{ name: 'Pinscreen', description: 'The default.', patch: {} },
|
|
34
|
+
{ name: 'Steel pins', description: 'Fine metal pins, a deeper relief.', patch: { pins: 90, metalness: 0.75, roughness: 0.3, relief: 0.22 } },
|
|
35
|
+
{ name: 'Blocks', description: 'Few fat pins, shallow.', patch: { pins: 36, pinSize: 0.94, relief: 0.1, base: 0.3 } },
|
|
36
|
+
];
|
|
37
|
+
export function createUniforms() {
|
|
38
|
+
return { ...baseUniforms(), uRelief: { value: 0.16 }, uBase: { value: 0.12 }, uPin: { value: 0.84 }, uPitch: { value: 0.03 }, uGy: { value: 46 } };
|
|
39
|
+
}
|
|
40
|
+
export function applyConfig(u, c) {
|
|
41
|
+
const set = applyBase(u, c, POINTER_MODES);
|
|
42
|
+
set('uRelief', c.relief);
|
|
43
|
+
set('uBase', c.base);
|
|
44
|
+
set('uPin', c.pinSize);
|
|
45
|
+
}
|
|
46
|
+
const vertex = {
|
|
47
|
+
head: /* glsl */ `uniform float uRelief, uBase, uPin, uPitch; varying vec3 vCol; varying float vAlpha;`,
|
|
48
|
+
body: /* glsl */ `
|
|
49
|
+
float img = aI.x; vec2 g = aI.zw; float act = actOf(img);
|
|
50
|
+
vec3 pic = textureLod(uTex, vec3(g, img), 1.5).rgb;
|
|
51
|
+
float lum = lumOf(pic);
|
|
52
|
+
vec2 cen = vec2((g.x - 0.5) * uW, (g.y - 0.5) * uH);
|
|
53
|
+
float w = waveAt(act, g);
|
|
54
|
+
float press = 1.0 - 0.92 * maskAt(cen);
|
|
55
|
+
float h = uRelief * (uBase + (1.0 - uBase) * lum) * w * press;
|
|
56
|
+
float top = step(0.49, position.z);
|
|
57
|
+
// the pin stands on the board: from just behind it (z = -0.01) up to its head at h
|
|
58
|
+
gPos = vec3(cen + position.xy * uPitch * uPin, mix(-0.01, h + 0.002, position.z + 0.5));
|
|
59
|
+
vec3 c = mix(fadedOf(pic), pic, smoothstep(0.0, 1.0, w));
|
|
60
|
+
vCol = c * mix(0.55, 1.0, top); // the head carries the picture, the sides are its shade
|
|
61
|
+
vAlpha = fadeAt(img);
|
|
62
|
+
`,
|
|
63
|
+
};
|
|
64
|
+
const fragment = {
|
|
65
|
+
head: /* glsl */ `varying vec3 vCol; varying float vAlpha;`,
|
|
66
|
+
body: /* glsl */ `diffuseColor.rgb = vCol * uIntensity; diffuseColor.a *= vAlpha * uOpacity; if (diffuseColor.a < 0.01) discard;`,
|
|
67
|
+
};
|
|
68
|
+
const boardVertex = {
|
|
69
|
+
head: /* glsl */ `varying float vAlpha;`,
|
|
70
|
+
body: /* glsl */ `gPos = vec3(position.x * uW, position.y * uH, -0.004); vAlpha = fadeAt(aI.x);`,
|
|
71
|
+
};
|
|
72
|
+
const boardFragment = { head: /* glsl */ `varying float vAlpha;`, body: /* glsl */ `diffuseColor.a *= vAlpha * uOpacity; if (diffuseColor.a < 0.01) discard;` };
|
|
73
|
+
export function build(u, c) { return withLean(buildGallery(u, c), c); }
|
|
74
|
+
function buildGallery(u, c) {
|
|
75
|
+
const W = c.width, H = W / c.aspect, gx = Math.max(8, c.pins | 0), gy = Math.max(6, Math.round(gx / c.aspect)), per = gx * gy;
|
|
76
|
+
u.uPitch.value = W / gx;
|
|
77
|
+
const pinGeo = instanced(new THREE.BoxGeometry(1, 1, 1), per, (k) => [((k % gx) + 0.5) / gx, (Math.floor(k / gx) + 0.5) / gy]);
|
|
78
|
+
const pinMat = litMaterial(u, 'pinscreen-pin', vertex, fragment, { roughness: c.roughness, metalness: c.metalness });
|
|
79
|
+
const pins = new THREE.Mesh(pinGeo, pinMat);
|
|
80
|
+
pins.frustumCulled = false;
|
|
81
|
+
pins.raycast = () => { };
|
|
82
|
+
pins.receiveShadow = true;
|
|
83
|
+
const boardGeo = instanced(new THREE.PlaneGeometry(1, 1), 1, () => [0.5, 0.5]);
|
|
84
|
+
const boardMat = litMaterial(u, 'pinscreen-board', boardVertex, boardFragment, { color: c.boardColor, roughness: 0.85 });
|
|
85
|
+
const board = new THREE.Mesh(boardGeo, boardMat);
|
|
86
|
+
board.frustumCulled = false;
|
|
87
|
+
board.raycast = () => { };
|
|
88
|
+
board.receiveShadow = true;
|
|
89
|
+
const g = makeGallery(u, c, { W, H, meshes: [pins, board], setCount: (n) => { pinGeo.instanceCount = n * per; boardGeo.instanceCount = n; } });
|
|
90
|
+
const apply = g.apply;
|
|
91
|
+
g.apply = (k) => { apply(k); applyConfig(u, k); if (k.roughness !== undefined)
|
|
92
|
+
pinMat.roughness = k.roughness; if (k.metalness !== undefined)
|
|
93
|
+
pinMat.metalness = k.metalness; if (k.boardColor)
|
|
94
|
+
boardMat.color.set(k.boardColor); };
|
|
95
|
+
return g;
|
|
96
|
+
}
|