There’s a little slight-of-hand maneuver you can try that’s hard to explain, but works pretty well. The key point is using two equal length segments of time, the one starting at time zero and the other ending at time zero (i.e. a segment that starts before time zero). Then you use linear() to blend them so that at the start you’re using the segment that starts at time zero, but by the end of the cycle you’re using the segment that ends at time zero – returning you to your starting point. Here’s an example for an opacity expression using noise();
cycle = 2;
t = time % cycle;
amp = 50;
x = position[0];
y = position[1];
z = time;
xCompress = 200;
yCompress = 200;
zCompress = .2;
noiseVal1 = noise([x / xCompress, y / yCompress, t / zCompress]);
noiseVal2 = noise([x / xCompress, y / yCompress, (t – cycle) / zCompress]);
50 + amp * linear(t, 0, cycle, noiseVal1, noiseVal2)
By the way, you can use this technique to loop other things (like wiggle()) that don’t normally loop easily.
Dan