// examples/visualize.ling — Ling source → SVG pattern visualizer
// Usage: ling run examples/visualize.ling <input.ling> [output.svg]
//
// Generates a dark-themed SVG where each function in the source file
// becomes a geometric pattern panel — style inspired by AI crypto-fill.
// ─── Geometry helpers ────────────────────────────────────────────────────────
ฟังก์ชัน สีHSL(hue, sat, lit) {
ผูก r = ปัดลง(lit + sat * ไซน์(hue * 6.2832))
ผูก g = ปัดลง(lit + sat * ไซน์(hue * 6.2832 + 2.0944))
ผูก b = ปัดลง(lit + sat * ไซน์(hue * 6.2832 + 4.1888))
ผูก r = max(0.0, min(255.0, r))
ผูก g = max(0.0, min(255.0, g))
ผูก b = max(0.0, min(255.0, b))
คืน "rgb(" + to_str(r) + "," + to_str(g) + "," + to_str(b) + ")"
}
ฟังก์ชัน f(n) {
คืน to_str(ปัดลง(n * 10.0) / 10.0)
}
ฟังก์ชัน reg_mark(mx, my) {
ผูก sz = 10.0
ผูก s = "<circle cx='" + f(mx) + "' cy='" + f(my) + "' r='2.5' fill='#FFD700'/>"
ผูก s = s + "<line x1='" + f(mx - sz) + "' y1='" + f(my) + "' x2='" + f(mx + sz) + "' y2='" + f(my) + "' stroke='#FFD700' stroke-width='0.5'/>"
ผูก s = s + "<line x1='" + f(mx) + "' y1='" + f(my - sz) + "' x2='" + f(mx) + "' y2='" + f(my + sz) + "' stroke='#FFD700' stroke-width='0.5'/>"
คืน s
}
ฟังก์ชัน detect_vtex(body) {
ถ้า str_find(body, "vtex_rings") >= 0 { คืน "#00e5ff" }
ถ้า str_find(body, "vtex_flower") >= 0 { คืน "#ff79c6" }
ถ้า str_find(body, "vtex_spiral") >= 0 { คืน "#00ffb3" }
ถ้า str_find(body, "vtex_lotus") >= 0 { คืน "#ff5e8a" }
ถ้า str_find(body, "vtex_chakra") >= 0 { คืน "#bd93f9" }
ถ้า str_find(body, "vtex_yantra") >= 0 { คืน "#ffb86c" }
ถ้า str_find(body, "vtex_star") >= 0 { คืน "#ffd700" }
ถ้า str_find(body, "vtex_hyperbolic") >= 0 { คืน "#5575c8" }
ถ้า str_find(body, "vtex_tess") >= 0 { คืน "#50fa7b" }
ถ้า str_find(body, "vtex_grid") >= 0 { คืน "#8be9fd" }
ถ้า str_find(body, "vtex_halftone") >= 0 { คืน "#888899" }
ถ้า str_find(body, "vtex_letter_rain") >= 0 { คืน "#f1fa8c" }
ถ้า str_find(body, "audio_") >= 0 { คืน "#ff1493" }
ถ้า str_find(body, "camera") >= 0 { คืน "#ffe066" }
ถ้า str_find(body, "light") >= 0 { คืน "#ffe4b5" }
คืน "#6688aa"
}
// ─── Pattern generators (each returns an SVG fragment string) ────────────────
ฟังก์ชัน pat_dot_grid(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก rows = 5
ผูก cols = 6
ผูก r = 0
ขณะที่ r < rows {
ผูก c = 0
ขณะที่ c < cols {
ผูก t = (r * cols + c) / (rows * cols)
ผูก cx = ox + (c + 0.5) * w / cols
ผูก cy = oy + (r + 0.5) * h / rows
ผูก dr = 2.0 + 3.5 * ค่าสัมบูรณ์(ไซน์(t * 6.28 * 3.0 + phase * 9.42))
ผูก op = 0.35 + 0.65 * ค่าสัมบูรณ์(ไซน์(t * 6.28 + phase * 5.0))
ผูก s = s + "<circle cx='" + f(cx) + "' cy='" + f(cy) + "' r='" + f(dr) + "' fill='" + สี + "' opacity='" + f(op) + "'/>"
ผูก c = c + 1
}
ผูก r = r + 1
}
คืน s
}
ฟังก์ชัน pat_waveform(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก steps = 36
ผูก pts1 = ""
ผูก pts2 = ""
ผูก pts3 = ""
ผูก i = 0
ขณะที่ i <= steps {
ผูก t = i / steps
ผูก px = ox + t * w
ผูก sep = ถ้า i == 0 { "" } มิฉะนั้น { " " }
ผูก py1 = oy + h * 0.35 + h * 0.22 * ไซน์(t * 6.28 * 2.5 + phase * 12.56)
ผูก py2 = oy + h * 0.55 + h * 0.15 * ไซน์(t * 6.28 * 4.0 + phase * 18.84)
ผูก py3 = oy + h * 0.72 + h * 0.10 * ไซน์(t * 6.28 * 6.0 + phase * 25.0)
ผูก pts1 = pts1 + sep + f(px) + "," + f(py1)
ผูก pts2 = pts2 + sep + f(px) + "," + f(py2)
ผูก pts3 = pts3 + sep + f(px) + "," + f(py3)
ผูก i = i + 1
}
ผูก s = s + "<polyline points='" + pts1 + "' fill='none' stroke='" + สี + "' stroke-width='2' opacity='0.85'/>"
ผูก s = s + "<polyline points='" + pts2 + "' fill='none' stroke='" + สี + "' stroke-width='1.5' opacity='0.55'/>"
ผูก s = s + "<polyline points='" + pts3 + "' fill='none' stroke='" + สี + "' stroke-width='1' opacity='0.30'/>"
คืน s
}
ฟังก์ชัน pat_spectral_grid(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก rows = 8
ผูก cols = 8
ผูก r = 0
ขณะที่ r < rows {
ผูก c = 0
ขณะที่ c < cols {
ผูก t = (r * cols + c) / (rows * cols)
ผูก active = ไซน์(t * 6.28 * 7.0 + phase * 18.0 + r * 0.55 + c * 0.33) > 0.15
ผูก elem = ถ้า active {
"<rect x='" + f(ox + c * w / cols + 1.5) + "' y='" + f(oy + r * h / rows + 1.5) + "' width='" + f(w / cols - 3.0) + "' height='" + f(h / rows - 3.0) + "' fill='" + สี + "' opacity='" + f(0.25 + 0.55 * ค่าสัมบูรณ์(ไซน์(t * 6.28 + phase * 6.28))) + "' rx='2'/>"
} มิฉะนั้น {
""
}
ผูก s = s + elem
ผูก c = c + 1
}
ผูก r = r + 1
}
คืน s
}
ฟังก์ชัน pat_radial_rings(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก cx = ox + w * 0.5
ผูก cy = oy + h * 0.5
ผูก max_r = min(w, h) * 0.44
ผูก rings = 4
ผูก r = 1
ขณะที่ r <= rings {
ผูก rad = max_r * r / rings
ผูก n_dots = 6 + r * 4
ผูก d = 0
ขณะที่ d < n_dots {
ผูก angle = d * 6.2832 / n_dots + phase * 6.2832 + r * 0.52
ผูก px = cx + rad * โคไซน์(angle)
ผูก py = cy + rad * ไซน์(angle)
ผูก dr = 1.2 + 2.0 * (1.0 - r / (rings + 1.0))
ผูก s = s + "<circle cx='" + f(px) + "' cy='" + f(py) + "' r='" + f(dr) + "' fill='" + สี + "' opacity='0.8'/>"
ผูก d = d + 1
}
ผูก r = r + 1
}
คืน s
}
ฟังก์ชัน pat_barcode(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก n = 40
ผูก bw = w / n
ผูก i = 0
ขณะที่ i < n {
ผูก t = i / n
ผูก bh = h * (0.25 + 0.75 * ค่าสัมบูรณ์(ไซน์(t * 6.28 * 6.0 + phase * 31.4)))
ผูก bx = ox + i * bw
ผูก by = oy + (h - bh) * 0.5
ผูก op = 0.3 + 0.65 * ค่าสัมบูรณ์(ไซน์(t * 3.14 + phase * 6.28))
ผูก s = s + "<rect x='" + f(bx) + "' y='" + f(by) + "' width='" + f(bw * 0.62) + "' height='" + f(bh) + "' fill='" + สี + "' opacity='" + f(op) + "'/>"
ผูก i = i + 1
}
คืน s
}
ฟังก์ชัน pat_branch_lines(ox, oy, w, h, สี, phase) {
ผูก s = ""
ผูก n = 18
ผูก cx = ox + w * 0.5
ผูก cy = oy + h * 0.88
ผูก i = 0
ขณะที่ i < n {
ผูก frac = i / n
ผูก angle = -1.5708 + (frac - 0.5) * 2.2 + phase * 0.4
ผูก ความยาว = h * (0.5 + 0.42 * ค่าสัมบูรณ์(ไซน์(i * 0.71 + phase * 3.14)))
ผูก x2 = cx + ความยาว * โคไซน์(angle)
ผูก y2 = cy + ความยาว * ไซน์(angle)
ผูก op = 0.25 + 0.6 * ค่าสัมบูรณ์(ไซน์(i * 0.5 + phase * 6.28))
ผูก sw = 0.6 + 1.4 * ค่าสัมบูรณ์(ไซน์(i * 0.9 + phase * 2.0))
ผูก s = s + "<line x1='" + f(cx) + "' y1='" + f(cy) + "' x2='" + f(x2) + "' y2='" + f(y2) + "' stroke='" + สี + "' stroke-width='" + f(sw) + "' opacity='" + f(op) + "'/>"
ผูก i = i + 1
}
คืน s
}
ฟังก์ชัน safe_id(name) {
ผูก s = str_replace(name, " ", "_")
ผูก s = str_replace(s, "(", "_")
ผูก s = str_replace(s, ")", "_")
ผูก s = str_replace(s, "{", "_")
ผูก s = str_replace(s, "}", "_")
ผูก s = str_replace(s, "-", "_")
ผูก s = str_replace(s, ".", "_")
คืน s
}
// ─── Render one function panel ───────────────────────────────────────────────
ฟังก์ชัน render_panel(fn_name, fn_body, px, py, pw, ph) {
ผูก hue = hash_str(fn_name)
ผูก hue2 = hash_str(fn_name + "b")
ผูก pt = ปัดลง(hash_int(fn_name + "pt", 6))
ผูก accent = detect_vtex(fn_body)
ผูก fg = สีHSL(hue, 90.0, 128.0)
ผูก bg = สีHSL(hue2, 20.0, 30.0)
ผูก id = safe_id(fn_name)
ผูก s = ""
// Panel background
ผูก s = s + "<rect x='" + f(px) + "' y='" + f(py) + "' width='" + f(pw) + "' height='" + f(ph) + "' fill='" + bg + "' fill-opacity='0.18' rx='5'/>"
ผูก s = s + "<rect x='" + f(px) + "' y='" + f(py) + "' width='" + f(pw) + "' height='" + f(ph) + "' fill='none' stroke='" + fg + "' stroke-width='0.8' rx='5' opacity='0.5'/>"
// Accent stripe (vtex color)
ผูก s = s + "<rect x='" + f(px) + "' y='" + f(py) + "' width='4' height='" + f(ph) + "' fill='" + accent + "' rx='3' opacity='0.9'/>"
// Clip rect for pattern area
ผูก clip_id = "clip_" + id
ผูก s = s + "<clipPath id='" + clip_id + "'><rect x='" + f(px + 5.0) + "' y='" + f(py + 2.0) + "' width='" + f(pw - 7.0) + "' height='" + f(ph - 18.0) + "'/></clipPath>"
ผูก s = s + "<g clip-path='url(#" + clip_id + ")'>"
// Pattern body
ผูก pattern = ถ้า pt == 0 {
pat_dot_grid(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
} มิฉะนั้น {
ถ้า pt == 1 {
pat_waveform(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
} มิฉะนั้น {
ถ้า pt == 2 {
pat_spectral_grid(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
} มิฉะนั้น {
ถ้า pt == 3 {
pat_radial_rings(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
} มิฉะนั้น {
ถ้า pt == 4 {
pat_barcode(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
} มิฉะนั้น {
pat_branch_lines(px + 5.0, py + 2.0, pw - 7.0, ph - 18.0, fg, hue)
}
}
}
}
}
ผูก s = s + pattern
ผูก s = s + "</g>"
// Function label at bottom
ผูก label_y = py + ph - 5.0
ผูก s = s + "<text x='" + f(px + 8.0) + "' y='" + f(label_y) + "' font-family='monospace' font-size='8.5' fill='" + accent + "' opacity='0.95'>" + fn_name + "</text>"
คืน s
}
// ─── Extract basename from path ──────────────────────────────────────────────
ฟังก์ชัน extract_basename(path) {
ผูก result = path
ผูก searching = 1
ขณะที่ searching == 1 {
ผูก pos = str_find(result, "/")
ผูก result = ถ้า pos >= 0 { substr(result, pos + 1, 9999) } มิฉะนั้น { result }
ผูก searching = ถ้า pos >= 0 { 1 } มิฉะนั้น { 0 }
}
ผูก searching = 1
ขณะที่ searching == 1 {
ผูก pos = str_find(result, "\\")
ผูก result = ถ้า pos >= 0 { substr(result, pos + 1, 9999) } มิฉะนั้น { result }
ผูก searching = ถ้า pos >= 0 { 1 } มิฉะนั้น { 0 }
}
คืน result
}
// ─── Entry point ─────────────────────────────────────────────────────────────
ผูก start = ทำ {
// ── Parse CLI args ──────────────────────────────────────────────────────
ผูก all_args = get_args()
ผูก n_args = ความยาว(all_args)
ผูก อินพุต = ""
ผูก เอาต์พุต = ""
ผูก i = 1
ขณะที่ i < n_args {
ผูก a = list_get(all_args, i)
ผูก is_ling = ends_with(a, ".ling")
ผูก is_self = ends_with(a, "visualize.ling")
ผูก is_svg = ends_with(a, ".svg")
ผูก อินพุต = ถ้า is_ling {
ถ้า is_self { อินพุต }
มิฉะนั้น {
ถ้า อินพุต == "" { a } มิฉะนั้น { อินพุต }
}
} มิฉะนั้น { อินพุต }
ผูก เอาต์พุต = ถ้า is_svg {
ถ้า เอาต์พุต == "" { a } มิฉะนั้น { เอาต์พุต }
} มิฉะนั้น { เอาต์พุต }
ผูก i = i + 1
}
ถ้า อินพุต == "" {
พิมพ์("usage: ling run examples/visualize.ling <input.ling> [output.svg]")
คืน ()
}
ผูก เอาต์พุต = ถ้า เอาต์พุต == "" { อินพุต + ".svg" } มิฉะนั้น { เอาต์พุต }
// ── Read source ─────────────────────────────────────────────────────────
ผูก ต้นฉบับ = read_file(อินพุต)
ผูก lines = split(ต้นฉบับ, "\n")
ผูก n_lines = ความยาว(lines)
// ── Scan for function / entry-point definitions ─────────────────────────
ผูก fn_names = list_new()
ผูก fn_bodies = list_new()
ผูก current_fn = ""
ผูก current_body = ""
ผูก i = 0
ขณะที่ i < n_lines {
ผูก line = list_get(lines, i)
ผูก trimmed = trim(line)
// Detect function start: "fn name(" or Thai/Chinese variants
ผูก is_fn = starts_with(trimmed, "fn ")
ผูก is_th = starts_with(trimmed, "ฟังก์ชัน ")
ผูก is_zh = starts_with(trimmed, "函 ")
ผูก is_ko = starts_with(trimmed, "함수 ")
ผูก is_new_def = is_fn || is_th || is_zh || is_ko
// Save the previous function when starting a new definition
ผูก fn_names = ถ้า is_new_def {
ถ้า current_fn != "" { list_push(fn_names, current_fn) } มิฉะนั้น { fn_names }
} มิฉะนั้น { fn_names }
ผูก fn_bodies = ถ้า is_new_def {
ถ้า current_fn != "" { list_push(fn_bodies, current_body) } มิฉะนั้น { fn_bodies }
} มิฉะนั้น { fn_bodies }
// Compute name prefix offset (number of Unicode chars in keyword + space)
// ฟังก์ชัน = 8 chars + 1 space = 9; 함수 = 2 chars + 1 space = 3
ผูก kw_len = ถ้า is_fn { 3 }
มิฉะนั้น {
ถ้า is_th { 9 }
มิฉะนั้น {
ถ้า is_zh { 2 }
มิฉะนั้น { 3 }
}
}
// Extract new function name
ผูก pos_open = str_find(trimmed, "(")
ผูก raw_name = ถ้า pos_open >= 0 {
substr(trimmed, kw_len, pos_open - kw_len)
} มิฉะนั้น {
substr(trimmed, kw_len, 60)
}
ผูก new_fn_name = trim(raw_name)
// Update state
ผูก current_fn = ถ้า is_new_def { new_fn_name } มิฉะนั้น { current_fn }
ผูก current_body = ถ้า is_new_def { "" } มิฉะนั้น {
ถ้า current_fn != "" { current_body + " " + trimmed } มิฉะนั้น { current_body }
}
ผูก i = i + 1
}
// Save the last function
ผูก fn_names = ถ้า current_fn != "" { list_push(fn_names, current_fn) } มิฉะนั้น { fn_names }
ผูก fn_bodies = ถ้า current_fn != "" { list_push(fn_bodies, current_body) } มิฉะนั้น { fn_bodies }
ผูก n_fns = ความยาว(fn_names)
พิมพ์("found " + to_str(n_fns) + " functions in " + อินพุต)
// ── SVG layout ──────────────────────────────────────────────────────────
ผูก cols = 4.0
ผูก cell_w = 200.0
ผูก cell_h = 200.0
ผูก pad = 10.0
ผูก sidebar = 170.0
ผูก rows = ปัดขึ้น(n_fns / cols)
ผูก total_w = sidebar + pad + cols * (cell_w + pad)
ผูก total_h = 60.0 + rows * (cell_h + pad) + 50.0
// ── Build SVG ───────────────────────────────────────────────────────────
ผูก svg = ""
ผูก svg = svg + "<svg xmlns='http://www.w3.org/2000/svg' width='" + f(total_w) + "' height='" + f(total_h) + "'>\n"
// Defs: glow filter + background grid
ผูก svg = svg + "<defs>"
ผูก svg = svg + "<filter id='glow' x='-20%' y='-20%' width='140%' height='140%'>"
ผูก svg = svg + "<feGaussianBlur stdDeviation='3' result='b'/>"
ผูก svg = svg + "<feMerge><feMergeNode in='b'/><feMergeNode in='SourceGraphic'/></feMerge>"
ผูก svg = svg + "</filter>"
ผูก svg = svg + "<pattern id='bg_grid' width='20' height='20' patternUnits='userSpaceOnUse'>"
ผูก svg = svg + "<path d='M 20 0 L 0 0 0 20' fill='none' stroke='#ffffff' stroke-width='0.2' opacity='0.06'/>"
ผูก svg = svg + "</pattern>"
ผูก svg = svg + "</defs>\n"
// Background
ผูก svg = svg + "<rect width='" + f(total_w) + "' height='" + f(total_h) + "' fill='#090912'/>\n"
ผูก svg = svg + "<rect width='" + f(total_w) + "' height='" + f(total_h) + "' fill='url(#bg_grid)'/>\n"
// Sidebar background
ผูก svg = svg + "<rect x='0' y='0' width='" + f(sidebar) + "' height='" + f(total_h) + "' fill='#0c0c1f'/>\n"
// Title
ผูก basename = extract_basename(อินพุต)
ผูก svg = svg + "<text x='12' y='34' font-family='monospace' font-size='16' fill='#e8e8f8' font-weight='bold'>" + basename + "</text>\n"
ผูก svg = svg + "<text x='12' y='50' font-family='monospace' font-size='10' fill='#6688aa'>" + to_str(n_fns) + " functions</text>\n"
// Sidebar legend header
ผูก svg = svg + "<text x='8' y='74' font-family='monospace' font-size='9' fill='#aaaacc' font-weight='bold'>PATTERNS</text>\n"
ผูก legend_items = list_new()
ผูก legend_items = list_push(legend_items, "dot grid")
ผูก legend_items = list_push(legend_items, "waveform")
ผูก legend_items = list_push(legend_items, "spectral")
ผูก legend_items = list_push(legend_items, "radial")
ผูก legend_items = list_push(legend_items, "barcode")
ผูก legend_items = list_push(legend_items, "branches")
ผูก li = 0
ขณะที่ li < 6 {
ผูก lhue = li / 6.0
ผูก lc = สีHSL(lhue, 100.0, 128.0)
ผูก ly = 88.0 + li * 16.0
ผูก svg = svg + "<rect x='8' y='" + f(ly - 6.0) + "' width='10' height='10' fill='" + lc + "' rx='2' opacity='0.8'/>"
ผูก svg = svg + "<text x='22' y='" + f(ly + 2.0) + "' font-family='monospace' font-size='8.5' fill='" + lc + "'>" + list_get(legend_items, li) + "</text>\n"
ผูก li = li + 1
}
// ── Render function panels ──────────────────────────────────────────────
ผูก i = 0
ขณะที่ i < n_fns {
ผูก fn_name = list_get(fn_names, i)
ผูก fn_body = list_get(fn_bodies, i)
ผูก col_idx = i % cols
ผูก row_idx = ปัดลง(i / cols)
ผูก px = sidebar + pad + col_idx * (cell_w + pad)
ผูก py = 60.0 + row_idx * (cell_h + pad)
ผูก panel = render_panel(fn_name, fn_body, px, py, cell_w, cell_h)
ผูก svg = svg + panel + "\n"
ผูก i = i + 1
}
// ── Registration marks (corners) ────────────────────────────────────────
ผูก svg = svg + reg_mark(12.0, 12.0)
ผูก svg = svg + reg_mark(total_w - 12.0, 12.0)
ผูก svg = svg + reg_mark(12.0, total_h - 12.0)
ผูก svg = svg + reg_mark(total_w - 12.0, total_h - 12.0)
// ── Footer ──────────────────────────────────────────────────────────────
ผูก svg = svg + "<text x='" + f(total_w * 0.5) + "' y='" + f(total_h - 8.0) + "' text-anchor='middle' font-family='monospace' font-size='8' fill='#333355'>ling visualize · " + basename + "</text>\n"
ผูก svg = svg + "</svg>"
// ── Write output ────────────────────────────────────────────────────────
write_file(เอาต์พุต, svg)
พิมพ์("written: " + เอาต์พุต)
}