I have spent quite some time looking into this (few hours) and it is not so simple to solve. BUT I do have a solution. That said, the solution is also not so simple.

Note, the blue polygon is just there to help explain what shape is being used for the clip-path of the group element <g id="Line_Orange" >
I did not attach this to the scroll event because I needed a way to work on the logic behind the clip-path polygon with the simplest set-up I could get and allow me to start and stop the setInterval()
to console.log()
out the current x and y values etc. to compute where the turns needed to occur etc.
The full example is here: https://codepen.io/Alexander9111/pen/eYmbajB
And the JavaScript is:
var running = false;
const g = document.querySelector("#Line_Orange");
const g_clone = g.cloneNode(true);
const svg = document.querySelector("svg");
g_clone.id = "Line_Grey";
//svg.appendChild(g_clone);
svg.insertBefore(g_clone, svg.childNodes[0]);
g.setAttribute('clip-path', "polygon(0 0, 0 100, 250 100, 250 0)");
const polygon = document.querySelector("#polygon_mask");
let segment_num = 0;
var temp_arr = [];
var polygon_points_arr = [80, 0, 80, 0];
var polygon_points_str = "80 0 80 0";
const polygon_segments = [
{
n: 0, dir: 1, progress: "y", boost: 1, init_x_y: [80,0], index: [3,5],
points:[80, 0, 80, 250, 250, 250, 250, 0]
},
{
n: 1, dir: 1, progress: "y", boost: 2, init_x_y: [80,100], index: [3,null],
points:[80, 0, 80, 250, 250, 100, 250, 0]
},
{
n: 2, dir: 1, progress: "x", boost: 2, init_x_y: [80,250], index: [4,null],
points:[80, 0, 80, 250, 250, 250, 250, 100, 250, 100, 250, 0]
},
{
n: 3, dir: 1, progress: "x", boost: 1, init_x_y: [250,100], index: [4,6],
points:[80, 0, 80, 250, 450, 250, 450, 100, 250, 100, 250, 0]
},
{
n: 4, dir: 1, progress: "x", boost: 2, init_x_y: [700,100], index: [null,6],
points:[80, 0, 80, 250, 700, 250, 820, 100, 250, 100, 250, 0]
},
{
n: 5, dir: 1, progress: "y", boost: 2, init_x_y: [820,100], index: [null,9],
points:[80, 0, 80, 250, 700, 250, 700, 250, 820, 100, 820, 100, 250, 100, 250, 0]
},
{
n: 6, dir: 1, progress: "y", boost: 1, init_x_y: [820,250], index: [7,9],
points:[80, 0, 80, 250, 700, 250, 700, 250, 820, 100, 820, 100, 250, 100, 250, 0]
},
{
n: 7, dir: 1, progress: "y", boost: 2, init_x_y: [820,600], index: [null,9],
points:[80, 0, 80, 250, 700, 250, 700, 600, 820, 600, 820, 100, 250, 100, 250, 0]
},
{
n: 8, dir: -1, progress: "x", boost: 2, init_x_y: [820,750], index: [null,10],
points:[80, 0, 80, 250, 700, 250, 700, 600, 700, 600, 820, 750, 820, 750, 820, 100, 250, 100, 250, 0]
},
{
n: 9, dir: -1, progress: "x", boost: 1, init_x_y: [700,750], index: [8,10],
points:[80, 0, 80, 250, 700, 250, 700, 600, 700, 600, 820, 750, 820, 750, 820, 100, 250, 100, 250, 0]
},
{
n: 10, dir: -1, progress: "x", boost: 2, init_x_y: [150,600], index: [10,null],
points:[80, 0, 80, 250, 700, 250, 700, 600, 150, 600, 150, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
},
{
n: 11, dir: 1, progress: "y", boost: 2, init_x_y: [0,600], index: [11,null],
points:[80, 0, 80, 250, 700, 250, 700, 600, 0, 600, 0, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
},
{
n: 12, dir: 1, progress: "y", boost: 1, init_x_y: [0,750], index: [11,13],
points:[80, 0, 80, 250, 700, 250, 700, 600, 0, 600, 0, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
}
];
var progressY = 0;
var progressX = 80;
const velocity = 1;
var boost = 1;
var direction = 1;
var timeInterval; //to be started at a later time
function myTimer() {
//console.log(progress);
direction = polygon_segments[segment_num].dir;
polygon_points_arr = polygon_segments[segment_num].points;
//console.log("null == 0", null == 0);
var progress = polygon_segments[segment_num].progress == "x" ? progressX : progressY;
var first_index = polygon_segments[segment_num].index[0];
var second_index = polygon_segments[segment_num].index[1];
if (first_index != null){
polygon_points_arr[first_index] = progress;
}
if (second_index != null){
polygon_points_arr[second_index] = progress;
}
polygon_points_arr.map((child, index) => {
if (index % 2 == 0 && index < polygon_points_arr.length - 1){
return child + ",";
} else {
return child
}
});
temp_arr = polygon_points_arr.map((el, index, arr) => {
if ((index + 1) % 2 == 0 && index < arr.length - 1){
return el + ",";
} else {
return el;
}
});
polygon_points_str = temp_arr.join(" ");
console.log(polygon_points_str);
function incrementAndSetValues(){
segment_num +=1;
boost = polygon_segments[segment_num].boost;
progressX = polygon_segments[segment_num].init_x_y[0];
progressY = polygon_segments[segment_num].init_x_y[1];
}
if (progressY>= 10000) {
clearInterval(timeInterval);
} else {
if (segment_num == 0) {
progressY += (velocity * boost * direction);
if (progressY >= 100) {
incrementAndSetValues()
}
} else if (segment_num == 1){
progressY += (velocity * boost * direction);
if (progressY >= 250) {
incrementAndSetValues()
}
console.log(segment_num);
} else if (segment_num == 2){
progressX += (velocity * boost * direction);
if (progressX >= 250) {
incrementAndSetValues()
}
} else if (segment_num == 3){
progressX += (velocity * boost * direction);
if (progressX >= 700) {
incrementAndSetValues()
}
} else if (segment_num == 4){
progressX += (velocity * boost * direction);
if (progressX >= 820) {
incrementAndSetValues()
}
} else if (segment_num == 5){
progressY += (velocity * boost * direction);
if (progressY >= 250) {
incrementAndSetValues()
}
} else if (segment_num == 6){
progressY += (velocity * boost * direction);
if (progressY >= 600) {
incrementAndSetValues()
}
} else if (segment_num == 7){
progressY += (velocity * boost * direction);
if (progressY >= 750) {
incrementAndSetValues()
}
} else if (segment_num == 8){
progressX += (velocity * boost * direction);
if (progressX <= 700) {
incrementAndSetValues()
}
} else if (segment_num == 9){
progressX += (velocity * boost * direction);
if (progressX <= 150) {
incrementAndSetValues()
}
} else if (segment_num == 10){
progressX += (velocity * boost * direction);
if (progressX <= 0) {
incrementAndSetValues()
}
} else if (segment_num == 11){
progressY += (velocity * boost * direction);
if (progressY >= 750) {
incrementAndSetValues()
}
} else if (segment_num == 12){
progressY += (velocity * boost * direction);
}
}
//console.log(segment_num);
g.setAttribute('clip-path', `polygon(${polygon_points_str})`);
polygon.setAttribute('points', polygon_points_str);
}
function myStopFunction() {
console.log("stop X,Y", progressX, progressY);
document.querySelector("#start").removeAttribute('disabled', true);
document.querySelector("#stop").setAttribute('disabled', true);
clearInterval(timeInterval);
running = false;
}
function myStartFunction() {
timeInterval = setInterval(myTimer, 10);
document.querySelector("#start").setAttribute('disabled', true);
document.querySelector("#stop").removeAttribute('disabled', true);
running = true;
}
document.querySelector("#start").addEventListener('click', myStartFunction);
document.querySelector("#stop").addEventListener('click', myStopFunction);
document.addEventListener('keydown', function(e){
console.log(e.code);
if (e.code == "Enter"){
if (running){
myStopFunction();
} else {
myStartFunction();
}
}
});
document.querySelector("#reset").addEventListener('click', function(){
progressY = 0.00;
progressX = 0.00;
segment_num = 0;
myTimer();
document.querySelector("#start").removeAttribute('disabled', true);
document.querySelector("#stop").removeAttribute('disabled', true);
});
document.addEventListener('DOMContentLoaded',
function(){
const g_grey = document.querySelector("#Line_Grey");
//console.log(g_grey);
const grey_paths = g_grey.querySelectorAll("path, polygon");
for (i = 0; i< grey_paths.length; i++) {
//console.log(grey_paths[i]);
if (grey_paths[i].getAttribute('fill') == "none"){
//do nothing
} else if (grey_paths[i].getAttribute('fill') != "#bbbbbb"){
//must be orange, change to grey
grey_paths[i].setAttribute('fill',"#bbbbbb");
}
}
myTimer();
}, false);
And the most important part of the JavaScript is this array:
const polygon_segments = [
{
n: 0, dir: 1, progress: "y", boost: 1, init_x_y: [80,0], index: [3,5],
points:[80, 0, 80, 250, 250, 250, 250, 0]
}, ...
There is a segment for each segment of the polygon, as it grows and becomes more complex.
This diagram should help explain that a little bit:

And this one, explaining how the polygon increases in the number of points:

Seems to work on my phone (chrome mobile). Well mostly. It’s got other problems but the animation follows the curve like you want.
I have updated my answer.
“How do I create a path for the entire animation and not just for the beginning?” The same way you got the design in the first place. Use a program to draw it.
“Also, when you turn the line, you can notice a white triangle at the bend point. How can this be fixed?” Tweak the mask path corner curves.
“How do I add gray lines until the line is filled with color?” In your original CodePen you are doing that by cloning the paths/groups. You can do the same thing here.
8 values in polygon 0 is because 4 points of x & y coordinates. So it’s like (x1 y1, x2 y2, x3 y3, x4 y4) and the index[3,5] means change index 3 and 5 of that array. i.e y2 and y3 – this is because at one time we move 1 or 2 of the points of the polygon as we progress down or across (if we have index[3,null] then it means only move y2 – this happens on the curves)