We are quieter than we used to be. I did come across a good Text Adventure tutorial way back, when trying to learn C#, it might have the kind of logic you're looking for. https://www.3dbuzz.com/training/view/xna-volume-1/hyperion-text-adventure-game
It is in their XNA section, but actually just uses core Visual C# and a console project.
If I recall, it goes along the lines of treating it as entering rooms and areas. So rather than scenes, you are traversing across different rooms and that would be where player choice comes into it. Perhaps think of it like programming a Point and Click Adventure without the graphics. You have different exits and each room will contain various items, people and you can have a description of each, including the scene.
If you are translating that into a story, you would perhaps follow the same principle, but each "exit" is a different path the player can take in the story. Maybe think of it like a grid or a tree, how a player can traverse. Hmm, maybe if you are branching, maybe take some inspiration from Git? Given it is a version control program that focuses on a branched approach, might put you in the right frame of mind? Maybe if you are programming it, you could include "BRANCH" into your array.
It can potentially get more and more complicated you branch, depending on how complicated you're wanting to work the story logic.
The other approach could be to work in a 2D or 3D grid and traverse the story as you would in a 2D or 3D space, but I think that's more traditional text adventures rather than a visual novel branching.
But in taking the inspiration from Git Branching. Here is a visual representation:
And this is how you might lay it out in your story?
I guess programmatically, you'll want to still create an array, but for the branch, I wonder if we can store it as a float or a string. I suspect this will be the difficult part with arrays.
I might look at it from dealing with objects (if you're thinking DBP, you can simulate something that works with a similar logic using custom data types, but just takes more work to get running, as you can only store variables this way and not methods). So instead of "Scene 1, Frame 1" go for:
Scene1.Branch(1.2) = "Hello world, is it me you're looking for?"
In my head, the above is actually a method, rather than an array or variable.
In fact, I would probably break it down like this;
Scene1.AddBranch(float BranchID, string Frame)
currentFrame = Scene1.GetBranch(float BranchID)
In "AddBranch" you can have a fallback, should your Branch ID already exist, throw up an error, so you don't end up with accidentally creating a duplicate. You'll have an array you can insert into and store a float, perhaps into something like "Branch[0].id". Then add the string for the part of the story you want.
In "GetBranch" you pull out the string you need to progress the next part of the story.
So an active example might be:
Scene1.AddBranch(1.1, "Hello world, is it me you're looking for?")
Scene1.AddBranch(1.12 "Okay then...")
currentFrame = Scene1.GetBranch(1.1)
if (player.input = "Go Away Lionel") then currentFrame = Scene1.GetBranch(1.12)
If each frame can be labelled, you could replace the floats with strings, but I figure in branching, floats might be easier to some extent, especially if you've got a reference for each bit for it to make sense. I guess it could end up more complicated with each part, but I guess it can be tweaked to get less confusing, as I'd imagine 1.3311234221 would be harder to follow. I know Git has a label & an ID for branches, so maybe it'll make more sense that way. At least the pseudo code above can easily be made to work that way, as "Get Branch" searches for an ID by a value and not by asking for a specific ID.