Situs ini dikemudikan dua tombol, seperti mesin pemiliknya. Membaca: j dan k menggulir, d dan u setengah layar, gg ke atas, G ke bawah, H dan L pindah jendela, ? membuka panduan. Spasi adalah kunci leader Neovim dan mengurus isi: Spasi lalu h beranda, r riset, p proyek, g gear, a tentang, / tag, atau Spasi lalu angka untuk melompat ke jendela bernomor itu. Home adalah prefix tmux dan mengurus jendela: Home lalu c membuka terminal, Home lalu & menutup jendela, Home lalu spasi ke jendela berikutnya. Saat fokus ada di papan ketik, h j k l memindahkan pilihan antar tombol dan Enter membukanya.

RisetR TentangA Gear — G untuk gear — papan ketik, terminal, editor, homelab.G
    ProyekP Tag — / seperti di vim: cari./
    ×
    Menu

    fate-studio: Melihat dan Menjalankan Statechart di Browser

    Viewer dan simulator langsung untuk statechart fate — kirim event, jalankan timer, resolve invocation, dan lihat state aktif berubah lewat Server-Sent Events. Satu binary statis, tanpa satu pun permintaan ke luar.

    Kalau fate adalah mesinnya, fate-studio adalah tempat melihat mesin itu bekerja. Buka sebuah machine, diagramnya muncul; lalu jalankan langkah demi langkah — kirim event, picu transisi tertunda, resolve atau tolak invocation — dan state aktifnya berubah di layar secara langsung.

    Kenapa repo terpisah

    Ini keputusan yang paling sering ditanyakan, dan jawabannya satu kalimat: mesinnya tidak punya dependensi, studio-nya butuh web server.

    Kalau keduanya satu repo, go get github.com/arisros/fate akan ikut menarik net/http dan seluruh isi studio ke dalam program orang yang cuma butuh state machine. Memisahkannya berarti orang membayar hanya untuk apa yang dipakai.

    Bisa ditempelkan ke program sendiri

    Studio-nya adalah http.Handler biasa, jadi bukan cuma bisa dijalankan sebagai server demo, tapi juga dipasang di dalam aplikasi yang sedang berjalan:

    srv := studio.NewServer("my app")
    srv.Register(studio.Entry{
        Name:    "checkout",
        Summary: "the checkout flow",
        Build:   checkoutMachine().Describe,
        BuildLive: func() studio.LiveInstance {
            return studio.NewLiveActor(checkoutMachine(), dispatch, checkoutMachine().Describe)
        },
    })
    http.Handle("/studio/", http.StripPrefix("/studio", srv.Handler()))

    Kuncinya ada di antarmuka LiveInstance. fate bertipe generik — Actor[Ctx, Evt] — sementara simulator harus bisa menjalankan machine apa pun tanpa tahu tipe konkretnya. LiveInstance menghapus tipe itu, dan dispatch yang diberikan pemakai bertugas memetakan nama event dari UI ke event bertipe miliknya. Machine yang didaftarkan dengan Build saja tetap tampil diagramnya, tanpa simulator.

    Kanvas dan transport

    Diagramnya digambar dengan React Flow (@xyflow/react) dan tata letaknya diatur elkjs, jadi posisi node tidak perlu ditulis manual. Perubahan state dikirim dari server ke browser lewat Server-Sent Events, bukan WebSocket — arah datanya memang satu, dari server ke browser, dan event dari pengguna tetap lewat request biasa. SSE reconnect sendiri dan tidak butuh penanganan apa pun di proxy.

    Ada juga snapshot yang bisa di-inspect, di-diff, diimpor dan diekspor, ditambah timeline yang merekam tiap langkah — praktis dipakai untuk menceritakan ulang urutan kejadian yang menghasilkan state yang aneh.

    Satu binary, tanpa panggilan keluar

    Hasil build UI (Vite) di-commit ke assets/ dan ditanam ke dalam binary Go. Jadi yang di-deploy hanya satu berkas: tidak butuh Node, tidak ada CDN, tidak ada permintaan font eksternal. Ini penting karena studio ini kemungkinan besar dipasang di dalam jaringan internal yang tidak punya akses keluar sama sekali.

    go run ./cmd/fate-studio    # lalu buka http://localhost:8090

    Alamatnya diatur lewat FATE_STUDIO_ADDR. Server demo-nya membawa beberapa machine contoh — traffic light, media player paralel, build pipeline, editor dengan deep history, counter dengan konteks hidup, serta machine timeout dan fetch untuk mencoba kontrol timer dan invocation.

    id en
    rss gh in