Cuneiform tablet

Neo-Assyrian cuneiform, if you absolutely have to be anal about it

Reference images:
(mostly, Epic of Gilgamesh tablets)
penn.museum/sites/journal/550/
biblicalarchaeology.…-gilgamesh-epic-.jpg
britishmuseum.org/collection/object/w_k-3375
pixels.com/featured/…on-westmoreland.html

Log in to post a comment.

const seed = 4536; // min=1, max=10000, step=1
const symbol_h = 6; // min=4, max=12, step=1
const tablet = 1; // min=0, max=1, step=1 (full screen, broken tablet)
const n_columns = 2; // min=1, max=3, step=1

Canvas.setpenopacity(1);

const t = new Turtle();


let cur_rand = seed;
function rand_int() { cur_rand = (cur_rand * 48271) % (2**31 - 1); return cur_rand; }
function rand_bool() { return rand_int() % 2 == 0; }
function rand_float() { return rand_int() / (2**31 - 1); }


function draw_arc(x1, y1, x2, y2, deg) {
    let rad = deg * Math.PI / 180;
    
    let dx = x2 - x1, dy = y2 - y1;
    let phi = Math.atan2(dy, dx);
    let d = Math.sqrt(dx * dx + dy * dy);
    
    let rot = (phi * 180 / Math.PI) - (180 - deg/2) ;
    let r = (d / 2) / Math.sin(rad/2);
    
    t.jump(x1, y1);
    t.seth(rot);
    t.circle(r, -deg);
}

function draw_wedge(x, y, w, h, stem, rotate) {
    let rot = rotate * Math.PI / 180;
    let h1 = stem ? h/3 : h;
    
    let x1 = x - w/2 * Math.cos(rot), y1 = y - w/2 * Math.sin(rot);
    let x2 = x + h1 * Math.sin(rot), y2 = y - h1 * Math.cos(rot);
    let x3 = x + w/2 * Math.cos(rot), y3 = y + w/2 * Math.sin(rot);
    let x4 = x + h * Math.sin(rot), y4 = y - h * Math.cos(rot); 
    
    draw_arc(x1, y1, x2, y2, 90);
    draw_arc(x2, y2, x3, y3, 45);
    draw_arc(x3, y3, x1, y1, 45);
    
    if (stem) {
        t.jump(x2, y2);
        t.goto(x4, y4);
    }
}

const N_types = 6;

function draw_symbol(x, y, h, type, max_w=200) {
    var W;
    
    switch (type) {
        case 0: // vert 1 row
            let n0 = 1 + rand_int() % 4;
            
            W = n0 * h/3;
            
            if (W <= max_w) {
                for (let i = 0; i < n0; i++) {
                    draw_wedge(x + h/3 * i, y, h/3, h, true, 180);
                }
            }
            
            break;

        case 1: // hor 1 row
            W = h;
            
            if (W <= max_w) {
                let n1 = 1 + rand_int() % 3;

                for (let i = 0; i < n1; i++) {
                    draw_wedge(x, y + h/(n1 + 1) * (i + 1), h/3, h, true, 90);
                }
            }
            
            break;
            
        case 2: // hor 1 row + vert 1 row
            W = h;

            if (W <= max_w) {
                let n21 = 1 + rand_int() % 3;

                for (let i = 0; i < n21; i++) {
                    draw_wedge(x, y + h/(n21 + 1) * (i + 1), h/3, h, true, 90);
                }

                let n20 = 1 + rand_int() % 2;
            
                for (let i = 0; i < n20; i++) {
                    draw_wedge(x + h/3 + h*2/3/(n20 + 1) * (i + 1), y, h/3, h, true, 180);
                }
            }

            break;
            
        case 3: // vert 2 rows
            let n31 = 1 + rand_int() % 4;
            let n32 = 1 + rand_int() % 4;
            let n3 = Math.max(n31, n32);

            W = n3 * h/3;
            
            if (W <= max_w)
            {
                for (let i = 0; i < n31; i++) {
                    draw_wedge(x + h/3 * n3 / (n31 + 1) * (i + 1), y + h/3 - h/6, h/3, h/3, false, 180);
                }

                for (let i = 0; i < n32; i++) {
                    draw_wedge(x + h/3 * n3 / (n32 + 1) * (i + 1), y + 2*h/3 - h/6, h/3, h/3, false, 180);
                }
            }

            break;

        case 4: // hor 2 rows
            W = 2 * h/3;
            
            if (W <= max_w) {
                let n41 = 1 + rand_int() % 4;
                let n42 = 1 + rand_int() % 4;
                let n4 = Math.max(n41, n42);
    
                for (let i = 0; i < n41; i++) {
                    draw_wedge(x, y + h/3 * n4 / (n41 + 1) * (i + 1), h/3, h/3, false, 90);
                }
    
                for (let i = 0; i < n42; i++) {
                    draw_wedge(x + h/3, y + h/3 * n4 / (n42 + 1) * (i + 1), h/3, h/3, false, 90);
                }
            }

            break;
            
        case 5: // blank
            if (rand_float() < 0.15) {
                W = h * (1 + 2.5 * rand_float());
            }
            else {
                W = 0;
            }
            
            break;
            
        default:
            W = 0;
    }
    
    return W;
}


let x_left = [];
for (let y = 0; y <= 200; y++) {
    x_left[y] = -100;
}

let frame = 5;

if (tablet == 1) {
    for (let y = 0; y <= 200; y++) {
        x_left[y] += frame;
    }

    var x1, y1, x2, y2;
    let corner = rand_int() % 2;
    
    switch (corner) {
        case 0:
            x1 = -100 + frame;
            y1 = -100 + frame + 20 + 40 * rand_float();
            x2 = -100 + frame + 60 + 80 * rand_float();
            y2 = -100 + frame;
            
            t.jump(x2, y2);
            t.goto(+100 - frame, -100 + frame);
            t.goto(+100 - frame, +100 - frame);
            t.goto(-100 + frame, +100 - frame);
            t.goto(x1, y1);
            break;

        case 1:
            x1 = -100 + frame;
            y1 = +100 - frame - 20 - 40 * rand_float();
            x2 = -100 + frame + 60 + 80 * rand_float();
            y2 = +100 - frame;

            t.jump(x1, y1);
            t.goto(-100 + frame, -100 + frame);
            t.goto(+100 - frame, -100 + frame);
            t.goto(+100 - frame, +100 - frame);
            t.goto(x2, y2);
            break;
    }
    
    stack = [];
    stack.push([x1, y1, x2, y2]);
    
    while (stack.length > 0) {
        var sx1, sy1, sx2, sy2;
        [sx1, sy1, sx2, sy2] = stack.pop();
        
        if ((Math.abs(sy1 - sy2) < 0.5) && (Math.abs(sx1 - sx2) < 0.5)) {
            let ymin = Math.floor(Math.min(sy1, sy2)) + 100;

            x_left[ymin] = Math.max(x_left[ymin], sx1, sx2);

            t.jump(sx1, sy1);
            t.goto(sx2, sy2)
        }
        else {
            let cy = (sy1 + sy2) / 2;
            let cx = (sx1 + sx2) / 2 + Math.abs(sx1 - sx2) * 0.2 * (1 - 2 * rand_float());
            
            stack.push([sx1, sy1, cx, cy]);
            stack.push([cx, cy, sx2, sy2]);
        }
    }
}

let h = symbol_h;
let gap_h = h/4;
let gap_v = h/10;
let gap_c = h;
let H = Math.floor((200 - 2 * frame) / (h + gap_h));
let prev_type = -1;
let prev_w = -1;

for (let y = 0; y < H; y++) {
    let y0 = -100 + gap_h + y * (h + gap_h) + frame;

    for (let c = 0; c < n_columns; c++) {
        let x0 = -100 + (200 - gap_c * (n_columns - 1)) / n_columns * c + gap_c * c;
        let x1 = x0 + (200 - gap_c * (n_columns - 1)) / n_columns;
        
        x0 = Math.max(x0, x_left[Math.floor(y0) + 100] + gap_h, x_left[Math.floor(y0 + h + gap_h) + 100] + gap_h);
        
        if (tablet == 1) {
            x1 = Math.min(x1, 100 - frame);
        }
        
        while (x0 < x1) {
            let type = rand_int() % N_types;
            if (type == prev_type) {
                type = (type + 1 + N_types) % N_types;
            }
            
            let max_w = x1 - x0;
    
            prev_w = draw_symbol(x0, y0, h, type, max_w);
    
            if (type != 5) { // not blank
                prev_type = type;
            }
     
            x0 += prev_w
            
            if (prev_w != 0) {
                x0 += gap_h
            }
        }
    }
}