// Path: app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java
// public class TimeLine {
// 
//     private final double frameRate;
// 
//     private final Timeline fxTimeline;
// 
//     public TimeLine(double frameRate) {
//         this.frameRate = frameRate;
//         fxTimeline = new Timeline(frameRate);
//     }
// 
//     public double getFrameRate() {
//         return frameRate;
//     }
// 
//     public Timeline getFxTimeline() {
//         return fxTimeline;
//     }
// 
//     public void addKeyFrame(KeyFrame keyFrame, KeyValue fxKeyValue) {
//         fxTimeline.getKeyFrames().add(new javafx.animation.KeyFrame(
//                 duration(keyFrame), fxKeyValue));
//     }
// 
//     private Duration duration(KeyFrame keyFrame) {
//         return Duration.millis(1000d * keyFrame.getFrame() / frameRate);
//     }
// 
//     public void togglePause() {
//         switch (fxTimeline.getStatus()) {
//             case PAUSED:
//                 fxTimeline.play();
//                 break;
//             case RUNNING:
//                 fxTimeline.pause();
//                 break;
//             case STOPPED:
//                 fxTimeline.playFromStart();
//                 break;
//         }
//     }
// 
//     public void seekFrame(final int value) {
//         fxTimeline.pause();
//         final var offset = Duration.millis(1000d * Math.abs(value) / frameRate);
//         final var now = fxTimeline.getCurrentTime();
//         final var newDuration = value > 0 ? now.add(offset) : now.subtract(offset);
//         fxTimeline.jumpTo(newDuration);
//     }
// 
//     public void seek(final int sec) {
//         final var now = fxTimeline.getCurrentTime();
//         fxTimeline.jumpTo(now.add(Duration.seconds(sec)));
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/visual/VirtualScene.java
// public class VirtualScene {
// 
//     private final NodesGroup group;
// 
//     private final int virtualWidth, virtualHeight;
// 
//     public VirtualScene(NodesGroup group, int virtualWidth, int virtualHeight) {
//         this.group = group;
//         this.virtualWidth = virtualWidth;
//         this.virtualHeight = virtualHeight;
//     }
// 
//     public NodesGroup getGroup() {
//         return group;
//     }
// 
//     public int getVirtualWidth() {
//         return virtualWidth;
//     }
// 
//     public int getVirtualHeight() {
//         return virtualHeight;
//     }
// 
//     public void add(Node node) {
//         group.getChildren().add(node);
//     }
// }


import com.annimon.hotarufx.visual.TimeLine;
import com.annimon.hotarufx.visual.VirtualScene;
import com.annimon.hotarufx.visual.objects.*;
package com.annimon.hotarufx.visual.visitors;


public class RenderVisitor implements NodeVisitor<Void, VirtualScene> {

    private final TimeLine timeline;

// Path: app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java
// public class TimeLine {
// 
//     private final double frameRate;
// 
//     private final Timeline fxTimeline;
// 
//     public TimeLine(double frameRate) {
//         this.frameRate = frameRate;
//         fxTimeline = new Timeline(frameRate);
//     }
// 
//     public double getFrameRate() {
//         return frameRate;
//     }
// 
//     public Timeline getFxTimeline() {
//         return fxTimeline;
//     }
// 
//     public void addKeyFrame(KeyFrame keyFrame, KeyValue fxKeyValue) {
//         fxTimeline.getKeyFrames().add(new javafx.animation.KeyFrame(
//                 duration(keyFrame), fxKeyValue));
//     }
// 
//     private Duration duration(KeyFrame keyFrame) {
//         return Duration.millis(1000d * keyFrame.getFrame() / frameRate);
//     }
// 
//     public void togglePause() {
//         switch (fxTimeline.getStatus()) {
//             case PAUSED:
//                 fxTimeline.play();
//                 break;
//             case RUNNING:
//                 fxTimeline.pause();
//                 break;
//             case STOPPED:
//                 fxTimeline.playFromStart();
//                 break;
//         }
//     }
// 
//     public void seekFrame(final int value) {
//         fxTimeline.pause();
//         final var offset = Duration.millis(1000d * Math.abs(value) / frameRate);
//         final var now = fxTimeline.getCurrentTime();
//         final var newDuration = value > 0 ? now.add(offset) : now.subtract(offset);
//         fxTimeline.jumpTo(newDuration);
//     }
// 
//     public void seek(final int sec) {
//         final var now = fxTimeline.getCurrentTime();
//         fxTimeline.jumpTo(now.add(Duration.seconds(sec)));
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/visual/VirtualScene.java
// public class VirtualScene {
// 
//     private final NodesGroup group;
// 
//     private final int virtualWidth, virtualHeight;
// 
//     public VirtualScene(NodesGroup group, int virtualWidth, int virtualHeight) {
//         this.group = group;
//         this.virtualWidth = virtualWidth;
//         this.virtualHeight = virtualHeight;
//     }
// 
//     public NodesGroup getGroup() {
//         return group;
//     }
// 
//     public int getVirtualWidth() {
//         return virtualWidth;
//     }
// 
//     public int getVirtualHeight() {
//         return virtualHeight;
//     }
// 
//     public void add(Node node) {
//         group.getChildren().add(node);
//     }
// }


// Path: app/src/main/java/com/annimon/hotarufx/visual/visitors/RenderVisitor.java
import com.annimon.hotarufx.visual.TimeLine;
import com.annimon.hotarufx.visual.VirtualScene;
import com.annimon.hotarufx.visual.objects.*;

package com.annimon.hotarufx.visual.visitors;


public class RenderVisitor implements NodeVisitor<Void, VirtualScene> {

    private final TimeLine timeline;

    public RenderVisitor(TimeLine timeline) {