I think this is a fairly simple, accurate and elegant approach. He uses a strategy of separation and conquest. Start with just 2 values:
Calculate the midpoint. The offset, which in the middle means the value of variance (which can be calculated relative to the length). An offset should ideally be normal for a vector connecting the beginning and the end, but you can be cheap by making this offset horizontal if your bolts move mostly vertically, like real lightning. Repeat the above procedure for both (start, offset_mid) and (offset_mid, end), but this time use a smaller number for variance . This is a recursive approach that can end when either the threshold variance or the length of the threshold line segment is reached. When the recursion is unwound, you can draw all segments of the connector. The idea is that the greatest variance occurs at the center of the bolt (when the distance from the beginning to the end is the longest), and with each recursive call, the distance between the points decreases, as well as the variance. Thus, the global dispersion of the bolt will be much larger than any local deviations (for example, a real lightning bolt).
Here are 3 different bolts generated from the same predefined points using this algorithm. These points are (250 100) and (500 800). If you want the bolts to move in any direction (and not just “mostly vertical”), you need to add extra complexity to the point shift code by moving both X and Y by the angle of the bolt.

And here is some java code for this approach. I used ArrayList , since the divide and conquer approach does not know in advance how many elements it will finish.
// play with these values to fine-tune the appearance of your bolt private static final double VAR_FACTOR = 0.40; private static final double VAR_DECREASE = 0.55; private static final int MIN_LENGTH = 50; public static ArrayList<Point> buildBolt(Point start, Point end) { ArrayList<Point> bolt = new ArrayList<Point>(); double dx = start.getX() - end.getX(); double dy = start.getY() - end.getY(); double length = Math.sqrt(dx*dx + dy*dy); double variance = length * VAR_FACTOR; bolt.add(start); buildBolt(start, end, bolt, variance); return bolt; } private static void buildBolt(Point start, Point end, List<Point> bolt, double variance) { double dx = start.getX() - end.getX(); double dy = start.getY() - end.getY(); double length = Math.sqrt(dx*dx + dy*dy); if (length > MIN_LENGTH) { int varX = (int) ((Math.random() * variance * 2) - variance); int midX = (start.x + end.x)/2 + varX; int midY = (start.y + end.y)/2; Point mid = new Point(midX, midY); buildBolt(start, mid, bolt, variance * VAR_DECREASE); buildBolt(mid, end, bolt, variance * VAR_DECREASE); } else { bolt.add(end); } return; }