TesserActions

Fun little Tesseract turtle.

Note: You can add up to 4 cubes. If you only have 2 cubes, the controls for Cube3 & Cube4 will do nothing.

Enjoy, and please share your variants!

Log in to post a comment.

// ============================================================
// ARCHITECTURAL RULED CUBES — V6.0
// TurtleToy / Pen Plotter Friendly
//
// MASTER VERSION:
//   cubeCount = 2, 3, or 4
//
// Active cubes:
//   2 cubes = Cube 1 + Cube 4
//   3 cubes = Cube 1 + Cube 2 + Cube 4
//   4 cubes = Cube 1 + Cube 2 + Cube 3 + Cube 4
//
// ORIENTATION MODES:
//
//   0 = Free XYZ
//   1 = Square
//   2 = Z snap 15°
//   3 = Z snap 22.5°
//   4 = Z snap 30°
//   5 = Z snap 45°
//   6 = XYZ snap 15°
//   7 = XYZ snap 22.5°
//
// Modes 1-5 preserve architectural integrity.
// Modes 6-7 allow deliberate snapped 3D tilting.
//
// All geometry is straight-line / plotter friendly.
// ============================================================

Canvas.setpenopacity(1);

const turtle = new Turtle();


// ============================================================
// MASTER CONTROLS
// ============================================================

const cubeCount = 3;             // min=2 max=4 step=1

const size = 58;                 // min=35 max=70 step=1


// Projection mode:
//
// 0 = Free
// 1 = Reference / Architectural
// 2 = Strong Axonometric
//
const projectionMode = 1;        // min=0 max=2 step=1


// Used only when Projection Mode = 0

const depthX = 0.42;             // min=0.10 max=0.70 step=0.01
const depthY = -0.31;            // min=-0.65 max=-0.05 step=0.01
const perspective = 0.00;        // min=0 max=0.12 step=0.005


// Surface controls

const localSheets = 1;           // min=0 max=1 step=1
const connectionSheets = 1;      // min=0 max=1 step=1
const centerMesh = 1;            // min=0 max=1 step=1
const crossHatch = 1;            // min=0 max=1 step=1


// Connection complexity:
//
// 1 = main architectural sheets
// 2 = + corner fans
// 3 = + depth sheets
//
const connectionComplexity = 3;  // min=1 max=3 step=1

const connectionDensity = 1.00;  // min=0.40 max=1.50 step=0.05

const patternPhase = 0;          // min=0 max=3 step=1


// ============================================================
// FRAME CONTROLS
// ============================================================

const frames = 1;                // min=0 max=1 step=1
const thickFrames = 1;           // min=0 max=1 step=1

// Very closely spaced 3D lines.
// These should visually merge into a heavier edge.

const framePasses = 9;           // min=1 max=13 step=2

const frameRadius = 0.0020;      // min=0 max=0.008 step=0.0005


// ============================================================
// CUBE 1 — OUTER
// ============================================================

const cube1Size = 1.00;          // min=0.85 max=1.10 step=0.01

const cube1Orientation = 1;      // min=0 max=7 step=1

const cube1RotX = 0;             // min=-90 max=90 step=0.5
const cube1RotY = 0;             // min=-90 max=90 step=0.5
const cube1RotZ = 0;             // min=-90 max=90 step=0.5

const cube1OffsetX = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube1OffsetY = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube1OffsetZ = 0.00;       // min=-0.30 max=0.30 step=0.005

const cube1Lines = 28;           // min=6 max=50 step=1


// ============================================================
// CUBE 2 — PRIMARY MIDDLE
// ============================================================

const cube2Size = 0.62;          // min=0.40 max=0.82 step=0.01

// Default = perfectly clean 22.5° Z rotation

const cube2Orientation = 3;      // min=0 max=7 step=1

const cube2RotX = 0;             // min=-90 max=90 step=0.5
const cube2RotY = 0;             // min=-90 max=90 step=0.5
const cube2RotZ = -22.5;         // min=-90 max=90 step=0.5

const cube2OffsetX = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube2OffsetY = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube2OffsetZ = 0.00;       // min=-0.30 max=0.30 step=0.005

const cube2Lines = 23;           // min=6 max=50 step=1


// ============================================================
// CUBE 3 — SECOND MIDDLE
//
// Used only when cubeCount = 4.
// ============================================================

const cube3Size = 0.47;          // min=0.28 max=0.70 step=0.01

const cube3Orientation = 3;      // min=0 max=7 step=1

const cube3RotX = 0;             // min=-90 max=90 step=0.5
const cube3RotY = 0;             // min=-90 max=90 step=0.5
const cube3RotZ = 22.5;          // min=-90 max=90 step=0.5

const cube3OffsetX = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube3OffsetY = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube3OffsetZ = 0.00;       // min=-0.30 max=0.30 step=0.005

const cube3Lines = 20;           // min=6 max=50 step=1


// ============================================================
// CUBE 4 — INNER
// ============================================================

const cube4Size = 0.34;          // min=0.16 max=0.55 step=0.01

const cube4Orientation = 1;      // min=0 max=7 step=1

const cube4RotX = 0;             // min=-90 max=90 step=0.5
const cube4RotY = 0;             // min=-90 max=90 step=0.5
const cube4RotZ = 0;             // min=-90 max=90 step=0.5

const cube4OffsetX = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube4OffsetY = 0.00;       // min=-0.30 max=0.30 step=0.005
const cube4OffsetZ = 0.00;       // min=-0.30 max=0.30 step=0.005

const cube4Lines = 18;           // min=6 max=50 step=1


// ============================================================
// STORAGE
// ============================================================

const paths = [];


function addLine(a, b) {

    paths.push([
        a,
        b
    ]);

}


function lerp(a, b, t) {

    return [

        a[0] + (b[0] - a[0]) * t,

        a[1] + (b[1] - a[1]) * t

    ];

}


// ============================================================
// 3D VECTOR MATH
// ============================================================

function add3(a, b) {

    return [

        a[0] + b[0],
        a[1] + b[1],
        a[2] + b[2]

    ];

}


function sub3(a, b) {

    return [

        a[0] - b[0],
        a[1] - b[1],
        a[2] - b[2]

    ];

}


function scale3(a, s) {

    return [

        a[0] * s,
        a[1] * s,
        a[2] * s

    ];

}


function length3(a) {

    return Math.sqrt(

        a[0] * a[0] +
        a[1] * a[1] +
        a[2] * a[2]

    );

}


function normalize3(a) {

    const len =
        length3(a);


    if (len < 0.0000001) {

        return [0, 0, 0];

    }


    return [

        a[0] / len,
        a[1] / len,
        a[2] / len

    ];

}


function cross3(a, b) {

    return [

        a[1] * b[2] - a[2] * b[1],

        a[2] * b[0] - a[0] * b[2],

        a[0] * b[1] - a[1] * b[0]

    ];

}


// ============================================================
// ROTATIONS
// ============================================================

function rotateX(p, degrees) {

    const a =
        degrees * Math.PI / 180;


    const c =
        Math.cos(a);


    const s =
        Math.sin(a);


    return [

        p[0],

        p[1] * c - p[2] * s,

        p[1] * s + p[2] * c

    ];

}


function rotateY(p, degrees) {

    const a =
        degrees * Math.PI / 180;


    const c =
        Math.cos(a);


    const s =
        Math.sin(a);


    return [

         p[0] * c + p[2] * s,

         p[1],

        -p[0] * s + p[2] * c

    ];

}


function rotateZ(p, degrees) {

    const a =
        degrees * Math.PI / 180;


    const c =
        Math.cos(a);


    const s =
        Math.sin(a);


    return [

        p[0] * c - p[1] * s,

        p[0] * s + p[1] * c,

        p[2]

    ];

}


// ============================================================
// ROTATION SNAPPING
// ============================================================

function snapAngle(value, increment) {

    return (

        Math.round(
            value / increment
        )

        *

        increment

    );

}


function resolveOrientation(
    mode,
    rx,
    ry,
    rz
) {

    // FREE XYZ

    if (mode === 0) {

        return [
            rx,
            ry,
            rz
        ];

    }


    // SQUARE

    if (mode === 1) {

        return [
            0,
            0,
            0
        ];

    }


    // Z ONLY — 15 DEGREE SNAP

    if (mode === 2) {

        return [

            0,
            0,

            snapAngle(
                rz,
                15
            )

        ];

    }


    // Z ONLY — 22.5 DEGREE SNAP

    if (mode === 3) {

        return [

            0,
            0,

            snapAngle(
                rz,
                22.5
            )

        ];

    }


    // Z ONLY — 30 DEGREE SNAP

    if (mode === 4) {

        return [

            0,
            0,

            snapAngle(
                rz,
                30
            )

        ];

    }


    // Z ONLY — 45 DEGREE SNAP

    if (mode === 5) {

        return [

            0,
            0,

            snapAngle(
                rz,
                45
            )

        ];

    }


    // FULL XYZ — 15 DEGREE SNAP

    if (mode === 6) {

        return [

            snapAngle(
                rx,
                15
            ),

            snapAngle(
                ry,
                15
            ),

            snapAngle(
                rz,
                15
            )

        ];

    }


    // FULL XYZ — 22.5 DEGREE SNAP

    return [

        snapAngle(
            rx,
            22.5
        ),

        snapAngle(
            ry,
            22.5
        ),

        snapAngle(
            rz,
            22.5
        )

    ];

}


// ============================================================
// PROJECTION
// ============================================================

function project(p) {

    let dx;
    let dy;
    let persp;


    // FREE

    if (projectionMode === 0) {

        dx =
            depthX;

        dy =
            depthY;

        persp =
            perspective;

    }


    // REFERENCE / ARCHITECTURAL

    else if (projectionMode === 1) {

        dx =
            0.42;

        dy =
            -0.31;

        persp =
            0;

    }


    // STRONG AXONOMETRIC

    else {

        dx =
            0.50;

        dy =
            -0.50;

        persp =
            0;

    }


    let x =

        p[0] +

        p[2] * dx;


    let y =

        p[1] +

        p[2] * dy;


    const factor =

        1 /

        (1 - p[2] * persp);


    return [

        x * factor * size,

        y * factor * size

    ];

}


// ============================================================
// BASE CUBE
// ============================================================

const base = [

    [-1,-1,-1], // 0
    [ 1,-1,-1], // 1
    [ 1, 1,-1], // 2
    [-1, 1,-1], // 3

    [-1,-1, 1], // 4
    [ 1,-1, 1], // 5
    [ 1, 1, 1], // 6
    [-1, 1, 1]  // 7

];


// ============================================================
// EDGES
// ============================================================

const edges = [

    [0,1], // 0 front bottom
    [1,2], // 1 front right
    [2,3], // 2 front top
    [3,0], // 3 front left

    [4,5], // 4 back bottom
    [5,6], // 5 back right
    [6,7], // 6 back top
    [7,4], // 7 back left

    [0,4], // 8 depth bottom-left
    [1,5], // 9 depth bottom-right
    [2,6], // 10 depth top-right
    [3,7]  // 11 depth top-left

];


const FRONT_BOTTOM = 0;
const FRONT_RIGHT  = 1;
const FRONT_TOP    = 2;
const FRONT_LEFT   = 3;

const BACK_BOTTOM  = 4;
const BACK_RIGHT   = 5;
const BACK_TOP     = 6;
const BACK_LEFT    = 7;

const DEPTH_BL     = 8;
const DEPTH_BR     = 9;
const DEPTH_TR     = 10;
const DEPTH_TL     = 11;


// ============================================================
// FACES
// ============================================================

const FRONT_FACE  = [0,1,2,3];
const BACK_FACE   = [4,5,6,7];

const LEFT_FACE   = [0,3,7,4];
const RIGHT_FACE  = [1,2,6,5];

const BOTTOM_FACE = [0,1,5,4];
const TOP_FACE    = [3,2,6,7];


// ============================================================
// BUILD CUBE
// ============================================================

function makeCube(
    cubeSize,
    orientationMode,
    rx,
    ry,
    rz,
    ox,
    oy,
    oz,
    lineCount
) {

    const orientation =
        resolveOrientation(

            orientationMode,

            rx,
            ry,
            rz

        );


    const finalX =
        orientation[0];

    const finalY =
        orientation[1];

    const finalZ =
        orientation[2];


    const p3 = [];
    const p2 = [];


    for (
        let i = 0;
        i < base.length;
        i++
    ) {

        let p = [

            base[i][0] * cubeSize,

            base[i][1] * cubeSize,

            base[i][2] * cubeSize

        ];


        p =
            rotateX(
                p,
                finalX
            );


        p =
            rotateY(
                p,
                finalY
            );


        p =
            rotateZ(
                p,
                finalZ
            );


        p[0] += ox;
        p[1] += oy;
        p[2] += oz;


        p3.push(
            p
        );


        p2.push(
            project(p)
        );

    }


    return {

        p3: p3,

        p2: p2,

        size: cubeSize,

        lines: lineCount

    };

}


// ============================================================
// CREATE ALL FOUR POSSIBLE CUBES
// ============================================================

const cube1 = makeCube(

    cube1Size,

    cube1Orientation,

    cube1RotX,
    cube1RotY,
    cube1RotZ,

    cube1OffsetX,
    cube1OffsetY,
    cube1OffsetZ,

    cube1Lines

);


const cube2 = makeCube(

    cube2Size,

    cube2Orientation,

    cube2RotX,
    cube2RotY,
    cube2RotZ,

    cube2OffsetX,
    cube2OffsetY,
    cube2OffsetZ,

    cube2Lines

);


const cube3 = makeCube(

    cube3Size,

    cube3Orientation,

    cube3RotX,
    cube3RotY,
    cube3RotZ,

    cube3OffsetX,
    cube3OffsetY,
    cube3OffsetZ,

    cube3Lines

);


const cube4 = makeCube(

    cube4Size,

    cube4Orientation,

    cube4RotX,
    cube4RotY,
    cube4RotZ,

    cube4OffsetX,
    cube4OffsetY,
    cube4OffsetZ,

    cube4Lines

);


// ============================================================
// ACTIVE CUBE LIST
// ============================================================

const cubes = [];


if (cubeCount === 2) {

    cubes.push(
        cube1
    );

    cubes.push(
        cube4
    );

}


else if (cubeCount === 3) {

    cubes.push(
        cube1
    );

    cubes.push(
        cube2
    );

    cubes.push(
        cube4
    );

}


else {

    cubes.push(
        cube1
    );

    cubes.push(
        cube2
    );

    cubes.push(
        cube3
    );

    cubes.push(
        cube4
    );

}


// ============================================================
// EDGE HELPER
// ============================================================

function getEdge(
    cube,
    edgeNumber
) {

    const e =
        edges[edgeNumber];


    return [

        cube.p2[e[0]],

        cube.p2[e[1]]

    ];

}


// ============================================================
// CORNER STRING-ART SHEET
// ============================================================

function cornerSheet(
    A,
    B,
    C,
    count,
    reverse
) {

    for (
        let i = 0;
        i <= count;
        i++
    ) {

        const t =
            i / count;


        let a =
            t;


        let b =
            1 - t;


        if (reverse) {

            a =
                1 - t;

            b =
                t;

        }


        addLine(

            lerp(
                A,
                B,
                a
            ),

            lerp(
                B,
                C,
                b
            )

        );

    }

}


// ============================================================
// RULED EDGE-TO-EDGE SHEET
// ============================================================

function ruledEdges(
    cubeA,
    edgeA,
    cubeB,
    edgeB,
    count,
    reverse
) {

    const A =
        getEdge(
            cubeA,
            edgeA
        );


    const B =
        getEdge(
            cubeB,
            edgeB
        );


    for (
        let i = 0;
        i <= count;
        i++
    ) {

        const t =
            i / count;


        const q =
            reverse
                ? 1 - t
                : t;


        addLine(

            lerp(
                A[0],
                A[1],
                t
            ),

            lerp(
                B[0],
                B[1],
                q
            )

        );

    }

}


// ============================================================
// VERTEX-TO-EDGE FAN
// ============================================================

function vertexFan(
    vertex,
    cube,
    edgeNumber,
    count,
    reverse
) {

    const E =
        getEdge(
            cube,
            edgeNumber
        );


    for (
        let i = 0;
        i <= count;
        i++
    ) {

        let t =
            i / count;


        if (reverse) {

            t =
                1 - t;

        }


        addLine(

            vertex,

            lerp(
                E[0],
                E[1],
                t
            )

        );

    }

}


// ============================================================
// LOCAL ARCHITECTURAL SHEETS
// ============================================================

function drawLocalSheets(
    cube,
    index
) {

    if (!localSheets)
        return;


    const c =
        cube.p2;


    const n =
        cube.lines;


    const phase =
        (index + patternPhase) % 4;


    if (phase === 0) {

        cornerSheet(
            c[4],
            c[7],
            c[6],
            n,
            false
        );


        cornerSheet(
            c[3],
            c[0],
            c[4],
            n,
            false
        );


        cornerSheet(
            c[2],
            c[6],
            c[5],
            n,
            true
        );


        cornerSheet(
            c[0],
            c[1],
            c[5],
            n,
            true
        );

    }


    else if (phase === 1) {

        cornerSheet(
            c[3],
            c[2],
            c[6],
            n,
            false
        );


        cornerSheet(
            c[0],
            c[4],
            c[5],
            n,
            true
        );


        cornerSheet(
            c[7],
            c[6],
            c[5],
            n,
            false
        );


        cornerSheet(
            c[3],
            c[0],
            c[1],
            n,
            true
        );

    }


    else if (phase === 2) {

        cornerSheet(
            c[4],
            c[7],
            c[3],
            n,
            false
        );


        cornerSheet(
            c[2],
            c[1],
            c[5],
            n,
            true
        );


        cornerSheet(
            c[0],
            c[4],
            c[5],
            n,
            false
        );


        cornerSheet(
            c[3],
            c[2],
            c[6],
            n,
            true
        );

    }


    else {

        cornerSheet(
            c[7],
            c[6],
            c[2],
            n,
            true
        );


        cornerSheet(
            c[3],
            c[0],
            c[4],
            n,
            false
        );


        cornerSheet(
            c[1],
            c[5],
            c[6],
            n,
            false
        );


        cornerSheet(
            c[0],
            c[1],
            c[2],
            n,
            true
        );

    }

}


// ============================================================
// MODULAR CUBE-TO-CUBE CONNECTION
// ============================================================

function drawConnection(
    outer,
    inner,
    connectionIndex
) {

    if (!connectionSheets)
        return;


    const n = Math.max(

        6,

        Math.round(

            (
                outer.lines +
                inner.lines
            )

            *

            0.5

            *

            connectionDensity

        )

    );


    const reverse =
        (
            connectionIndex +
            patternPhase
        ) % 2 === 0;


    // ========================================================
    // LEVEL 1
    // MAIN ARCHITECTURAL SURFACES
    // ========================================================

    ruledEdges(

        outer,
        BACK_TOP,

        inner,
        FRONT_TOP,

        n,

        reverse

    );


    ruledEdges(

        outer,
        FRONT_LEFT,

        inner,
        BACK_LEFT,

        n,

        !reverse

    );


    ruledEdges(

        outer,
        BACK_RIGHT,

        inner,
        FRONT_RIGHT,

        n,

        reverse

    );


    ruledEdges(

        outer,
        FRONT_BOTTOM,

        inner,
        BACK_BOTTOM,

        n,

        !reverse

    );


    // ========================================================
    // LEVEL 2
    // CORNER FANS
    // ========================================================

    if (connectionComplexity >= 2) {

        const O =
            outer.p2;


        vertexFan(

            O[7],

            inner,

            FRONT_TOP,

            n,

            false

        );


        vertexFan(

            O[6],

            inner,

            FRONT_RIGHT,

            n,

            true

        );


        vertexFan(

            O[0],

            inner,

            BACK_BOTTOM,

            n,

            false

        );


        vertexFan(

            O[1],

            inner,

            BACK_RIGHT,

            n,

            true

        );

    }


    // ========================================================
    // LEVEL 3
    // DEPTH SURFACES
    // ========================================================

    if (connectionComplexity >= 3) {

        const d =
            Math.max(

                6,

                Math.round(
                    n * 0.70
                )

            );


        ruledEdges(

            outer,
            DEPTH_TL,

            inner,
            FRONT_LEFT,

            d,

            !reverse

        );


        ruledEdges(

            outer,
            DEPTH_TR,

            inner,
            BACK_RIGHT,

            d,

            reverse

        );


        ruledEdges(

            outer,
            DEPTH_BL,

            inner,
            FRONT_BOTTOM,

            d,

            reverse

        );

    }

}


// ============================================================
// CENTER FACE HATCH
// ============================================================

function hatchFace(
    cube,
    face,
    count,
    cross
) {

    const A =
        cube.p2[face[0]];


    const B =
        cube.p2[face[1]];


    const C =
        cube.p2[face[2]];


    const D =
        cube.p2[face[3]];


    for (
        let i = 0;
        i <= count;
        i++
    ) {

        const t =
            i / count;


        addLine(

            lerp(
                A,
                B,
                t
            ),

            lerp(
                D,
                C,
                1 - t
            )

        );

    }


    if (cross) {

        for (
            let i = 0;
            i <= count;
            i++
        ) {

            const t =
                i / count;


            addLine(

                lerp(
                    A,
                    D,
                    t
                ),

                lerp(
                    B,
                    C,
                    1 - t
                )

            );

        }

    }

}


// ============================================================
// 3D FRAME MICRO-BUNDLE
//
// Multiple lines sit extremely close together in actual
// 3D space so they read as one stronger cube edge.
// ============================================================

function draw3DThickEdge(
    A,
    B
) {

    addLine(
        project(A),
        project(B)
    );


    if (
        !thickFrames ||
        framePasses <= 1 ||
        frameRadius <= 0
    ) {

        return;

    }


    const direction =

        normalize3(
            sub3(
                B,
                A
            )
        );


    let reference;


    if (
        Math.abs(
            direction[2]
        ) < 0.90
    ) {

        reference =
            [0, 0, 1];

    }

    else {

        reference =
            [0, 1, 0];

    }


    const U =

        normalize3(

            cross3(
                direction,
                reference
            )

        );


    const V =

        normalize3(

            cross3(
                direction,
                U
            )

        );


    const shellCount =
        framePasses - 1;


    for (
        let i = 0;
        i < shellCount;
        i++
    ) {

        const angle =

            Math.PI *

            2 *

            i /

            shellCount;


        const offset =

            add3(

                scale3(

                    U,

                    Math.cos(angle) *
                    frameRadius

                ),

                scale3(

                    V,

                    Math.sin(angle) *
                    frameRadius

                )

            );


        addLine(

            project(
                add3(
                    A,
                    offset
                )
            ),

            project(
                add3(
                    B,
                    offset
                )
            )

        );

    }

}


// ============================================================
// DRAW FRAME
// ============================================================

function drawFrame(
    cube
) {

    for (
        let i = 0;
        i < edges.length;
        i++
    ) {

        const e =
            edges[i];


        draw3DThickEdge(

            cube.p3[e[0]],

            cube.p3[e[1]]

        );

    }

}


// ============================================================
// BUILD LOCAL SHEETS
// ============================================================

for (
    let i = 0;
    i < cubes.length;
    i++
) {

    drawLocalSheets(
        cubes[i],
        i
    );

}


// ============================================================
// BUILD BETWEEN-CUBE SURFACES
// ============================================================

for (
    let i = 0;
    i < cubes.length - 1;
    i++
) {

    drawConnection(

        cubes[i],

        cubes[i + 1],

        i

    );

}


// ============================================================
// DENSE INNER CUBE
// ============================================================

if (
    centerMesh &&
    cubes.length > 0
) {

    const center =
        cubes[
            cubes.length - 1
        ];


    const n =
        center.lines;


    hatchFace(

        center,

        FRONT_FACE,

        n,

        crossHatch

    );


    hatchFace(

        center,

        TOP_FACE,

        Math.max(
            6,
            Math.round(
                n * 0.80
            )
        ),

        crossHatch

    );


    hatchFace(

        center,

        RIGHT_FACE,

        Math.max(
            6,
            Math.round(
                n * 0.80
            )
        ),

        crossHatch

    );

}


// ============================================================
// FRAMES LAST
// ============================================================

if (frames) {

    for (
        let i = 0;
        i < cubes.length;
        i++
    ) {

        drawFrame(
            cubes[i]
        );

    }

}


// ============================================================
// TURTLETOY WALK
// ============================================================

function walk(i) {

    if (
        i >= paths.length
    ) {

        return false;

    }


    const p =
        paths[i];


    turtle.jump(

        p[0][0],

        p[0][1]

    );


    turtle.goto(

        p[1][0],

        p[1][1]

    );


    return true;

}