In the sequence, gravity is disabled so when the alien is shot, the acid floats freely. The acid spins along the corridor and forms a tunnel with an open center, leaving room for characters to move through. For this article I re-created the setup and broke it down into smaller, reusable components for future reference.

The acid should read as directional and stringy, like a hand reaching out. It moves slowly, feels dangerous, and drifts through space.



The most important parameters are scale and surface tension. Scene scale usually needs to be larger than real world to preserve small details. I use a top wedging workflow to find suitable liquid values.

Wedging the velocity noise size and surface tension to find the right look



string wedge_list[] = split(chs("wedge_list")," ");
for(int i=0; i<len(wedge_list);i++){
int id = addpoint(0,set(0,0,0));
setpointattrib(0,"wedge",id,wedge_list[i]);
}
Other useful resource for surface tension: https://medium.com/@vupham_37726/houdini-flip-surface-tension-demystified-f1239da880ce
While FLIP simulation provides detailed fluid animation, procedural post-sim advection gives greater control for composition and layout.
Applying a ramp to the advected field scales the deformation by distance from the core. This creates organic motion but can over-distort if run too long. A common approach is to use two advection passes: one that moves the whole piece for large scale movement and a second per-point advection for finer deformation.
Using a static VDB advect point to set initial positions and an animated VDB advect point for motion works well:

vector4 original_orient = p@orient;
matrix3 m = qconvert(original_orient);
prerotate(m,radians(ch("amount")*@rotate_speed*(@Frame+ch("frame_offset"))),chv("rotate"));
p@orient = quaternion(m);
This builds the velocity field from a curve, useful for both simulation and post-sim deformation:



curve_vel_field wrangle:
// runs on volume with vector field vel
int prim;
vector primuv;
float radius = ch("radius");
float dist = xyzdist(1,v@P,prim,primuv);
vector N = primuv(1,"N",prim,primuv);
vector P = primuv(1,"P",prim,primuv);
//prep
float r_normalize = fit(dist,0,radius,0,1);
float mask = (dist>radius)? 0:1;
//follow
vector follow_dir = normalize(N);
float follow_mult = ch("follow_mult");
float follow_ramp_r = chramp("follow_ramp_radius",r_normalize);
// suction
vector suction_dir = normalize(P-v@P);
float suction_mult = ch("suction_mult");
float suction_ramp_r = chramp("suction_ramp_radius",r_normalize);
// orbit
vector orbit_dir = normalize(cross(follow_dir,suction_dir));
float orbit_mult = ch("orbit_mult");
float orbit_ramp_r = chramp("orbit_ramp_radius",r_normalize);
v@vel = follow_dir*follow_mult*follow_ramp_r;
v@vel += suction_dir*suction_mult*suction_ramp_r;
v@vel += orbit_dir*orbit_mult*orbit_ramp_r;
v@vel *= mask;