lingmodeler
↓ 0 downloadsLingModeler: box modeling with quads and tris, rigging + weight painting, 2D vector illustration and animation, procedural textures and game assets; .lmesh / .ling native formats, OBJ, glTF and SVG import / export
Keywords 3d, modeling, vector, svg, gltf, obj, rigging, animation, textures, ling
lingfu install lingmodelerCode / Files (67)
ling/timeline.ling
# ━━━ timeline.ling — shared frame timeline (pose animation, 2D vector animation, animated textures) ━━━
fn tl_init() {
st_set("tl_frame", 0.0)
st_set("tl_start", 0.0)
st_set("tl_end", 48.0)
st_set("tl_fps", 24.0)
st_set("tl_playing", 0.0)
st_set("tl_loop", 1.0)
st_set("tl_dirty", 1.0)
st_set("tl_last", 0.0 - 1.0)
}
fn tl_frame() { return st_get("tl_frame", 0.0) }
fn tl_fps() { return max(1.0, st_get("tl_fps", 24.0)) }
fn tl_playing() { return st_get("tl_playing", 0.0) > 0.5 }
fn tl_set_frame(f) {
st_set("tl_frame", clampf(f, st_get("tl_start", 0.0), max(st_get("tl_start", 0.0), st_get("tl_end", 48.0))))
tl_mark_dirty()
}
fn tl_mark_dirty() { st_set("tl_dirty", 1.0) }
fn tl_toggle_play() {
st_set("tl_playing", 1.0 - st_get("tl_playing", 0.0))
if tl_playing() { st_set("status", "Playing - Space pauses") }
}
# advance when playing, then evaluate the animation for the current mode
fn tl_tick() {
bind m = st_get("mode", 0.0)
if tl_playing() {
bind f = st_get("tl_frame", 0.0) + st_get("dt", 0.016) * tl_fps()
bind e = st_get("tl_end", 48.0)
bind s = st_get("tl_start", 0.0)
if f > e { if st_get("tl_loop", 1.0) > 0.5 { bind f = s + (f - e) % max(1.0, e - s) } else { bind f = e st_set("tl_playing", 0.0) } }
st_set("tl_frame", f)
st_set("tl_dirty", 1.0)
}
if st_get("tl_dirty", 0.0) < 0.5 { return 0.0 }
st_set("tl_dirty", 0.0)
bind f = st_get("tl_frame", 0.0)
if m < 4.5 {
bind ids = me_ids()
bind i = 0.0
while i < len(ids) {
bind o = list_get(ids, i)
if ps_cur_action(o) >= 0.0 && rg_count(o) > 0.5 { ps_eval(o, f) }
bind i = i + 1.0
}
} else if m < 6.5 {
an_eval(f)
} else {
st_set("tx_time", f / tl_fps())
}
}
# key frames to show for the current selection
fn tl_keys_for_mode() {
bind m = st_get("mode", 0.0)
if m < 4.5 { bind o = me_sel_o() if o >= 0.0 { return ps_key_frames(o) } return [] }
if m < 6.5 { return an_key_frames() }
return []
}
fn tl_draw(x, y, w, h) {
px_rect(x, y, w, h, C_BG_SIDE)
u_hsep(x, y, w)
bind m = st_get("mode", 0.0)
bind by = y + 6.0
bind bx = x + 8.0
bind playing = tl_playing()
if u_icon_button("tl_first", bx, by, 26.0, 22.0, "skip_l", 11.0, C_TEXT, false) { tl_set_frame(st_get("tl_start", 0.0)) }
if u_icon_button("tl_play", bx + 28.0, by, 34.0, 22.0, sel(playing, "pause", "play"), 13.0, sel(playing, C_YELLOW, C_GREEN), playing) { tl_toggle_play() }
if u_icon_button("tl_last", bx + 64.0, by, 26.0, 22.0, "skip_r", 11.0, C_TEXT, false) { tl_set_frame(st_get("tl_end", 48.0)) }
bind bx = bx + 98.0
bind nv = u_dragval("tl_fr", bx, by, 74.0, 22.0, floor(st_get("tl_frame", 0.0)), 0.0, 100000.0, 0.25, "Frame " + fmt0(st_get("tl_frame", 0.0)))
if u_has(nv) { tl_set_frame(round(nv)) }
bind bx = bx + 80.0
bind nv = u_dragval("tl_st", bx, by, 64.0, 22.0, st_get("tl_start", 0.0), 0.0, 100000.0, 0.25, "Start " + fmt0(st_get("tl_start", 0.0)))
if u_has(nv) { st_set("tl_start", min(round(nv), st_get("tl_end", 48.0) - 1.0)) tl_mark_dirty() }
bind bx = bx + 68.0
bind nv = u_dragval("tl_en", bx, by, 64.0, 22.0, st_get("tl_end", 48.0), 1.0, 100000.0, 0.25, "End " + fmt0(st_get("tl_end", 48.0)))
if u_has(nv) { st_set("tl_end", max(round(nv), st_get("tl_start", 0.0) + 1.0)) tl_mark_dirty() }
bind bx = bx + 68.0
bind nv = u_dragval("tl_fps", bx, by, 64.0, 22.0, st_get("tl_fps", 24.0), 1.0, 120.0, 0.1, fmt0(st_get("tl_fps", 24.0)) + " fps")
if u_has(nv) { st_set("tl_fps", round(nv)) st_set("an_fps", round(nv)) }
bind bx = bx + 72.0
if u_chip("tl_loop", bx, by + 1.0, 46.0, 20.0, "Loop", st_get("tl_loop", 1.0) > 0.5, C_BLUE) { st_set("tl_loop", 1.0 - st_get("tl_loop", 1.0)) }
if u_chip("tl_autokey", bx + 50.0, by + 1.0, 66.0, 20.0, "Auto key", st_get("autokey", 0.0) > 0.5, C_RED) { st_set("autokey", 1.0 - st_get("autokey", 0.0)) }
bind bx = bx + 124.0
if m == 4.0 || m == 6.0 {
if u_button("tl_key", bx, by, 64.0, 22.0, "Key (I)", C_BLUE) { if m == 4.0 { ps_key() } else { an_key() } }
if u_button("tl_unkey", bx + 68.0, by, 64.0, 22.0, "Unkey", 0.0) { if m == 4.0 { ps_unkey() } else { an_unkey() } }
if m == 6.0 { if u_button("tl_shape", bx + 136.0, by, 92.0, 22.0, "Shape key (K)", 0.0) { an_shapekey() } }
}
# ruler
bind ry = y + 36.0
bind rh = h - 44.0
bind rx = x + 8.0
bind rw = w - 16.0
px_rect(rx, ry, rw, rh, C_BG_DEEP)
px_outline(rx, ry, rw, rh, C_LINE_SOFT)
bind s = st_get("tl_start", 0.0)
bind e = max(s + 1.0, st_get("tl_end", 48.0))
bind span = e - s
bind pxf = rw / span
bind step = 1.0
if pxf < 40.0 { bind step = 5.0 }
if pxf < 8.0 { bind step = 10.0 }
if pxf < 3.0 { bind step = 50.0 }
if pxf < 0.6 { bind step = 250.0 }
bind f = ceil(s / step) * step
while f <= e {
bind fx = rx + (f - s) * pxf
bind major = f % (step * 5.0) == 0.0
px_line(fx, ry + sel(major, 2.0, rh - 10.0), fx, ry + rh - 1.0, sel(major, C_GRID_MAJ, C_GRID_MIN), 1.0)
if major || pxf > 20.0 { g_text(fx + 3.0, ry + 3.0, 10.0, C_TEXT_DIM, fmt0(f)) }
bind f = f + step
}
# keys
bind keys = tl_keys_for_mode()
bind cur = st_get("tl_frame", 0.0)
bind ky = ry + rh * 0.55
bind i = 0.0
while i < len(keys) {
bind kf = list_get(keys, i)
if kf >= s && kf <= e {
bind kx = rx + (kf - s) * pxf
bind on = abs(kf - cur) < 0.5
bind col = sel(on, C_TEXT_STRONG, C_YELLOW)
g_tri(kx, ky - 6.0, kx + 6.0, ky, kx, ky + 6.0, col)
g_tri(kx, ky - 6.0, kx, ky + 6.0, kx - 6.0, ky, col)
}
bind i = i + 1.0
}
# playhead
bind px2 = rx + clampf((cur - s) * pxf, 0.0, rw)
px_line(px2, ry, px2, ry + rh, C_PLAYHEAD, 1.0)
px_rect(px2 - 14.0, ry + rh - 14.0, 28.0, 13.0, C_PLAYHEAD)
g_text_c(px2, ry + rh - 13.0, 10.0, C_BG_DEEP, fmt0(cur))
# scrub
bind hot = u_hot(rx, ry, rw, rh)
if hot && u_pressed() { u_set_active("tl_scrub") }
if u_active() == "tl_scrub" && u_down() {
bind nf = s + (u_mx() - rx) / pxf
tl_set_frame(round(clampf(nf, s, e)))
}
if hot && u_scroll() != 0.0 && st_get("wheel_used", 0.0) < 0.5 { tl_set_frame(cur + sel(u_scroll() > 0.0, 1.0, 0.0 - 1.0)) st_set("wheel_used", 1.0) }
# mode hint
bind hint = sel(m == 4.0, "Pose keys of the selected bones", sel(m == 6.0, "Keys of the selected items", "Texture time"))
g_text_r(x + w - 10.0, by + 5.0, 11.0, C_TEXT_DIM, hint)
}