I have a problem in animating the lights path of the line. Basically what I want to happen here is that… there is one-animation in bottom-face-edges of the box. And two-loop animation in side-face-edges of the box. I’m not sure if this is TSL shader problem or the logic in edges… can anyone help me into this?
I can’t fix it… I want to repeat the loop in left-side-face of edges of the box. Check the image for you to be able to understand it… as you can see I don’t want the lights to fade. i want it to keep continuing but it does not.
Here is the code. Anyhelp would do thanks!
const TSLBoxLoader = () => {
// 12 edges with manually assigned t values so the light travels in order
const edgeGeo = useMemo(() => {
const h = 0.325;
// Define Bottom vertices (b) and Top vertices (t)
const b0 = [-h, -h, -h]; // Bottom Back-Left
const b1 = [h, -h, -h]; // Bottom Back-Right
const b2 = [h, -h, h]; // Bottom Front-Right
const b3 = [-h, -h, h]; // Bottom Front-Left
const t0 = [-h, h, -h]; // Top Back-Left
const t1 = [h, h, -h]; // Top Back-Right
const t2 = [h, h, h]; // Top Front-Right
const t3 = [-h, h, h]; // Top Front-Left
// The exact sequence: Bottom -> Yo-Yo the Sides -> Top
const sequence = [
// ── Bottom × 1 ──────────────────────────
b0, b1, b2, b3, b0,
// ── Left side × 2 ───────────────────────
// Pass 1: b0 → up → across top → down → back
t0, t3, b3, b0,
// Pass 2: repeat the same left-side loop
t0, t3, b3, b0,
];
const edges = [];
// Connect the dots into segment pairs
for (let i = 0; i < sequence.length - 1; i++) {
edges.push([...sequence[i], ...sequence[i + 1]]);
}
const positions = [];
const lineTVals = [];
const totalSegments = edges.length;
edges.forEach((e, i) => {
positions.push(e[0], e[1], e[2], e[3], e[4], e[5]);
// lineT smoothly travels from 0 to 1 across this exact path
lineTVals.push(i / totalSegments, (i + 1) / totalSegments);
});
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geo.setAttribute('lineT', new THREE.Float32BufferAttribute(lineTVals, 1));
return geo;
}, []);
const items = useMemo(() => {
return [0, 1, 2].map(() => {
const prog = uniform(0.0)
const lineTAttr = attribute('lineT', 'float')
// How far behind the travelling head is this vertex?
// delta = 0 at the head, grows going backward
const delta = fract(prog.sub(lineTAttr).add(1.0))
const tailLen = float(0.28)
// Bright tail: 1 at head → 0 at tail end
const brightness = smoothstep(tailLen, float(0.0), delta)
// Extra white-hot flare right at the head
const headFlare = smoothstep(float(0.04), float(0.0), delta)
const cyan = color(0x00e5ff)
const white = color(0xffffff)
const dimBase = color(0x001a26) // faint outline so box reads when idle
const mat = new THREE.LineBasicNodeMaterial()
mat.colorNode = mix(dimBase, mix(cyan, white, headFlare), brightness)
mat.transparent = true
mat.side = THREE.DoubleSide
return { mat, prog }
})
}, [])
useFrame(({ clock }) => {
const t = clock.elapsedTime
items.forEach(({ prog }, i) => {
// Each box offset by 1/3 of the cycle so they stagger
prog.value = (t * 0.09 + i * (1 / 3)) % 1
})
})
return (
<>
<group>
{[-1.1, 0, 1.1].map((x, i) => (
// Tilt each box to a nice isometric-ish angle so depth is visible
<lineSegments
key={i}
position={[x, 0, 0]}
rotation={[0.5, 0.7, 0]}
material={items[i].mat}
>
<primitive object={edgeGeo} attach="geometry" />
</lineSegments>
))}
</group>
<OrbitControls />
</>
)
}

