@3driseai/3drise-viewer 0.1.29 → 0.1.31
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/ClipPlayer.d.ts.map +1 -1
- package/dist/animationsV2/ClipPlayer.js +14 -12
- package/dist/animationsV2/ClipsRuntime.d.ts +13 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +115 -4
- package/dist/animationsV2/appliers.d.ts.map +1 -1
- package/dist/animationsV2/appliers.js +21 -2
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +5 -1
- package/dist/animationsV2/sequenceUtils.d.ts +5 -0
- package/dist/animationsV2/sequenceUtils.d.ts.map +1 -1
- package/dist/animationsV2/sequenceUtils.js +14 -5
- package/dist/animationsV2/sunSystemLive.d.ts +12 -0
- package/dist/animationsV2/sunSystemLive.d.ts.map +1 -0
- package/dist/animationsV2/sunSystemLive.js +8 -0
- package/dist/animationsV2/types.d.ts +6 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/api/sceneHandle.d.ts +3 -1
- package/dist/api/sceneHandle.d.ts.map +1 -1
- package/dist/api/sceneHandle.js +2 -2
- package/dist/components/AdaptiveResolution.d.ts +9 -0
- package/dist/components/AdaptiveResolution.d.ts.map +1 -0
- package/dist/components/AdaptiveResolution.js +61 -0
- package/dist/components/CameraController.d.ts.map +1 -1
- package/dist/components/CameraController.js +24 -7
- package/dist/components/EffectsGenerator.d.ts.map +1 -1
- package/dist/components/EffectsGenerator.js +43 -38
- package/dist/components/GeometryShape.d.ts.map +1 -1
- package/dist/components/GeometryShape.js +22 -2
- package/dist/components/MoonDisc.d.ts.map +1 -1
- package/dist/components/MoonDisc.js +2 -1
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +6 -17
- package/dist/components/OceanBuilder.d.ts +4 -1
- package/dist/components/OceanBuilder.d.ts.map +1 -1
- package/dist/components/OceanBuilder.js +2 -1
- package/dist/components/ParticlesGenerator.d.ts.map +1 -1
- package/dist/components/ParticlesGenerator.js +46 -24
- package/dist/components/PickVolume.d.ts +17 -0
- package/dist/components/PickVolume.d.ts.map +1 -0
- package/dist/components/PickVolume.js +20 -0
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SceneBuilder.js +5 -2
- package/dist/components/SkyStars.d.ts.map +1 -1
- package/dist/components/SkyStars.js +83 -2
- package/dist/components/Skybox.d.ts.map +1 -1
- package/dist/components/Skybox.js +2 -1
- package/dist/components/SunLight.d.ts.map +1 -1
- package/dist/components/SunLight.js +3 -2
- package/dist/components/TextGenerator.d.ts.map +1 -1
- package/dist/components/TextGenerator.js +3 -2
- package/dist/components/index.d.ts +2 -8
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -4
- package/dist/components/lightBulb/LightBulb.d.ts.map +1 -1
- package/dist/components/lightBulb/LightBulb.js +7 -2
- package/dist/components/particles/BioluminescentWakeParticles.d.ts +5 -0
- package/dist/components/particles/BioluminescentWakeParticles.d.ts.map +1 -1
- package/dist/components/particles/BioluminescentWakeParticles.js +2 -1
- package/dist/components/particles/BrownianDustParticles.d.ts +5 -0
- package/dist/components/particles/BrownianDustParticles.d.ts.map +1 -1
- package/dist/components/particles/BrownianDustParticles.js +2 -0
- package/dist/components/particles/ChladniSandParticles.d.ts +5 -0
- package/dist/components/particles/ChladniSandParticles.d.ts.map +1 -1
- package/dist/components/particles/ChladniSandParticles.js +2 -1
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts +5 -0
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts.map +1 -1
- package/dist/components/particles/ElectronOrbitalsParticles.js +2 -1
- package/dist/components/particles/FaradayPowderParticles.d.ts +5 -0
- package/dist/components/particles/FaradayPowderParticles.d.ts.map +1 -1
- package/dist/components/particles/FaradayPowderParticles.js +2 -1
- package/dist/components/particles/FireworksParticles.d.ts +22 -0
- package/dist/components/particles/FireworksParticles.d.ts.map +1 -0
- package/dist/components/particles/FireworksParticles.js +1649 -0
- package/dist/components/particles/GrinderSparksParticles.d.ts +5 -0
- package/dist/components/particles/GrinderSparksParticles.d.ts.map +1 -1
- package/dist/components/particles/GrinderSparksParticles.js +2 -1
- package/dist/components/particles/MagneticBottleParticles.d.ts +5 -0
- package/dist/components/particles/MagneticBottleParticles.d.ts.map +1 -1
- package/dist/components/particles/MagneticBottleParticles.js +2 -1
- package/dist/components/particles/NeonRainParticles.d.ts +5 -0
- package/dist/components/particles/NeonRainParticles.d.ts.map +1 -1
- package/dist/components/particles/NeonRainParticles.js +2 -1
- package/dist/components/particles/ShapeBurstParticles.d.ts +5 -0
- package/dist/components/particles/ShapeBurstParticles.d.ts.map +1 -1
- package/dist/components/particles/ShapeBurstParticles.js +2 -1
- package/dist/components/particles/ShapeFlowParticles.d.ts +5 -0
- package/dist/components/particles/ShapeFlowParticles.d.ts.map +1 -1
- package/dist/components/particles/ShapeFlowParticles.js +2 -1
- package/dist/components/particles/TidalStreamParticles.d.ts +5 -0
- package/dist/components/particles/TidalStreamParticles.d.ts.map +1 -1
- package/dist/components/particles/TidalStreamParticles.js +2 -0
- package/dist/components/particles/index.d.ts +2 -0
- package/dist/components/particles/index.d.ts.map +1 -1
- package/dist/components/particles/index.js +1 -0
- package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
- package/dist/components/terrain/TerrainSurface.js +26 -4
- package/dist/components/text/PlainText.d.ts +15 -0
- package/dist/components/text/PlainText.d.ts.map +1 -0
- package/dist/components/text/PlainText.js +4 -0
- package/dist/components/text/TextObjectView.d.ts +3 -1
- package/dist/components/text/TextObjectView.d.ts.map +1 -1
- package/dist/components/text/TextObjectView.js +9 -3
- package/dist/components/text/engine/looks/index.d.ts.map +1 -1
- package/dist/components/text/engine/looks/index.js +2 -1
- package/dist/components/text/engine/looks/plain.d.ts +146 -0
- package/dist/components/text/engine/looks/plain.d.ts.map +1 -0
- package/dist/components/text/engine/looks/plain.js +104 -0
- package/dist/components/text/fonts/bebas-neue.outline.d.ts +3 -0
- package/dist/components/text/fonts/bebas-neue.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/bebas-neue.outline.js +4 -0
- package/dist/components/text/fonts/bebas-neue.strokes.d.ts +3 -0
- package/dist/components/text/fonts/bebas-neue.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/bebas-neue.strokes.js +4 -0
- package/dist/components/text/fonts/index.d.ts +1 -1
- package/dist/components/text/fonts/index.d.ts.map +1 -1
- package/dist/components/text/fonts/index.js +15 -1
- package/dist/components/text/fonts/inter.outline.d.ts +3 -0
- package/dist/components/text/fonts/inter.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/inter.outline.js +4 -0
- package/dist/components/text/fonts/inter.strokes.d.ts +3 -0
- package/dist/components/text/fonts/inter.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/inter.strokes.js +4 -0
- package/dist/components/text/fonts/lora.outline.d.ts +3 -0
- package/dist/components/text/fonts/lora.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/lora.outline.js +4 -0
- package/dist/components/text/fonts/lora.strokes.d.ts +3 -0
- package/dist/components/text/fonts/lora.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/lora.strokes.js +4 -0
- package/dist/components/text/fonts/montserrat.outline.d.ts +3 -0
- package/dist/components/text/fonts/montserrat.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/montserrat.outline.js +4 -0
- package/dist/components/text/fonts/montserrat.strokes.d.ts +3 -0
- package/dist/components/text/fonts/montserrat.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/montserrat.strokes.js +4 -0
- package/dist/components/text/fonts/oswald.outline.d.ts +3 -0
- package/dist/components/text/fonts/oswald.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/oswald.outline.js +4 -0
- package/dist/components/text/fonts/oswald.strokes.d.ts +3 -0
- package/dist/components/text/fonts/oswald.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/oswald.strokes.js +4 -0
- package/dist/components/text/fonts/playfair-display.outline.d.ts +3 -0
- package/dist/components/text/fonts/playfair-display.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/playfair-display.outline.js +4 -0
- package/dist/components/text/fonts/playfair-display.strokes.d.ts +3 -0
- package/dist/components/text/fonts/playfair-display.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/playfair-display.strokes.js +4 -0
- package/dist/components/text/fonts/roboto.outline.d.ts +3 -0
- package/dist/components/text/fonts/roboto.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/roboto.outline.js +4 -0
- package/dist/components/text/fonts/roboto.strokes.d.ts +3 -0
- package/dist/components/text/fonts/roboto.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/roboto.strokes.js +4 -0
- package/dist/components/text/index.d.ts +2 -0
- package/dist/components/text/index.d.ts.map +1 -1
- package/dist/components/text/index.js +1 -0
- package/dist/components/text/useTextObject.d.ts +1 -0
- package/dist/components/text/useTextObject.d.ts.map +1 -1
- package/dist/components/text/useTextObject.js +23 -11
- package/dist/components/water/OceanSurface.d.ts.map +1 -1
- package/dist/components/water/OceanSurface.js +5 -1
- package/dist/components/water/types.d.ts +3 -1
- package/dist/components/water/types.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/hooks/useOceanMaterial.d.ts +6 -2
- package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
- package/dist/hooks/useOceanMaterial.js +22 -2
- package/dist/hooks/useOrbitTargetFollow.d.ts +10 -0
- package/dist/hooks/useOrbitTargetFollow.d.ts.map +1 -0
- package/dist/hooks/useOrbitTargetFollow.js +194 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/operations/catalogue/flock.d.ts.map +1 -1
- package/dist/operations/catalogue/flock.js +44 -9
- package/dist/operations/catalogue/inkBloom.d.ts.map +1 -1
- package/dist/operations/catalogue/inkBloom.js +46 -9
- package/dist/operations/catalogue/liquidMetal.d.ts.map +1 -1
- package/dist/operations/catalogue/liquidMetal.js +41 -12
- package/dist/operations/catalogue/particleSwarm.d.ts.map +1 -1
- package/dist/operations/catalogue/particleSwarm.js +29 -9
- package/dist/operations/catalogue/petalPeel.d.ts.map +1 -1
- package/dist/operations/catalogue/petalPeel.js +33 -9
- package/dist/operations/catalogue/portal.d.ts.map +1 -1
- package/dist/operations/catalogue/portal.js +33 -11
- package/dist/operations/catalogue/sandErosion.d.ts.map +1 -1
- package/dist/operations/catalogue/sandErosion.js +36 -14
- package/dist/operations/catalogue/teleport.d.ts.map +1 -1
- package/dist/operations/catalogue/teleport.js +43 -12
- package/dist/operations/catalogue/unweave.d.ts.map +1 -1
- package/dist/operations/catalogue/unweave.js +34 -15
- package/dist/operations/catalogue/voxelize.d.ts.map +1 -1
- package/dist/operations/catalogue/voxelize.js +37 -10
- package/dist/shaders/glsl/terrainCore.glsl.d.ts +18 -3
- package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -1
- package/dist/shaders/glsl/terrainCore.glsl.js +42 -21
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +36 -11
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -1
- package/dist/shaders/ocean/OceanSurfaceMaterial.js +96 -5
- package/dist/triggers/engine.d.ts +1 -1
- package/dist/triggers/engine.d.ts.map +1 -1
- package/dist/triggers/engine.js +3 -0
- package/dist/triggers/hosts/actions.d.ts.map +1 -1
- package/dist/triggers/hosts/actions.js +3 -1
- package/dist/triggers/hosts/interactions.d.ts.map +1 -1
- package/dist/triggers/hosts/interactions.js +1 -1
- package/dist/triggers/hosts/timelineCues.js +1 -1
- package/dist/triggers/kinds/change.d.ts +4 -0
- package/dist/triggers/kinds/change.d.ts.map +1 -0
- package/dist/triggers/kinds/change.js +50 -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/utils/CameraSingleton.d.ts +4 -0
- package/dist/utils/CameraSingleton.d.ts.map +1 -1
- package/dist/utils/CameraSingleton.js +4 -0
- package/dist/utils/deviceTier.d.ts +2 -0
- package/dist/utils/deviceTier.d.ts.map +1 -0
- package/dist/utils/deviceTier.js +16 -0
- package/dist/utils/environmentDrawOrder.d.ts +23 -0
- package/dist/utils/environmentDrawOrder.d.ts.map +1 -0
- package/dist/utils/environmentDrawOrder.js +22 -0
- package/dist/utils/pickProxy.d.ts +11 -0
- package/dist/utils/pickProxy.d.ts.map +1 -0
- package/dist/utils/pickProxy.js +36 -0
- package/dist/utils/shapes.d.ts +4 -0
- package/dist/utils/shapes.d.ts.map +1 -1
- package/dist/utils/shapes.js +4 -1
- package/dist/utils/terrainUniforms.d.ts +7 -0
- package/dist/utils/terrainUniforms.d.ts.map +1 -1
- package/dist/utils/terrainUniforms.js +15 -2
- package/dist/utils/textShape.d.ts +24 -0
- package/dist/utils/textShape.d.ts.map +1 -0
- package/dist/utils/textShape.js +102 -0
- package/package.json +2 -2
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// streams — out and up, or all toward one side of the screen — accelerating
|
|
5
5
|
// until they are gone. Birds always face the way they fly, so on revert they
|
|
6
6
|
// fly back in (head first) and settle into place as the surface re-forms.
|
|
7
|
+
// With Disappear off (an object effect's default) the birds stay perched on every
|
|
8
|
+
// spot of the surface (the surface itself gone): a flutter now and then, heads turning.
|
|
7
9
|
import { BufferAttribute, BufferGeometry, Vector3 } from 'three';
|
|
8
10
|
import { defineOperation } from '../types.js';
|
|
9
11
|
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
@@ -36,17 +38,19 @@ function birdGeometry() {
|
|
|
36
38
|
export default defineOperation({
|
|
37
39
|
value: 'flock',
|
|
38
40
|
label: 'Flock',
|
|
39
|
-
description: 'Turn the targets into a flock of birds that takes off and flies away — reverting flies them home',
|
|
41
|
+
description: 'Turn the targets into a flock of birds that takes off and flies away (or, Disappear off, stays perched) — reverting flies them home',
|
|
40
42
|
channel: 'visual',
|
|
41
43
|
multi: true,
|
|
42
44
|
toggles: true,
|
|
43
|
-
usableIn: ['interaction', 'action'],
|
|
45
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
46
|
+
objectParams: { disappear: false },
|
|
44
47
|
params: {
|
|
45
48
|
direction: { type: 'select', label: 'Take-off order', default: 'down', options: DIRECTION_OPTIONS },
|
|
46
|
-
|
|
49
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the birds stay perched on the object' },
|
|
50
|
+
exit: { type: 'select', label: 'Fly', default: 'away', showWhen: { disappear: ['true'] }, options: [{ value: 'away', label: 'Out and up' }, { value: 'left', label: 'To the right' }, { value: 'right', label: 'To the left' }, { value: 'up', label: 'Straight up' }] },
|
|
47
51
|
birds: { type: 'number', label: 'Birds', default: 1400, min: 100, max: 12000, step: 100 },
|
|
48
52
|
birdSize: { type: 'number', label: 'Bird size', default: 1, min: 0.3, max: 4, step: 0.05, unit: '×' },
|
|
49
|
-
speed: { type: 'number', label: 'Speed', default: 1, min: 0.2, max: 4, step: 0.05, unit: '×' },
|
|
53
|
+
speed: { type: 'number', label: 'Speed', default: 1, min: 0.2, max: 4, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
50
54
|
edgeColor: { type: 'color', label: 'Edge colour', default: '#ffffff' },
|
|
51
55
|
scale: { type: 'number', label: 'Pattern', default: 2.5, min: 0.5, max: 12, step: 0.1 },
|
|
52
56
|
duration: { type: 'number', label: 'Duration', default: 3.4, min: 0.3, max: 14, step: 0.1, unit: 's' },
|
|
@@ -57,7 +61,7 @@ export default defineOperation({
|
|
|
57
61
|
const field = createFieldState(target);
|
|
58
62
|
field.edgeWidth.value = 0.04;
|
|
59
63
|
const own = {
|
|
60
|
-
field, exit: { value: new Vector3(1, 0, 0) }, mode: { value: 0 }, speed: { value: 1 }, dirSign: { value: 1 }, bird: { value: 1 }, mats: new Set(),
|
|
64
|
+
field, exit: { value: new Vector3(1, 0, 0) }, mode: { value: 0 }, speed: { value: 1 }, dirSign: { value: 1 }, bird: { value: 1 }, keep: { value: 0 }, mats: new Set(),
|
|
61
65
|
};
|
|
62
66
|
const sample = sampleSurfaceCached(target, Math.round(Number(p.birds)), 53);
|
|
63
67
|
const n = sample.count;
|
|
@@ -68,7 +72,7 @@ export default defineOperation({
|
|
|
68
72
|
attributes: { aFlkP: [pos, 3], aFlkN: [sample.normal.slice(0, n * 3), 3], aFlkR: [sample.random.slice(0, n * 4), 4] },
|
|
69
73
|
layerKey: 'flockInstances', roughness: 0.65, metalness: 0, doubleSided: true,
|
|
70
74
|
layer: {
|
|
71
|
-
uniforms: { ...fieldUniforms(P, field), uFlkExit: own.exit, uFlkMode: own.mode, uFlkSpeed: own.speed, uFlkDirSign: own.dirSign, uFlkBird: own.bird },
|
|
75
|
+
uniforms: { ...fieldUniforms(P, field), uFlkExit: own.exit, uFlkMode: own.mode, uFlkSpeed: own.speed, uFlkDirSign: own.dirSign, uFlkBird: own.bird, uFlkKeep: own.keep },
|
|
72
76
|
common: fieldGlsl(P),
|
|
73
77
|
vertexPars: /* glsl */ `
|
|
74
78
|
attribute float aWing; attribute vec3 aFlkP; attribute vec3 aFlkN; attribute vec4 aFlkR;
|
|
@@ -98,12 +102,33 @@ export default defineOperation({
|
|
|
98
102
|
vec3 right = normalize(cross(fwd, vec3(0.0, 1.0, 0.0)) + vec3(1e-4));
|
|
99
103
|
vec3 up = cross(right, fwd);
|
|
100
104
|
return mat3(right, up, fwd);
|
|
101
|
-
}
|
|
102
|
-
|
|
105
|
+
}
|
|
106
|
+
// perched: sitting on its spot, up along the surface normal, turning its head now and then
|
|
107
|
+
mat3 flkPerch() {
|
|
108
|
+
vec3 up = normalize(aFlkN + vec3(1e-4));
|
|
109
|
+
vec3 any = abs(up.y) < 0.9 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
|
110
|
+
vec3 right0 = normalize(cross(up, any));
|
|
111
|
+
float yaw = aFlkR.z * 6.2832 + step(0.6, aFlkR.y) * 0.35 * sin(uFlkTime * (0.4 + 0.5 * aFlkR.w) + aFlkR.x * 30.0);
|
|
112
|
+
vec3 right = right0 * cos(yaw) + cross(up, right0) * sin(yaw);
|
|
113
|
+
vec3 fwd = cross(right, up);
|
|
114
|
+
return mat3(right, up, fwd);
|
|
115
|
+
}
|
|
116
|
+
float flkHeld() { return uFlkKeep * step(0.9999, uFlkProgress); }`,
|
|
117
|
+
normal: `{ objectNormal = (uFlkKeep > 0.5 ? flkPerch() : flkFrame(clamp(flkAge(), 0.0, 1.0))) * objectNormal; }`,
|
|
103
118
|
vertex: /* glsl */ `
|
|
104
119
|
{
|
|
105
120
|
float a = flkAge();
|
|
106
121
|
if (a <= 0.0) { transformed *= 0.0; }
|
|
122
|
+
else if (uFlkKeep > 0.5) {
|
|
123
|
+
// perched on its spot; a brief flutter now and then
|
|
124
|
+
vec3 v = transformed;
|
|
125
|
+
float flutter = smoothstep(0.93, 1.0, sin(uFlkTime * (0.5 + 0.4 * aFlkR.x) + aFlkR.z * 60.0)) * flkHeld();
|
|
126
|
+
v.y += abs(aWing) * sin(uFlkTime * 22.0 + aFlkR.y * 6.28) * 0.38 * flutter;
|
|
127
|
+
v.y += abs(aWing) * 0.12; // wings held slightly up at rest
|
|
128
|
+
float size = uFlkExtent * 0.03 * uFlkBird * (0.8 + 0.4 * aFlkR.w);
|
|
129
|
+
float sc = smoothstep(0.0, 0.06, a);
|
|
130
|
+
transformed = flkPerch() * (v * size * sc) + aFlkN * uFlkExtent * 0.008;
|
|
131
|
+
}
|
|
107
132
|
else {
|
|
108
133
|
a = min(a, 1.0);
|
|
109
134
|
vec3 v = transformed;
|
|
@@ -139,6 +164,15 @@ export default defineOperation({
|
|
|
139
164
|
s.exit.value.copy(p.exit === 'left' ? r : r.negate());
|
|
140
165
|
}
|
|
141
166
|
s.mesh.visible = true;
|
|
167
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
168
|
+
if (s.keep.value) {
|
|
169
|
+
// keep: the surface becomes birds (0 → 1), perched, and holds
|
|
170
|
+
return runProgress(target, s.field, 1, {
|
|
171
|
+
duration: Number(p.duration) / (1 + LIFE), ease: 'none', hold: true,
|
|
172
|
+
onComplete: () => hideMeshes(target, KEY, true),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
hideMeshes(target, KEY, false);
|
|
142
176
|
return runProgress(target, s.field, 1 + LIFE, {
|
|
143
177
|
duration: Number(p.duration), ease: 'power1.in',
|
|
144
178
|
onComplete: () => { hideMeshes(target, KEY, true); s.mesh.visible = false; },
|
|
@@ -151,8 +185,9 @@ export default defineOperation({
|
|
|
151
185
|
hideMeshes(target, KEY, false);
|
|
152
186
|
s.mesh.visible = true;
|
|
153
187
|
s.dirSign.value = -1;
|
|
188
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
154
189
|
return runProgress(target, s.field, 0, {
|
|
155
|
-
duration: Number(p.duration), ease: 'power1.out',
|
|
190
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / (1 + LIFE))), ease: s.keep.value ? 'none' : 'power1.out',
|
|
156
191
|
onComplete: () => {
|
|
157
192
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
158
193
|
disposeFxInstances(s.mesh);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inkBloom.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/inkBloom.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"inkBloom.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/inkBloom.ts"],"names":[],"mappings":";AA4EA,wBAyHG"}
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
// so the ink reads as clean curling threads that fray, sink and thin out, not
|
|
5
5
|
// as soft blobs. Normal blending (dark on light), so it works on light scenes.
|
|
6
6
|
// Reverting draws the ink back into the object.
|
|
7
|
+
// With Disappear off (an object effect's default) the object stays stained with ink,
|
|
8
|
+
// filaments hanging in the water around it, swaying but never thinning out.
|
|
7
9
|
import { BufferAttribute, BufferGeometry, LineSegments, NormalBlending, ShaderMaterial } from 'three';
|
|
8
10
|
import { defineOperation } from '../types.js';
|
|
9
11
|
import { addLayer, forEachMeshMaterial, removeLayer, uniformDecl } from './shaderLayers.js';
|
|
10
|
-
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, surfaceLayer, } from './transitionField.js';
|
|
12
|
+
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, setReveal, surfaceLayer, } from './transitionField.js';
|
|
11
13
|
import { sampleSurfaceCached } from './surfaceSample.js';
|
|
12
14
|
import { hideUntilWarm } from './warmup.js';
|
|
13
15
|
const P = 'Ink';
|
|
@@ -16,6 +18,28 @@ const STATE = '__opInk';
|
|
|
16
18
|
const LIFE = 0.9;
|
|
17
19
|
/** Points per filament (its trail through the water). */
|
|
18
20
|
const TRAIL = 12;
|
|
21
|
+
/** Keep: a wisp hangs this far along its path. */
|
|
22
|
+
const KEEP_AGE = 0.35;
|
|
23
|
+
/** The surface: stained along the front and gone behind it — or, keeping, stained all over and staying. */
|
|
24
|
+
function inkLayer(field, mixC, keep) {
|
|
25
|
+
const base = surfaceLayer(P, field, 'stain');
|
|
26
|
+
return {
|
|
27
|
+
...base,
|
|
28
|
+
uniforms: { ...base.uniforms, uInkMix: mixC, uInkKeep: keep },
|
|
29
|
+
fragment: /* glsl */ `
|
|
30
|
+
if (uInkKeep > 0.5) {
|
|
31
|
+
float InkD = InkField(vInkQ) - InkThreshold();
|
|
32
|
+
float stained = smoothstep(0.0, uInkEdgeWidth, -InkD);
|
|
33
|
+
// painting the object in: nothing ahead of the front, full ink right behind it
|
|
34
|
+
if (uInkReveal > 0.5) { if (InkD > 0.0) discard; stained = 1.0; }
|
|
35
|
+
// ink: a slow swirl of slightly lighter ink moving through it
|
|
36
|
+
float swirl = 0.8 + 0.4 * fxNoise(vInkQ * 5.0 + vec3(uInkTime * 0.12, -uInkTime * 0.08, 0.0));
|
|
37
|
+
vec3 ink = mix(uInkEdgeColor, outgoingLight, uInkMix) * swirl;
|
|
38
|
+
outgoingLight = mix(outgoingLight, ink, stained);
|
|
39
|
+
} else {${base.fragment}
|
|
40
|
+
}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
19
43
|
function buildFilaments(target, count) {
|
|
20
44
|
const s = sampleSurfaceCached(target, count, 29);
|
|
21
45
|
const segs = TRAIL - 1;
|
|
@@ -45,18 +69,21 @@ function buildFilaments(target, count) {
|
|
|
45
69
|
export default defineOperation({
|
|
46
70
|
value: 'inkBloom',
|
|
47
71
|
label: 'Ink bloom',
|
|
48
|
-
description: 'Bleed the targets into fine curling ink filaments, like a drop in water — reverting draws the ink back in',
|
|
72
|
+
description: 'Bleed the targets into fine curling ink filaments, like a drop in water (or, Disappear off, keep them inked) — reverting draws the ink back in',
|
|
49
73
|
channel: 'visual',
|
|
50
74
|
multi: true,
|
|
51
75
|
toggles: true,
|
|
52
|
-
usableIn: ['interaction', 'action'],
|
|
76
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
77
|
+
objectParams: { disappear: false },
|
|
78
|
+
presence: 'paint',
|
|
53
79
|
params: {
|
|
54
80
|
direction: { type: 'select', label: 'Direction', default: 'noise', options: DIRECTION_OPTIONS },
|
|
81
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object stays inked, filaments hanging around it' },
|
|
55
82
|
edgeColor: { type: 'color', label: 'Ink colour', default: '#16203a' },
|
|
56
83
|
tint: { type: 'number', label: 'Object colour', default: 0.15, min: 0, max: 1, step: 0.05, hint: 'How much of the object’s own colour the ink keeps' },
|
|
57
84
|
filaments: { type: 'number', label: 'Filaments', default: 9000, min: 1000, max: 40000, step: 500 },
|
|
58
85
|
opacity: { type: 'number', label: 'Density', default: 0.55, min: 0.05, max: 1, step: 0.05 },
|
|
59
|
-
sink: { type: 'number', label: 'Sink', default: 1, min: -2, max: 3, step: 0.05, unit: '×', hint: 'Negative rises like smoke' },
|
|
86
|
+
sink: { type: 'number', label: 'Sink', default: 1, min: -2, max: 3, step: 0.05, unit: '×', hint: 'Negative rises like smoke', showWhen: { disappear: ['true'] } },
|
|
60
87
|
scale: { type: 'number', label: 'Pattern', default: 2.5, min: 0.5, max: 12, step: 0.1 },
|
|
61
88
|
duration: { type: 'number', label: 'Duration', default: 3.6, min: 0.3, max: 14, step: 0.1, unit: 's' },
|
|
62
89
|
},
|
|
@@ -65,8 +92,8 @@ export default defineOperation({
|
|
|
65
92
|
if (!st) {
|
|
66
93
|
const field = createFieldState(target);
|
|
67
94
|
field.edgeWidth.value = 0.12;
|
|
68
|
-
const mixC = { value: 0.15 }, sink = { value: 1 }, opacity = { value: 0.55 };
|
|
69
|
-
const uniforms = { ...fieldUniforms(P, field), uInkMix: mixC, uInkSink: sink, uInkOpacity: opacity };
|
|
95
|
+
const mixC = { value: 0.15 }, sink = { value: 1 }, opacity = { value: 0.55 }, keep = { value: 0 };
|
|
96
|
+
const uniforms = { ...fieldUniforms(P, field), uInkMix: mixC, uInkSink: sink, uInkOpacity: opacity, uInkKeep: keep };
|
|
70
97
|
const decl = Object.keys(uniforms).map(n => uniformDecl(n, uniforms[n].value)).join('\n');
|
|
71
98
|
const mat = new ShaderMaterial({
|
|
72
99
|
uniforms: uniforms,
|
|
@@ -88,6 +115,8 @@ vec3 inkAt(vec3 p0, vec3 n0, vec4 r, float a) {
|
|
|
88
115
|
void main() {
|
|
89
116
|
float birth = InkBirthOf(InkField(InkNorm(position)));
|
|
90
117
|
float a = (uInkProgress - birth) / ${LIFE.toFixed(2)};
|
|
118
|
+
// keep: the wisp hangs part-way along its path, swaying along it
|
|
119
|
+
a = mix(a, min(a, ${KEEP_AGE} * (0.92 + 0.08 * sin(uInkTime * 0.7 + aR.w * 6.2832))), uInkKeep);
|
|
91
120
|
// the trail: this vertex sits a little back along the wisp's own path
|
|
92
121
|
float trail = 0.22 * (0.6 + 0.8 * aR.w);
|
|
93
122
|
float ak = clamp(a - aK * trail, 0.0, 1.0);
|
|
@@ -114,9 +143,9 @@ void main() {
|
|
|
114
143
|
lines.renderOrder = 10;
|
|
115
144
|
target.add(lines);
|
|
116
145
|
hideUntilWarm(lines);
|
|
117
|
-
st = { field, mixC, sink, opacity, lines, mats: new Set() };
|
|
146
|
+
st = { field, mixC, sink, opacity, keep, lines, mats: new Set() };
|
|
118
147
|
const own = st;
|
|
119
|
-
const layer =
|
|
148
|
+
const layer = inkLayer(field, mixC, keep);
|
|
120
149
|
forEachMeshMaterial(target, (m, mesh) => {
|
|
121
150
|
if (mesh.userData?.__opFxHelper)
|
|
122
151
|
return;
|
|
@@ -131,6 +160,12 @@ void main() {
|
|
|
131
160
|
s.sink.value = Number(p.sink);
|
|
132
161
|
s.opacity.value = Number(p.opacity);
|
|
133
162
|
s.lines.visible = true;
|
|
163
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
164
|
+
hideMeshes(target, KEY, false);
|
|
165
|
+
if (s.keep.value) {
|
|
166
|
+
// keep: the ink spreads over the whole object (0 → 1) and holds
|
|
167
|
+
return runProgress(target, s.field, 1, { duration: Number(p.duration) / (1 + LIFE), ease: 'none', hold: true });
|
|
168
|
+
}
|
|
134
169
|
return runProgress(target, s.field, 1 + LIFE, {
|
|
135
170
|
duration: Number(p.duration), ease: 'none',
|
|
136
171
|
onComplete: () => { hideMeshes(target, KEY, true); s.lines.visible = false; },
|
|
@@ -141,9 +176,11 @@ void main() {
|
|
|
141
176
|
if (!s)
|
|
142
177
|
return;
|
|
143
178
|
hideMeshes(target, KEY, false);
|
|
179
|
+
setReveal(s.field, p);
|
|
144
180
|
s.lines.visible = true;
|
|
181
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
145
182
|
return runProgress(target, s.field, 0, {
|
|
146
|
-
duration: Number(p.duration), ease: 'none',
|
|
183
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / (1 + LIFE))), ease: 'none',
|
|
147
184
|
onComplete: () => {
|
|
148
185
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
149
186
|
s.lines.removeFromParent();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liquidMetal.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/liquidMetal.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"liquidMetal.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/liquidMetal.ts"],"names":[],"mappings":";AAgGA,wBAwDG"}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// from the top down and flows out into a puddle on the ground (higher parts
|
|
3
3
|
// travel further), with slow ripples running across the pool while it lies
|
|
4
4
|
// there. Reverting pulls it back up into shape and the chrome fades off.
|
|
5
|
+
// With Disappear off (an object effect's default) the object turns to chrome and
|
|
6
|
+
// stays, unmelted: the studio reflection turns slowly, a soft ripple runs over it.
|
|
7
|
+
// The chrome comes in along a front (Direction) so it can paint the object in.
|
|
5
8
|
//
|
|
6
9
|
// The chrome is a procedural studio environment (sky gradient, horizon band,
|
|
7
10
|
// two soft boxes) reflected about the surface normal, so it reads as metal in
|
|
@@ -11,22 +14,25 @@ import { gsap } from 'gsap';
|
|
|
11
14
|
import { Color } from 'three';
|
|
12
15
|
import { defineOperation } from '../types.js';
|
|
13
16
|
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
14
|
-
import { createFieldState, fieldGlsl, fieldUniforms, runProgress, syncRoot } from './transitionField.js';
|
|
17
|
+
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, runProgress, setFieldParams, setReveal, syncRoot } from './transitionField.js';
|
|
15
18
|
const P = 'Liq';
|
|
16
19
|
const KEY = 'liquidMetal';
|
|
17
20
|
const STATE = '__opLiquid';
|
|
21
|
+
/** The chrome comes in over this much of the progress; the melt runs after it. */
|
|
22
|
+
const CHROME = 0.2;
|
|
18
23
|
function layerFor(st) {
|
|
19
24
|
return {
|
|
20
|
-
uniforms: { ...fieldUniforms(P, st.field), uLiqTint: st.tint, uLiqSpread: st.spread },
|
|
21
|
-
common: `varying float vLiqM;\nvarying vec3 vLiqView;\n${fieldGlsl(P)}`,
|
|
25
|
+
uniforms: { ...fieldUniforms(P, st.field), uLiqTint: st.tint, uLiqSpread: st.spread, uLiqKeep: st.keep },
|
|
26
|
+
common: `varying float vLiqM;\nvarying vec3 vLiqView;\nvarying vec3 vLiqQ;\n${fieldGlsl(P)}`,
|
|
22
27
|
vertex: /* glsl */ `
|
|
23
28
|
{
|
|
24
29
|
mat4 toRoot = uLiqRootInv * modelMatrix;
|
|
25
30
|
vec3 rl = (toRoot * vec4(transformed, 1.0)).xyz;
|
|
26
31
|
vec3 q = LiqNorm(rl);
|
|
32
|
+
vLiqQ = q;
|
|
27
33
|
float E = uLiqExtent;
|
|
28
|
-
// melt runs after the chrome has come in; the top gives way first
|
|
29
|
-
float mp = clamp((uLiqProgress - 0.18) / 0.82, 0.0, 1.0);
|
|
34
|
+
// melt runs after the chrome has come in; the top gives way first (never in keep)
|
|
35
|
+
float mp = clamp((uLiqProgress - 0.18) / 0.82, 0.0, 1.0) * (1.0 - uLiqKeep);
|
|
30
36
|
float wob = 0.12 * (fxNoise(q * 4.0) - 0.5);
|
|
31
37
|
float m = clamp(mp * 1.3 - (1.0 - q.y) * 0.3 + wob, 0.0, 1.0);
|
|
32
38
|
m = m * m; // slow start: it sags before it runs
|
|
@@ -48,7 +54,13 @@ function layerFor(st) {
|
|
|
48
54
|
}`,
|
|
49
55
|
fragment: /* glsl */ `
|
|
50
56
|
{
|
|
51
|
-
|
|
57
|
+
// the chrome comes in along a front over the first part of the progress
|
|
58
|
+
float tc = clamp(uLiqProgress / ${CHROME}, 0.0, 1.0) * (1.0 + 2.0 * uLiqEdgeWidth) - uLiqEdgeWidth;
|
|
59
|
+
float d = LiqField(vLiqQ) - tc;
|
|
60
|
+
float chrome = smoothstep(0.0, 0.08, -d);
|
|
61
|
+
// painting the object in: nothing ahead of the front, full chrome right behind it
|
|
62
|
+
if (uLiqReveal > 0.5) { if (d > 0.0) discard; chrome = 1.0; }
|
|
63
|
+
float held = uLiqKeep * step(0.9999, uLiqProgress);
|
|
52
64
|
vec3 nv = normalize(cross(dFdx(vLiqView), dFdy(vLiqView)));
|
|
53
65
|
#if defined( STANDARD ) || defined( PHONG ) || defined( LAMBERT ) || defined( TOON )
|
|
54
66
|
vec3 n = normalize(mix(normal, nv, smoothstep(0.05, 0.5, vLiqM)));
|
|
@@ -56,8 +68,12 @@ function layerFor(st) {
|
|
|
56
68
|
vec3 n = nv;
|
|
57
69
|
#endif
|
|
58
70
|
vec3 v = normalize(vLiqView);
|
|
71
|
+
// holding as chrome: a soft ripple runs over the surface, the studio turns slowly
|
|
72
|
+
n = normalize(n + held * 0.04 * vec3(sin(vLiqQ.y * 22.0 - uLiqTime * 1.6), 0.0, cos(vLiqQ.x * 19.0 - uLiqTime * 1.3)));
|
|
59
73
|
vec3 rv = reflect(v, n);
|
|
60
74
|
vec3 rw = normalize((vec4(rv, 0.0) * viewMatrix).xyz); // view → world direction
|
|
75
|
+
float ra = held * uLiqTime * 0.25;
|
|
76
|
+
rw = vec3(rw.x * cos(ra) - rw.z * sin(ra), rw.y, rw.x * sin(ra) + rw.z * cos(ra));
|
|
61
77
|
// studio: dark floor, bright sky, a crisp horizon band and two soft boxes
|
|
62
78
|
float up = rw.y;
|
|
63
79
|
vec3 env = mix(vec3(0.05), vec3(0.85, 0.9, 1.0), smoothstep(-0.15, 0.6, up));
|
|
@@ -66,6 +82,8 @@ function layerFor(st) {
|
|
|
66
82
|
env += vec3(1.2) * smoothstep(0.9, 0.98, dot(rw, normalize(vec3(-0.7, 0.35, -0.3))));
|
|
67
83
|
float fres = 0.65 + 0.35 * pow(1.0 - abs(dot(n, -v)), 3.0);
|
|
68
84
|
vec3 metal = uLiqTint * env * fres;
|
|
85
|
+
// a bright lip right at the front
|
|
86
|
+
metal *= 1.0 + 1.5 * (1.0 - smoothstep(0.0, 0.05, abs(d))) * step(0.0001, uLiqProgress) * step(uLiqProgress, ${CHROME} - 0.0001);
|
|
69
87
|
outgoingLight = mix(outgoingLight, metal, chrome);
|
|
70
88
|
}`,
|
|
71
89
|
};
|
|
@@ -73,21 +91,26 @@ function layerFor(st) {
|
|
|
73
91
|
export default defineOperation({
|
|
74
92
|
value: 'liquidMetal',
|
|
75
93
|
label: 'Liquid metal',
|
|
76
|
-
description: 'Turn the targets to chrome and melt them into a rippling pool — reverting pulls them back into shape',
|
|
94
|
+
description: 'Turn the targets to chrome and melt them into a rippling pool (or, Disappear off, keep them as chrome) — reverting pulls them back into shape',
|
|
77
95
|
channel: 'visual',
|
|
78
96
|
multi: true,
|
|
79
97
|
toggles: true,
|
|
80
|
-
usableIn: ['interaction', 'action'],
|
|
98
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
99
|
+
objectParams: { disappear: false },
|
|
100
|
+
presence: 'paint',
|
|
81
101
|
params: {
|
|
102
|
+
direction: { type: 'select', label: 'Direction', default: 'up', options: DIRECTION_OPTIONS, hint: 'How the chrome comes in' },
|
|
82
103
|
tint: { type: 'color', label: 'Metal', default: '#dfe7ee' },
|
|
83
|
-
|
|
104
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object turns to chrome and stays' },
|
|
105
|
+
spread: { type: 'number', label: 'Pool size', default: 1, min: 0.2, max: 3, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
84
106
|
duration: { type: 'number', label: 'Duration', default: 3.4, min: 0.3, max: 12, step: 0.1, unit: 's' },
|
|
85
107
|
},
|
|
86
|
-
apply(target, p) {
|
|
108
|
+
apply(target, p, ctx) {
|
|
87
109
|
let st = target.userData[STATE];
|
|
88
110
|
if (!st) {
|
|
89
111
|
const field = createFieldState(target);
|
|
90
|
-
|
|
112
|
+
field.edgeWidth.value = 0.04;
|
|
113
|
+
const own = { field, tint: { value: new Color() }, spread: { value: 1 }, keep: { value: 0 }, mats: new Set() };
|
|
91
114
|
// ripples keep moving while it lies melted
|
|
92
115
|
own.tick = () => { own.field.time.value += gsap.ticker.deltaRatio() / 60; syncRoot(target, own.field); };
|
|
93
116
|
const layer = layerFor(own);
|
|
@@ -102,16 +125,22 @@ export default defineOperation({
|
|
|
102
125
|
target.userData[STATE] = st;
|
|
103
126
|
}
|
|
104
127
|
const s = st;
|
|
128
|
+
setFieldParams(s.field, p, target, ctx);
|
|
105
129
|
s.tint.value.set(String(p.tint));
|
|
106
130
|
s.spread.value = Number(p.spread);
|
|
131
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
132
|
+
// keep: only the chrome comes in (the melt is off), then it holds — its own ticker keeps the time running
|
|
133
|
+
if (s.keep.value)
|
|
134
|
+
return runProgress(target, s.field, 1, { duration: Number(p.duration) * CHROME * 1.5, ease: 'none', clock: false });
|
|
107
135
|
return runProgress(target, s.field, 1, { duration: Number(p.duration), ease: 'power1.inOut', clock: false });
|
|
108
136
|
},
|
|
109
137
|
revert(target, p) {
|
|
110
138
|
const s = target.userData[STATE];
|
|
111
139
|
if (!s)
|
|
112
140
|
return;
|
|
141
|
+
setReveal(s.field, p);
|
|
113
142
|
return runProgress(target, s.field, 0, {
|
|
114
|
-
duration: Number(p.duration), ease: 'power1.inOut', clock: false,
|
|
143
|
+
duration: Number(p.duration) * (s.keep.value ? CHROME * 1.5 : 1) * Math.min(1, Math.max(0.1, s.field.progress.value)), ease: s.keep.value ? 'none' : 'power1.inOut', clock: false,
|
|
115
144
|
onComplete: () => {
|
|
116
145
|
gsap.ticker.remove(s.tick);
|
|
117
146
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particleSwarm.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/particleSwarm.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"particleSwarm.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/particleSwarm.ts"],"names":[],"mappings":";AAoCA,wBAwHG"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// rotation (inner rings faster, like a disc). While it is on, the swarm keeps
|
|
5
5
|
// turning. Reverting pulls every particle back to its exact spot and the
|
|
6
6
|
// surface closes behind them.
|
|
7
|
+
// With Disappear off (an object effect's default) the object stays as a particle
|
|
8
|
+
// cloud in its own shape: every particle on its spot, twinkling and breathing.
|
|
7
9
|
import { gsap } from 'gsap';
|
|
8
10
|
import { defineOperation } from '../types.js';
|
|
9
11
|
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
@@ -18,17 +20,19 @@ const FLIGHT = 0.5;
|
|
|
18
20
|
export default defineOperation({
|
|
19
21
|
value: 'particleSwarm',
|
|
20
22
|
label: 'Particle swarm',
|
|
21
|
-
description: 'Break the targets into their own coloured particles that swirl around them — reverting reassembles',
|
|
23
|
+
description: 'Break the targets into their own coloured particles that swirl around them (or, Disappear off, stay as a particle cloud) — reverting reassembles',
|
|
22
24
|
channel: 'visual',
|
|
23
25
|
multi: true,
|
|
24
26
|
toggles: true,
|
|
25
|
-
usableIn: ['interaction', 'action'],
|
|
27
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
28
|
+
objectParams: { disappear: false },
|
|
26
29
|
params: {
|
|
27
30
|
direction: { type: 'select', label: 'Direction', default: 'up', options: DIRECTION_OPTIONS },
|
|
31
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object stays as a cloud of particles in its own shape' },
|
|
28
32
|
particles: { type: 'number', label: 'Particles', default: 30000, min: 2000, max: 120000, step: 1000 },
|
|
29
33
|
particleSize: { type: 'number', label: 'Particle size', default: 1, min: 0.2, max: 4, step: 0.1, unit: '×' },
|
|
30
|
-
spread: { type: 'number', label: 'Spread', default: 1, min: 0.3, max: 3, step: 0.05, unit: '×', hint: 'Radius of the vortex' },
|
|
31
|
-
speed: { type: 'number', label: 'Swirl speed', default: 1, min: 0, max: 4, step: 0.05, unit: '×' },
|
|
34
|
+
spread: { type: 'number', label: 'Spread', default: 1, min: 0.3, max: 3, step: 0.05, unit: '×', hint: 'Radius of the vortex', showWhen: { disappear: ['true'] } },
|
|
35
|
+
speed: { type: 'number', label: 'Swirl speed', default: 1, min: 0, max: 4, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
32
36
|
edgeColor: { type: 'color', label: 'Edge colour', default: '#9fe8ff' },
|
|
33
37
|
glow: { type: 'boolean', label: 'Glow', default: true, hint: 'Additive light — off keeps the true surface colours' },
|
|
34
38
|
duration: { type: 'number', label: 'Duration', default: 2.8, min: 0.3, max: 12, step: 0.1, unit: 's' },
|
|
@@ -39,16 +43,19 @@ export default defineOperation({
|
|
|
39
43
|
const field = createFieldState(target);
|
|
40
44
|
field.edgeWidth.value = 0.05;
|
|
41
45
|
field.scale.value = 2.5;
|
|
42
|
-
const flight = { value: FLIGHT }, spread = { value: 1 }, speed = { value: 1 }, size = { value: 1 };
|
|
46
|
+
const flight = { value: FLIGHT }, spread = { value: 1 }, speed = { value: 1 }, size = { value: 1 }, keep = { value: 0 };
|
|
43
47
|
const sample = sampleSurfaceCached(target, Math.round(Number(p.particles)), 11);
|
|
44
48
|
const points = createFxPoints(target, sample, {
|
|
45
49
|
additive: !!p.glow,
|
|
46
|
-
uniforms: { ...fieldUniforms(P, field), uSwmFlight: flight, uSwmSpread: spread, uSwmSpeed: speed, uSwmPtSize: size },
|
|
50
|
+
uniforms: { ...fieldUniforms(P, field), uSwmFlight: flight, uSwmSpread: spread, uSwmSpeed: speed, uSwmPtSize: size, uSwmKeep: keep },
|
|
47
51
|
vertexPars: fieldGlsl(P) + GLSL_POINT_SIZE,
|
|
48
52
|
vertexMain: /* glsl */ `
|
|
49
53
|
float birth = ${P}BirthOf(${P}Field(${P}Norm(aP)));
|
|
50
54
|
float a = clamp((uSwmProgress - birth) / uSwmFlight, 0.0, 1.0);
|
|
51
55
|
if (a <= 0.0) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; vColor = vec3(0.0); vAlpha = 0.0; return; }
|
|
56
|
+
// keep: the particle appears on its spot and stays there
|
|
57
|
+
float held = uSwmKeep * step(0.9999, uSwmProgress);
|
|
58
|
+
a = mix(a, min(a, 0.001), uSwmKeep);
|
|
52
59
|
float E = uSwmExtent;
|
|
53
60
|
vec3 C = u${P}Min + u${P}Size * 0.5;
|
|
54
61
|
// destination: a tilted two-arm spiral galaxy around the object's centre.
|
|
@@ -71,19 +78,22 @@ export default defineOperation({
|
|
|
71
78
|
vec3 ctrl = aP + aN * (0.25 * E) + vec3(0.0, 0.12 * E, 0.0);
|
|
72
79
|
float k = a * a * (3.0 - 2.0 * a);
|
|
73
80
|
vec3 local = mix(mix(aP, ctrl, k), mix(ctrl, D, k), k);
|
|
81
|
+
// holding as a cloud: particles jitter on their spots, the whole cloud breathes
|
|
82
|
+
local += held * (aN * E * 0.004 * sin(u${P}Time * (2.0 + 2.0 * aR.w) + aR.z * 40.0));
|
|
83
|
+
local = C + (local - C) * (1.0 + held * 0.012 * sin(u${P}Time * 0.9));
|
|
74
84
|
vec4 mv = modelViewMatrix * vec4(local, 1.0);
|
|
75
85
|
gl_Position = projectionMatrix * mv;
|
|
76
86
|
// the colour of the spot it left, brighter in flight, a slow shimmer in the vortex
|
|
77
87
|
float flightGlow = sin(3.14159 * a);
|
|
78
88
|
float shimmer = 0.85 + 0.15 * sin(u${P}Time * (1.0 + 2.0 * aR.w) + aR.z * 6.2832);
|
|
79
89
|
vColor = aC * (1.0 + 0.4 * flightGlow) * shimmer + u${P}EdgeColor * 0.25 * flightGlow * flightGlow;
|
|
80
|
-
vAlpha = smoothstep(0.0, 0.08, a);
|
|
90
|
+
vAlpha = mix(smoothstep(0.0, 0.08, a), 0.75 + 0.25 * sin(u${P}Time * (3.0 + 4.0 * aR.x) + aR.y * 50.0), uSwmKeep);
|
|
81
91
|
gl_PointSize = clamp(fxPointPx(E * 0.0045 * uSwmPtSize * (0.6 + 0.8 * aR.w), mv), 0.0, 20.0);`,
|
|
82
92
|
});
|
|
83
93
|
const own = {};
|
|
84
94
|
// while the swarm exists it keeps turning, even after the transition finished
|
|
85
95
|
const tick = () => { own.field.time.value += gsap.ticker.deltaRatio() / 60; syncRoot(target, own.field); };
|
|
86
|
-
Object.assign(own, { field, flight, spread, speed, size, points, mats: new Set(), tick });
|
|
96
|
+
Object.assign(own, { field, flight, spread, speed, size, keep, points, mats: new Set(), tick });
|
|
87
97
|
st = own;
|
|
88
98
|
const layer = surfaceLayer(P, field, 'tint');
|
|
89
99
|
forEachMeshMaterial(target, (mat, mesh) => {
|
|
@@ -100,6 +110,15 @@ export default defineOperation({
|
|
|
100
110
|
s.spread.value = Number(p.spread);
|
|
101
111
|
s.speed.value = Number(p.speed);
|
|
102
112
|
s.size.value = Number(p.particleSize);
|
|
113
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
114
|
+
setMeshesHidden(target, false);
|
|
115
|
+
if (s.keep.value) {
|
|
116
|
+
// keep: the surface becomes its particles (0 → 1) and holds — its own ticker keeps the time running
|
|
117
|
+
return runProgress(target, s.field, 1, {
|
|
118
|
+
duration: Number(p.duration) / (1 + FLIGHT), ease: 'none', clock: false,
|
|
119
|
+
onComplete: () => setMeshesHidden(target, true),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
103
122
|
return runProgress(target, s.field, 1 + FLIGHT, {
|
|
104
123
|
duration: Number(p.duration), ease: 'power1.inOut', clock: false,
|
|
105
124
|
onComplete: () => setMeshesHidden(target, true),
|
|
@@ -110,8 +129,9 @@ export default defineOperation({
|
|
|
110
129
|
if (!s)
|
|
111
130
|
return;
|
|
112
131
|
setMeshesHidden(target, false);
|
|
132
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
113
133
|
return runProgress(target, s.field, 0, {
|
|
114
|
-
duration: Number(p.duration), ease: 'power1.inOut', clock: false,
|
|
134
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / (1 + FLIGHT))), ease: s.keep.value ? 'none' : 'power1.inOut', clock: false,
|
|
115
135
|
onComplete: () => {
|
|
116
136
|
gsap.ticker.remove(s.tick);
|
|
117
137
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"petalPeel.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/petalPeel.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"petalPeel.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/petalPeel.ts"],"names":[],"mappings":";AAwBA,wBA2IG"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// rocking tumble — and settles flat on the ground around the base. The flakes
|
|
5
5
|
// are real lit, double-sided instances (one instanced mesh, casting shadows).
|
|
6
6
|
// Reverting lifts them back into place and the surface closes.
|
|
7
|
+
// With Disappear off (an object effect's default) the object stays "lifted": every
|
|
8
|
+
// flake hinged up off the surface like raised scales, breathing in slow waves.
|
|
7
9
|
import { CircleGeometry } from 'three';
|
|
8
10
|
import { defineOperation } from '../types.js';
|
|
9
11
|
import { GLSL_ROT, addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
@@ -17,16 +19,18 @@ const LIFE = 0.8;
|
|
|
17
19
|
export default defineOperation({
|
|
18
20
|
value: 'petalPeel',
|
|
19
21
|
label: 'Petal peel',
|
|
20
|
-
description: 'Peel the targets into flakes that flutter down like leaves — reverting lifts them back',
|
|
22
|
+
description: 'Peel the targets into flakes that flutter down like leaves (or, Disappear off, stay lifted like raised scales) — reverting lifts them back',
|
|
21
23
|
channel: 'visual',
|
|
22
24
|
multi: true,
|
|
23
25
|
toggles: true,
|
|
24
|
-
usableIn: ['interaction', 'action'],
|
|
26
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
27
|
+
objectParams: { disappear: false },
|
|
25
28
|
params: {
|
|
26
29
|
direction: { type: 'select', label: 'Direction', default: 'down', options: DIRECTION_OPTIONS },
|
|
30
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the flakes stay lifted off the surface, like raised scales' },
|
|
27
31
|
petals: { type: 'number', label: 'Petals', default: 2600, min: 300, max: 20000, step: 100 },
|
|
28
32
|
petalSize: { type: 'number', label: 'Petal size', default: 1, min: 0.3, max: 4, step: 0.05, unit: '×' },
|
|
29
|
-
drift: { type: 'number', label: 'Drift', default: 1, min: 0, max: 4, step: 0.05, unit: '×', hint: 'How far they sway and scatter' },
|
|
33
|
+
drift: { type: 'number', label: 'Drift', default: 1, min: 0, max: 4, step: 0.05, unit: '×', hint: 'How far they sway and scatter', showWhen: { disappear: ['true'] } },
|
|
30
34
|
edgeColor: { type: 'color', label: 'Edge colour', default: '#fff1d6' },
|
|
31
35
|
scale: { type: 'number', label: 'Pattern', default: 2.5, min: 0.5, max: 12, step: 0.1 },
|
|
32
36
|
duration: { type: 'number', label: 'Duration', default: 4, min: 0.3, max: 14, step: 0.1, unit: 's' },
|
|
@@ -36,7 +40,7 @@ export default defineOperation({
|
|
|
36
40
|
if (!st) {
|
|
37
41
|
const field = createFieldState(target);
|
|
38
42
|
field.edgeWidth.value = 0.04;
|
|
39
|
-
const life = { value: LIFE }, drift = { value: 1 };
|
|
43
|
+
const life = { value: LIFE }, drift = { value: 1 }, keep = { value: 0 };
|
|
40
44
|
const count = Math.round(Number(p.petals));
|
|
41
45
|
const sample = sampleSurfaceCached(target, count, 47);
|
|
42
46
|
// petal size from the surface area each one has to cover
|
|
@@ -54,7 +58,7 @@ export default defineOperation({
|
|
|
54
58
|
},
|
|
55
59
|
layerKey: 'petalInstances', roughness: 0.7, metalness: 0, doubleSided: true,
|
|
56
60
|
layer: {
|
|
57
|
-
uniforms: { ...fieldUniforms(P, field), uPdlLife: life, uPdlDrift: drift },
|
|
61
|
+
uniforms: { ...fieldUniforms(P, field), uPdlLife: life, uPdlDrift: drift, uPdlKeep: keep },
|
|
58
62
|
common: fieldGlsl(P) + GLSL_ROT,
|
|
59
63
|
vertexPars: /* glsl */ `
|
|
60
64
|
attribute vec3 aPdlP; attribute vec3 aPdlN; attribute vec4 aPdlR;
|
|
@@ -78,12 +82,22 @@ export default defineOperation({
|
|
|
78
82
|
mat3 lying = fxRot(vec3(0.0, 1.0, 0.0), aPdlR.y * 6.28) * mat3(1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
|
|
79
83
|
float settle = smoothstep(land, land + 0.06, a);
|
|
80
84
|
return mat3(mix(inAir[0], lying[0], settle), mix(inAir[1], lying[1], settle), mix(inAir[2], lying[2], settle));
|
|
81
|
-
}
|
|
82
|
-
|
|
85
|
+
}
|
|
86
|
+
// lifted (keep): hinged up off the surface, breathing in slow waves across the object
|
|
87
|
+
float pdlLift(float a) {
|
|
88
|
+
float held = uPdlKeep * step(0.9999, uPdlProgress);
|
|
89
|
+
float wave = sin(uPdlTime * 1.1 + dot(aPdlP, vec3(1.0, 0.6, 0.3)) / uPdlExtent * 7.0 + aPdlR.x * 0.8);
|
|
90
|
+
return smoothstep(0.0, 0.14, a) * (0.5 + held * 0.14 * wave);
|
|
91
|
+
}
|
|
92
|
+
mat3 pdlLifted(float a) { return pdlFrame() * fxRot(vec3(1.0, 0.0, 0.0), pdlLift(a)); }`,
|
|
93
|
+
normal: `{ objectNormal = (uPdlKeep > 0.5 ? pdlLifted(pdlAge()) : pdlRot(pdlAge())) * objectNormal; }`,
|
|
83
94
|
vertex: /* glsl */ `
|
|
84
95
|
{
|
|
85
96
|
float a = pdlAge();
|
|
86
97
|
if (a <= 0.0) { transformed *= 0.0; }
|
|
98
|
+
else if (uPdlKeep > 0.5) {
|
|
99
|
+
transformed = pdlLifted(a) * transformed + aPdlN * (0.012 * uPdlExtent) * smoothstep(0.0, 0.14, a);
|
|
100
|
+
}
|
|
87
101
|
else {
|
|
88
102
|
a = min(a, 1.0);
|
|
89
103
|
float E = uPdlExtent;
|
|
@@ -101,7 +115,7 @@ export default defineOperation({
|
|
|
101
115
|
}`,
|
|
102
116
|
},
|
|
103
117
|
});
|
|
104
|
-
st = { field, life, drift, mesh, mats: new Set() };
|
|
118
|
+
st = { field, life, drift, keep, mesh, mats: new Set() };
|
|
105
119
|
const own = st;
|
|
106
120
|
const layer = surfaceLayer(P, field, 'tint');
|
|
107
121
|
forEachMeshMaterial(target, (mat, m) => {
|
|
@@ -115,6 +129,15 @@ export default defineOperation({
|
|
|
115
129
|
const s = st;
|
|
116
130
|
setFieldParams(s.field, p, target, ctx);
|
|
117
131
|
s.drift.value = Number(p.drift);
|
|
132
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
133
|
+
hideMeshes(target, KEY, false);
|
|
134
|
+
if (s.keep.value) {
|
|
135
|
+
// keep: the surface lifts into flakes (0 → 1) and holds
|
|
136
|
+
return runProgress(target, s.field, 1, {
|
|
137
|
+
duration: Number(p.duration) / (1 + LIFE), ease: 'none', hold: true,
|
|
138
|
+
onComplete: () => hideMeshes(target, KEY, true),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
118
141
|
return runProgress(target, s.field, 1 + LIFE, {
|
|
119
142
|
duration: Number(p.duration), ease: 'none',
|
|
120
143
|
onComplete: () => hideMeshes(target, KEY, true),
|
|
@@ -125,8 +148,9 @@ export default defineOperation({
|
|
|
125
148
|
if (!s)
|
|
126
149
|
return;
|
|
127
150
|
hideMeshes(target, KEY, false);
|
|
151
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
128
152
|
return runProgress(target, s.field, 0, {
|
|
129
|
-
duration: Number(p.duration), ease: 'none',
|
|
153
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / (1 + LIFE))), ease: 'none',
|
|
130
154
|
onComplete: () => {
|
|
131
155
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
132
156
|
disposeFxInstances(s.mesh);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/portal.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/portal.ts"],"names":[],"mappings":";AA6IA,wBAiGG"}
|