@3driseai/3drise-viewer 0.1.29 → 0.1.30
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 +4 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +66 -2
- package/dist/animationsV2/clipUtils.js +1 -1
- package/dist/animationsV2/sequenceUtils.d.ts +5 -0
- package/dist/animationsV2/sequenceUtils.d.ts.map +1 -1
- package/dist/animationsV2/sequenceUtils.js +10 -0
- package/dist/animationsV2/types.d.ts +6 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- 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/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +6 -17
- package/dist/components/ParticlesGenerator.d.ts.map +1 -1
- package/dist/components/ParticlesGenerator.js +44 -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/SkyStars.d.ts.map +1 -1
- package/dist/components/SkyStars.js +83 -2
- package/dist/components/TextGenerator.d.ts.map +1 -1
- package/dist/components/TextGenerator.js +3 -2
- package/dist/components/index.d.ts +1 -8
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -4
- 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/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/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/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -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/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 +1 -1
- package/dist/triggers/hosts/interactions.d.ts.map +1 -1
- package/dist/triggers/hosts/interactions.js +1 -1
- 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/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
|
@@ -9,10 +9,12 @@ import { createPlayback } from './engine/playback.js';
|
|
|
9
9
|
import { VARIANTS } from './engine/variants.js';
|
|
10
10
|
import { layoutOutline, layoutStrokeFont } from './engine/glyphs.js';
|
|
11
11
|
import { loadOutline, loadStrokes } from './fonts/index.js';
|
|
12
|
+
import { extentOf } from './engine/methods.js';
|
|
13
|
+
import { stopRaycast } from '../../utils/pickProxy.js';
|
|
12
14
|
/** One em of the font in world units: the object's own size, so a text of 0.5 m high default. The parent transform does the rest. */
|
|
13
15
|
export const TEXT_EM = 0.5;
|
|
14
16
|
// Keys that are not look knobs.
|
|
15
|
-
const BASE_KEYS = new Set(['type', '
|
|
17
|
+
const BASE_KEYS = new Set(['type', 'shown', 'text', 'font', 'drawMethod', 'drawDuration', 'drawEase', 'drawStagger', 'drawAngle',
|
|
16
18
|
'eraseMethod', 'eraseDuration', 'eraseEase', 'eraseStagger', 'eraseAngle', 'autoPlay', 'loop', 'yoyo', 'holdTime', 'hiddenTime']);
|
|
17
19
|
/** Animation keys that bake a schedule into the geometry: a change rebuilds. */
|
|
18
20
|
const ANIM_STRUCTURAL = ['drawMethod', 'drawStagger', 'drawAngle', 'eraseMethod', 'eraseStagger', 'eraseAngle'];
|
|
@@ -36,6 +38,8 @@ export function useTextObject(look, props) {
|
|
|
36
38
|
const S = staticOf(look);
|
|
37
39
|
const rootRef = useRef(null);
|
|
38
40
|
const innerRef = useRef(null);
|
|
41
|
+
// Hover / click land on one plane over the text's box (em units, inside the em-scaled group), never on a letter.
|
|
42
|
+
const proxyRef = useRef(null);
|
|
39
43
|
const cfg = useMemo(() => withConfigDefaults(DEFAULT_TEXT_OBJECTS[look], config), [config, look]);
|
|
40
44
|
useObjectReady(rootRef, cfg, onObjectReady, onObjectDispose);
|
|
41
45
|
const cfgRef = useRef(cfg);
|
|
@@ -71,10 +75,18 @@ export function useTextObject(look, props) {
|
|
|
71
75
|
const now = cfgRef.current;
|
|
72
76
|
syncAnim(now);
|
|
73
77
|
built = V.build(layout, lookCfg(now), anim.current);
|
|
78
|
+
stopRaycast(built.object);
|
|
74
79
|
innerRef.current.add(built.object);
|
|
75
80
|
inst.current = built;
|
|
81
|
+
const e = extentOf(layout.strokes);
|
|
82
|
+
const pad = 0.12; // em: a little air around the glyphs
|
|
83
|
+
const proxy = proxyRef.current;
|
|
84
|
+
if (proxy) {
|
|
85
|
+
proxy.position.set((e.x0 + e.x1) / 2, (e.y0 + e.y1) / 2, 0);
|
|
86
|
+
proxy.scale.set(e.w + 2 * pad, e.h + 2 * pad, 1);
|
|
87
|
+
}
|
|
76
88
|
pb.current.reset(anim.current);
|
|
77
|
-
if (now.
|
|
89
|
+
if (now.shown === false)
|
|
78
90
|
pb.current.hide();
|
|
79
91
|
});
|
|
80
92
|
return () => { dead = true; if (built) {
|
|
@@ -84,24 +96,24 @@ export function useTextObject(look, props) {
|
|
|
84
96
|
inst.current = null;
|
|
85
97
|
} };
|
|
86
98
|
}, [look, rebuildKey, lookCfg, syncAnim]);
|
|
87
|
-
// `
|
|
88
|
-
const prev = useRef({
|
|
99
|
+
// `shown` is the trigger: on draws, off erases (then stays hidden). Loop / yoyo restart the cycle.
|
|
100
|
+
const prev = useRef({ shown: cfg.shown, loop: cfg.loop, yoyo: cfg.yoyo });
|
|
89
101
|
useEffect(() => {
|
|
90
102
|
const p = prev.current;
|
|
91
|
-
const
|
|
103
|
+
const changedShown = p.shown !== cfg.shown;
|
|
92
104
|
const changedPlay = p.loop !== cfg.loop || p.yoyo !== cfg.yoyo;
|
|
93
|
-
prev.current = {
|
|
105
|
+
prev.current = { shown: cfg.shown, loop: cfg.loop, yoyo: cfg.yoyo };
|
|
94
106
|
if (!inst.current)
|
|
95
107
|
return;
|
|
96
|
-
if (
|
|
97
|
-
if (cfg.
|
|
108
|
+
if (changedShown) {
|
|
109
|
+
if (cfg.shown === false)
|
|
98
110
|
pb.current.playErase(anim.current);
|
|
99
111
|
else
|
|
100
112
|
pb.current.restart(anim.current);
|
|
101
113
|
}
|
|
102
|
-
else if (changedPlay && cfg.
|
|
114
|
+
else if (changedPlay && cfg.shown !== false)
|
|
103
115
|
pb.current.restart(anim.current);
|
|
104
|
-
}, [cfg.
|
|
116
|
+
}, [cfg.shown, cfg.loop, cfg.yoyo]);
|
|
105
117
|
const scale = useMemo(() => new THREE.Vector3(), []);
|
|
106
118
|
useFrame((state, dt) => {
|
|
107
119
|
const i = inst.current;
|
|
@@ -114,5 +126,5 @@ export function useTextObject(look, props) {
|
|
|
114
126
|
root.getWorldScale(scale);
|
|
115
127
|
i.update(st, state.clock.elapsedTime, px * Math.abs(scale.x) * TEXT_EM);
|
|
116
128
|
});
|
|
117
|
-
return { rootRef, innerRef };
|
|
129
|
+
return { rootRef, innerRef, proxyRef };
|
|
118
130
|
}
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,aAqBhC,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -17,6 +17,8 @@ export const SELF_MANAGED_MATERIAL = new Set([
|
|
|
17
17
|
'environment',
|
|
18
18
|
// Land objects draw with the terrain material (TERRAIN_PATCH).
|
|
19
19
|
'land',
|
|
20
|
+
// Text looks (plain, handwriting, neon…) draw with their own shaders; 3d text is a mesh and takes a material.
|
|
21
|
+
'text',
|
|
20
22
|
// The water surface owns its shader — one material for both hosts, built
|
|
21
23
|
// around the wave field. Left out of this set, useMaterialApplication
|
|
22
24
|
// overwrites it with whatever the registry has under materialType, which for
|
package/dist/index.d.ts
CHANGED
|
@@ -15,13 +15,13 @@ export { cameraManager } from './utils/CameraSingleton';
|
|
|
15
15
|
export { applyAnchorSettings, createCurves, createSunPosition, randomRange, } from './utils/utils3d';
|
|
16
16
|
export { applyAnchorSettings as applyAnchorSettingsLegacy } from './utils/anchorUtils';
|
|
17
17
|
export * from './utils/shapes';
|
|
18
|
+
export * from './utils/pickProxy';
|
|
18
19
|
export { hasHoverAnimation } from './utils/hasHoverAnimation';
|
|
19
20
|
export { findById } from './utils/sceneQuery';
|
|
20
21
|
export { hasFrameRenderer, registerFrameRenderer, renderFrame } from './utils/frameRenderer';
|
|
21
22
|
export type { FrameRenderer } from './utils/frameRenderer';
|
|
22
23
|
export { resolveObject3D } from './utils/resolveObject3D';
|
|
23
24
|
export type { Object3DRefLike, Object3DSource } from './utils/resolveObject3D';
|
|
24
|
-
export * from './utils/textEffects';
|
|
25
25
|
export { applyTerrainUniforms, applyTerrainTextures } from './utils/terrainUniforms';
|
|
26
26
|
export { useTerrainTextures } from './hooks/useTerrainTextures';
|
|
27
27
|
export { terrainHeightAt } from './utils/terrainHeight';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAG5F,cAAc,SAAS,CAAC;AAGxB,cAAc,cAAc,CAAC;AAG7B,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,MAAM,CAAC;AACrB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE7N,YAAY,EAAE,oBAAoB,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAGjG,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,GAAG,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,mBAAmB,IAAI,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC/E,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -18,11 +18,11 @@ export { cameraManager } from './utils/CameraSingleton.js';
|
|
|
18
18
|
export { applyAnchorSettings, createCurves, createSunPosition, randomRange, } from './utils/utils3d.js';
|
|
19
19
|
export { applyAnchorSettings as applyAnchorSettingsLegacy } from './utils/anchorUtils.js';
|
|
20
20
|
export * from './utils/shapes.js';
|
|
21
|
+
export * from './utils/pickProxy.js';
|
|
21
22
|
export { hasHoverAnimation } from './utils/hasHoverAnimation.js';
|
|
22
23
|
export { findById } from './utils/sceneQuery.js';
|
|
23
24
|
export { hasFrameRenderer, registerFrameRenderer, renderFrame } from './utils/frameRenderer.js';
|
|
24
25
|
export { resolveObject3D } from './utils/resolveObject3D.js';
|
|
25
|
-
export * from './utils/textEffects.js';
|
|
26
26
|
export { applyTerrainUniforms, applyTerrainTextures } from './utils/terrainUniforms.js';
|
|
27
27
|
export { useTerrainTextures } from './hooks/useTerrainTextures.js';
|
|
28
28
|
export { terrainHeightAt } from './utils/terrainHeight.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flock.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/flock.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"flock.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/flock.ts"],"names":[],"mappings":";AA+CA,wBAyJG"}
|
|
@@ -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"}
|