Updated Aug 2026 Share
Change cover
Setyo Aji Imam Maliki
Change iconAdd coverAdd comment

Setyo Aji Imam Maliki

PersonasSoftware Engineer ← currentCivil Engineer
LocationJakarta, Indonesia
StatusAt NuvoPlay, open to interesting conversations

+⋮⋮
I treat code with the same structural rigor as physical infrastructure. Whether it's a bridge or a backend, the goal is the same: resilience, integrity, and long-term stability.
+⋮⋮

Engineer with two lives that overlapped on purpose: from 2022 to 2025 I ran infrastructure projects by day and took freelance software work at night, until the second one became the whole job. Same standards, different materials.

+⋮⋮

Explore

+⋮⋮
+⋮⋮
+⋮⋮
+⋮⋮
+⋮⋮
+⋮⋮
Why an engineer of buildings writes software

Load paths, redundancy, and factors of safety translate directly to system design: graceful degradation, defense in depth, honest margins. Buildings do not get hotfixes, and that mindset ships better code.

Change cover

Software Engineer

NowPT Nuvoplay Alpha Technology · since April 2026
FocusMobile apps owned end-to-end: app, API, media pipeline, CI, store release
Stack Flutter · Dart React · TypeScript Rust Kotlin Swift Ruby on Rails Riverpod Clean Architecture · SOLID Cloudflare Workers · D1 · R2 DRM Streaming CI/CD

+⋮⋮

Fullstack by necessity, mobile by focus. The app is where users actually meet the product, so I follow the problem wherever it lives: into the API, the media pipeline, the release process, instead of filing a ticket and waiting.

+⋮⋮

What I build

+⋮⋮

Install it and judge the work directly. That is the point of shipping.

+⋮⋮

Experience

+⋮⋮
Software Engineer, PT Nuvoplay Alpha Technology · Apr 2026 to now

Flutter clients for a DRM-protected streaming product: playback, offline downloads, background audio, realtime sessions.

Rust API and media pipeline work: licence flow, transcode queue, storage and CDN delivery.

Release engineering: staged rollouts, crash triage, and store submission for both platforms.

+⋮⋮
Software Engineer, PT Asa Mandiri Teknologi · Jun 2025 to Feb 2026

Client-side modules for Loyverse MCP, real-time sync between AMT Forge and Loyverse POS for sales, inventory, and customer workflows.

Cross-platform Flutter interface with reusable components, Riverpod state management, strict SOLID.

Automated CI/CD pipelines via GitHub Actions, cutting manual deployment bottlenecks.

+⋮⋮
Software Engineer, Freelance · Feb 2022 to now

Production cross-platform apps, full SDLC from requirements to deployment.

Koriru Coffee, architected the MVP: web storefront, internal dashboard, order management flow.

Backend Engineering Track, GoTo Impact Foundation (Generasi GIGIH 2.0). Ruby on Rails, REST API design, SQL.

+⋮⋮

Open source

+⋮⋮

When a problem hits the team twice, it becomes a tool. All three are public and MIT.

+⋮⋮
Native work when the platform demands it: Kotlin for Android services and media sessions, Swift for iOS audio and DRM playback, bridged into Flutter through platform channels.
Change cover

Civil Engineer

CertifiedBNSP × 2 building engineering + construction safety
Period2022 to 2025 · overlapped with freelance software work
RoleEngineer Specialist at Dinas CIKASDA, Sulawesi Tengah
Skills Structural Analysis AutoCAD ETABS SAP2000 DED Review Site Supervision Cost Estimation SNI Standards

+⋮⋮

Led multidisciplinary engineering teams delivering full-lifecycle infrastructure projects on time and within budget, structural design, DED review, standardized budgeting frameworks, and rigorous technical audits. The kind of engineering where mistakes are very visible and very permanent.

+⋮⋮

Licensure & certifications

+⋮⋮
Both issued by BNSP (Badan Nasional Sertifikasi Profesi), Indonesia's national professional certification authority. ● Active
+⋮⋮
Ahli Muda Teknik Bangunan Gedung (Building Engineering Specialist)

Issuing authority: Indonesia Professional Certification Authority

Agency: Tenaga Konstruksi Nasional

Status: ● Active

+⋮⋮
Ahli Muda K3 Konstruksi (Construction Safety Specialist)

Issuing authority: Indonesia Professional Certification Authority

Agency: Construction Occupational Safety & Health

Status: ● Active

+⋮⋮

Experience

+⋮⋮
Engineer Specialist at Dinas CIKASDA, Sulawesi Tengah · Apr 2022 to Jan 2025

Led multidisciplinary teams delivering full-lifecycle infrastructure projects, on schedule, inside budget, planning through handover.

Standardized budgeting frameworks, so cost estimates became a repeatable method rather than one engineer's spreadsheet.

Technical audits of designs and consultancy deliverables, the review seat, where you learn what actually goes wrong.

+⋮⋮
Bachelor of Engineering, Tadulako University, Palu · 2016 to 2021

Civil engineering. Palu is a high-seismicity city that lived through the 2018 earthquake and tsunami, you do not study structures there abstractly.

+⋮⋮

Project log

+⋮⋮
82 projects delivered across Central Sulawesi, 2021 to 2025, public buildings, offices, sports facilities, roads, drainage, and landscape works. The full log, with scope and outcome for each, lives on the Projects page.
+⋮⋮

What this era shipped

+⋮⋮
Bridges

Abutment capacity checks, vertical deflection control to SNI, elastomer bearing pad design, and the joint details where bridges actually fail.

+⋮⋮
Buildings

Concrete design to SNI 2847, wind load analysis to SNI 1727, seismic mode translation to SNI 1726, steel slenderness and stress-ratio checks, composite bondek floor slabs, including a project in Palu, where seismic detailing is not a formality.

+⋮⋮
Documents & governance

DED review, ANDALALIN traffic impact documents, environmental impact assessments, consultancy reporting for BGN, and procurement red-flag analysis on LPSE tenders. The unglamorous half of civil engineering, and the half that decides whether a project survives audit.

+⋮⋮
Safety & supervision

Site supervision and construction occupational safety (K3) management to SNI standards, certified, and applied on live sites where the consequences are immediate.

+⋮⋮
29 structural engineering articles came out of this era. All readable on the Writing page.
Change cover

Projects

+⋮⋮
The pinned cards below are public and MIT licensed. Clone them, open an issue, take what helps. Product work further down is mostly private client code, so those cards link nowhere on purpose.
+⋮⋮

Pinned

+⋮⋮

Current work

+⋮⋮

Shipped

+⋮⋮

Civil engineering, project log

+⋮⋮

82 projects delivered across Central Sulawesi between 2021 and 2025, public buildings, offices, sports facilities, roads, drainage, and landscape works for provincial government agencies.

+⋮⋮

Roles span the full lifecycle: site supervision and quality control during construction, design and DED review before tender, planning and cost analysis at inception, and HSE oversight throughout. Sorted by completion date, click any row for scope, responsibilities, and outcome.

▦ Table
▤ Timeline
All 822025 12024 332023 282022 172021 3
Aa Project
◫ Role
Location
Period
Construction of the Central Sulawesi Provincial Grand Mosque
Lead Construction Supervisor
Palu
Jan 2025 to Apr 2025
Workstation Power Outlet Installation · Dinas Cipta Karya & SDA Prov. Sulteng
MEP Planning Engineer & Supervisor
Palu
Nov 2024 to Dec 2024
Sports Field Rehabilitation · Siranindi Official Residence
Sports Facility Rehabilitation Engineer
Palu
Oct 2024 to Dec 2024
Signage & Wayfinding Works · Dinas Cipta Karya & SDA Prov. Sulteng
Planning Engineer & Installation Supervisor
Palu
Nov 2024 to Dec 2024
Secretary's Office Interior Renovation · Dinas Cipta Karya & SDA Prov. Sulteng
Lead Planner & Site Supervisor
Palu
Aug 2024 to Dec 2024
Painting & Road Marking Works · Dinas Cipta Karya & SDA Prov. Sulteng
Planning Engineer & Site Supervisor
Palu
Oct 2024 to Dec 2024
Office Building Maintenance · Dinas Cipta Karya & SDA Prov. Sulteng
Maintenance Planning Engineer
Palu
Jul 2024 to Dec 2024
Mezzanine Procurement · Dinas Cipta Karya & SDA Warehouse
Mezzanine Design & Procurement Engineer
Palu
Nov 2024 to Dec 2024
Lift Lobby Backdrop Works · Dinas Cipta Karya & SDA Prov. Sulteng
Design Engineer & Quality Controller
Palu
Aug 2024 to Dec 2024
Construction of the Lelean Nono Terminal Fence · Toli-Toli Regency
Design Engineer & HSE Expert
Toli-Toli
Jul 2024 to Dec 2024
Interior Phase II · Conference & Archive Rooms, Dinas Cipta Karya & SDA Prov. Sulteng
Lead Planner & Construction Supervisor
Palu
Aug 2024 to Dec 2024
Continued Infrastructure Improvement · Building & Road Works, Dinas Cipta Karya & SDA Office
Infrastructure Continuation Supervisor
Palu
Dec 2024 to Dec 2024
e-Bantekbgn Digital Service Platform
Technical Assistance Digital Platform Lead
Palu
Oct 2024 to Dec 2024
Continued Infrastructure Upgrade (Drainage Cover Procurement) · Dinas Cipta Karya & SDA Office
Drainage Infrastructure Engineer
Palu
Nov 2024 to Dec 2024
DED Review · Central Sulawesi Provincial DPRD Plenary Building
Senior Technical Reviewer (DED & Budget)
Palu
Dec 2024 to Dec 2024
Rehabilitation & Conversion of the Canteen Building · Dinas Cipta Karya & SDA Prov. Sulteng
Lead Planner & Rehabilitation Supervisor
Palu
Nov 2024 to Dec 2024
Canopy & Rear Fence Works · Dinas Cipta Karya & SDA Office
Canopy & Fence Construction Engineer
Palu
Oct 2024 to Dec 2024
DED Review · Central Sulawesi Provincial BAPENDA Meeting Room
Technical Reviewer & Cost Analyst
Palu
Nov 2024 to Dec 2024
Rehabilitation of Aspidsus Official Residence · Kejaksaan Tinggi
Lead Planner & Phased Construction Supervisor
Palu
Feb 2024 to Dec 2024
Renovation of the Asbin Official Residence · Central Sulawesi High Prosecutor's Office
Lead Planner & Rehabilitation Engineer
Palu
Jun 2024 to Dec 2024
Facade ACP Installation · Dinas Cipta Karya & SDA Prov. Sulteng
Facade Engineer & Quality Supervisor
Palu
Oct 2024 to Dec 2024
Building & Road Infrastructure Improvement · Dinas Cipta Karya & SDA Office
Infrastructure Improvement Project Lead
Palu
Feb 2024 to Oct 2024
Landscape Upgrade Phase II · Central Sulawesi Provincial BPKAD Office
Senior Landscape Engineer
Palu
Aug 2024 to Oct 2024
Billboard Structure Works · Dinas Cipta Karya & SDA Prov. Sulteng
Structural Engineer & Fast-Track Execution Supervisor
Palu
Aug 2024 to Sep 2024
Library Building Assessment · MTsN 2 Kota Palu
Educational Facility Assessment Engineer
Palu
Sep 2024 to Sep 2024
Building Inspection & Valuation · Central Sulawesi Provincial BPBD
Building Inspection & Valuation Expert
Palu
Sep 2024 to Sep 2024
Demolition of the Dinas Perkebunan Building · Central Sulawesi Province
Demolition Engineer & HSE Supervisor
Palu
Jul 2024 to Aug 2024
Physical Condition Survey of Cultural Heritage Sites · Tojo Una-Una
Cultural Heritage Survey Specialist
Tojo Una-Una
Aug 2024 to Aug 2024
Rehabilitation of BPOM Auditorium Building
Technical Management Expert & Cost Validator
Palu
Jul 2024 to Aug 2024
Rear Segment Landscape Design · Central Sulawesi Provincial BPKAD Building
Landscape Design Engineer
Palu
Jun 2024 to Aug 2024
Warehouse Development · Dinas Cipta Karya dan Sumber Daya Air
Lead Design Engineer & Construction Supervisor
Palu
Apr 2024 to Jul 2024
Landscaping & Garden Works · Office of Dinas Cipta Karya dan Sumber Daya Air
Landscape Engineer & Site Supervisor
Palu
May 2024 to Jul 2024
Site Survey · Kejaksaan Tinggi Clinic Planning
Survey Engineer
Palu
May 2024 to May 2024
Measurement & Evaluation · Pue Ndjidi Road Improvement Works, Sigi
Field Evaluation Engineer
Sigi
Feb 2024 to Feb 2024
Interior Procurement · Rest Room & Lobby Backdrop, Dinas Cipta Karya & SDA
Interior & Branding Engineer
Palu
Oct 2023 to Dec 2023
Interior Works Phase II · Dinas Cipta Karya & SDA Office
Review Engineer & Interior Supervisor
Palu
Sep 2023 to Dec 2023
Embankment, Drainage & Box Culvert Design · Cova Lima, Timor-Leste
International Hydraulic Structure Design Engineer
Cova Lima, Timor Leste
Nov 2023 to Dec 2023
Indoor Sports Facility Rehabilitation · Dinas Cipta Karya & SDA
Sports Facility Rehabilitation Engineer
Palu
Nov 2023 to Dec 2023
Office Partition Works · Dinas Cipta Karya & SDA
Office Partition Engineer
Palu
Nov 2023 to Dec 2023
Landscape Works · Dinas Cipta Karya & SDA Office
Landscape & Cultural Design Engineer
Palu
Oct 2023 to Dec 2023
Environmental Infrastructure · Dinas Cipta Karya & SDA Office
Environmental Infrastructure Engineer
Palu
Oct 2023 to Dec 2023
Interior Decoration · Workstation & Camouflage Partitions, BPKAD
Partition & Space Planning Engineer
Palu
Oct 2023 to Dec 2023
Interior Decoration · Windows & Doors, BPKAD Office
Interior Procurement Engineer
Palu
Oct 2023 to Dec 2023
Stationery Warehouse Construction · BPKAD Central Sulawesi Province
Warehouse Construction Supervisor
Palu
Nov 2023 to Dec 2023
Office Building Construction Phase II · BPKAD Central Sulawesi Province
Review Engineer & Construction Supervisor
Palu
Jun 2023 to Dec 2023
Traditional House Construction Phase II · Rumah Gadang, Minangkabau Family Association
Planning Reviewer & Construction Supervisor
Palu
Mar 2023 to Oct 2023
Aisyiyah Orphanage Facility Design
Social Infrastructure Design Engineer (Pro Bono)
Sigi, Central Sulawesi
Sep 2023 to Oct 2023
Office Building Maintenance · Dinas Cipta Karya & SDA
Building Maintenance Engineer
Palu
Aug 2023 to Oct 2023
Public Facilities · Paneki Scout Campground
Remote Facilities Design Engineer
Paneki
May 2023 to Sep 2023
Port Development Planning · Toli-Toli Port
Port Facilities Planning Engineer
Toli-Toli
Jun 2023 to Aug 2023
Fence Rehabilitation · Central Sulawesi Provincial PKK Office
Asset & Rehabilitation Engineer
Palu
May 2023 to Aug 2023
Canopy Design · Kindergarten Yard, Palu City
Canopy Design Engineer (Personal Contribution)
Palu
Aug 2023 to Aug 2023
Standard Cost Budget Planning · Central Sulawesi Province
Lead Cost Standardization Engineer
Palu
Jun 2023 to Jul 2023
Sanitation & Ablution Facility Design · Pondok Tahfidz Sunju
Sanitation Design Engineer (Personal Contribution)
Sunju
Jul 2023 to Jul 2023
Landscape and Fence Rehabilitation · Dinas Cipta Karya & SDA Office
Landscape & Facade Design Engineer
Palu
Mar 2023 to Jul 2023
Office Name Wall Construction · Dinas Cipta Karya & SDA
Facade & Signage Engineer
Palu
May 2023 to Jun 2023
Badminton Sports Hall Maintenance · Palu City
Sports Facility Engineer
Palu
Apr 2023 to Jun 2023
Fence Survey & Design · Jl. Agus Salim, Palu
Survey & Design Engineer (Personal Project)
Palu
Jun 2023 to Jun 2023
Landscape Upgrade · Official Residence of the Central Sulawesi Head Prosecutor
Landscape & Drainage Engineer
Palu
Apr 2023 to Apr 2023
Public Facility Rehabilitation · Gawalise Stadium, Palu City
Lead Design Engineer & Supervisor
Palu
Jan 2023 to Apr 2023
Resort Design & Cost Estimate · Head of Department
Concept Design Engineer & Cost Estimator
Central Sulawesi
Feb 2023 to Mar 2023
Landscape Enhancement Phase II (Aviary) · Vice Governor's Official Residence
Landscape & Aviary Design Engineer
Palu
Jan 2023 to Feb 2023
Warehouse & Sports Facility Maintenance · Dinas Cipta Karya & SDA Office
Facility Maintenance Engineer
Palu
Oct 2022 to Dec 2022
Rehabilitation & Restoration of Souraja House, Kampung Lere
Cultural Heritage Restoration Specialist
Palu
Jun 2022 to Dec 2022
Side Fence Construction · Deputy Governor's Official Residence
Fence & Security Infrastructure Engineer
Palu
Oct 2022 to Dec 2022
Rumah Gadang Construction, Phase I · Minangkabau Family Association
Cultural Heritage Construction Reviewer
Palu
Jun 2022 to Dec 2022
Supply of Divisional Workspace Partitions · Dinas Cipta Karya & SDA Office
Office Space Division Engineer
Palu
Oct 2022 to Dec 2022
Rehabilitation of the 4th-Floor Meeting Room · Dinas Cipta Karya & SDA Office
Meeting Room Renovation Engineer
Palu
Oct 2022 to Dec 2022
Building Maintenance · Bidarawasia Women's Building
Building Maintenance Planning Engineer
Palu
Sep 2022 to Dec 2022
Landscape Design · Deputy Governor's Official Residence
Official Residence Landscape Architect
Palu
Oct 2022 to Dec 2022
Pavilion Interior Works · Deputy Governor's Official Residence
VIP Interior Design Engineer
Palu
Oct 2022 to Dec 2022
Interior DED · Dinas Cipta Karya dan Sumber Daya Air
Interior Design Engineer
Palu
Aug 2022 to Dec 2022
Rehabilitation of Green Open Space (RTH) · Tavanuka Sub-District
Green Open Space Designer
Palu
Oct 2022 to Dec 2022
Supply of Glass Partitions · Deputy Governor's Official Residence
Glass Partition Procurement Engineer
Palu
Nov 2022 to Dec 2022
Gazebo, Pond, Aviary & Supporting Facilities · Deputy Governor's Official Residence
Landscape Planner & Construction Supervisor
Palu
Oct 2022 to Dec 2022
Garden & Podium Works · Dinas Cipta Karya & SDA Office
Landscape Planner & Site Supervisor
Palu
Oct 2022 to Dec 2022
Supply of Decorative Grilles · Dinas Cipta Karya & SDA Office
Facade Decoration Engineer
Palu
Oct 2022 to Dec 2022
Rehabilitation of the Central Sulawesi Provincial PKK Building
Rehabilitation Planning Engineer
Palu
Apr 2022 to Jun 2022
Supply and Installation of 4th-Floor Office Partitions · Dinas Cipta Karya & SDA
Interior Space Planning Engineer
Kota Palu, Sulawesi Tengah
Apr 2022 to Jun 2022
Budget Planning & Drawings for Type 36 BTN Housing
Residential Design Drafter & Cost Estimator
Sulawesi Tengah
Aug 2021 to Dec 2021
Design of a Riverside House with Fish Pond · Buol Regency
Residential & Aquaculture Design Engineer
Kabupaten Buol, Sulawesi Tengah
May 2021 to Jun 2021
Topographic Survey of Talise Salt Ponds (Post-Tsunami)
Post-Disaster Survey Engineer
Talise, Kota Palu
Feb 2021 to Apr 2021
Change cover

Writing

+⋮⋮

77 articles across two disciplines and two languages. Includes 20 case studies from building a streaming platform: real problems, what I measured, and what actually fixed them.

Aa Title
◫ Topic
Language
Year
Chasing a p99 That Dwarfed the Median
Case study
EN
2026
The test suite that blamed whichever commit happened to run
Case study
EN
2026
Cursor Pagination and Cache Design for Mobile Lists
Mobile
EN
2026
An Accessibility Pass That Improved the App for Everyone
Case study
EN
2026
When Payments Succeed and the App Disagrees
Case study
EN
2026
The version check that turned a feature into a no-op
Case study
EN
2026
Auditing Push Delivery: Sent Is Not Delivered
Case study
EN
2026
A Release Train With Brakes: Staged Rollouts That Actually Halt
Case study
EN
2026
Breadcrumbs that only exist in debug builds
Case study
EN
2026
Feature Flags: Deploy at 4 PM, Release When Ready
Fullstack
EN
2026
Tuning Adaptive Bitrate for Networks That Actually Exist
Case study
EN
2026
Two widgets, two answers, one bottom bar
Case study
EN
2026
Background Audio That Survives the Lock Screen, on Both Platforms
Case study
EN
2026
The blur that costs you every frame
Case study
EN
2026
A Transcode Queue That Does Not Melt Under a Launch
Case study
EN
2026
Widevine on Mobile: L1, L3, and the Screens In Between
Mobile
EN
2026
Shaving Time Off Playback Start by Fixing the Licence Path
Case study
EN
2026
A whole list rebuilt to keep one badge in sync
Case study
EN
2026
Raising the Crash-Free Rate, and Keeping It There
Case study
EN
2026
The animation that only stutters the first time
Case study
EN
2026
Cutting Cold Start on a Streaming App
Case study
EN
2026
The image encode that froze the whole app
Case study
EN
2026
Offline Downloads With DRM: Licences That Outlive the Network
Case study
EN
2026
Timezone Bugs: Store UTC, Display Local, Stop Guessing
Fullstack
EN
2026
Push Notifications on Aggressive Android OEMs: Why Your Message Never Arrived
Mobile
EN
2026
File Uploads That Scale: Presigned URLs to S3/R2
Fullstack
EN
2025
iOS Code Signing in CI, Explained Like You're Angry About It
Mobile
EN
2025
Webhooks That Don't Lose Money: Signatures, Retries, and Dedupe
Fullstack
EN
2025
Cutting an APK From 48 MB to 19 MB Without Deleting Features
Mobile
EN
2025
Rate Limiting With Redis: Sliding Windows in 20 Lines
Fullstack
EN
2025
Riverpod 3 Without Codegen: State Management That Fits in Your Head
Mobile
EN
2025
JWTs, Sessions, and the Refresh Token Rotation You Actually Need
Fullstack
EN
2025
Your Flutter Tests Are Not Slow - They Are Deadlocked
Mobile
EN
2025
Database Migrations Without the Maintenance Window
Fullstack
EN
2024
Panduan Lengkap: 6 Tahapan Perancangan Struktur Beton Bertulang Berdasarkan SNI 2847:2019
Structures
ID
2024
Red Flags dalam Pengadaan Barang/Jasa Pemerintah: Panduan Deteksi untuk Auditor dan Praktisi
Structures
ID
2024
Wrapping a Closed-Source Vendor SDK Without Breaking Everyone's Build
Mobile
EN
2024
Idempotency Keys: Charging the Card Exactly Once
Fullstack
EN
2024
Automasi Perhitungan Struktur dengan Python: Panduan Praktis untuk Insinyur
Structures
ID
2024
Google Play's 16 KB Page Size Rule Will Reject Your APK - Check It in CI
Mobile
EN
2024
AI di Industri Konstruksi Indonesia: Peluang dan Tantangan 2026
Structures
ID
2024
CORS Errors, Debugged Properly for Once
Fullstack
EN
2024
Migrating from Vercel to Cloudflare: A Complete Redesign Journey
Software
EN
2024
Offline-First Flutter: Architecture That Survives a Dead Signal
Mobile
EN
2024
SOLID Principles: Building Maintainable Software Architecture
Software
EN
2024
The N+1 Query: Your API Is Slow in a Loop
Fullstack
EN
2024
Practical Guide to Reading Structural Drawings Quickly and Accurately
Structures
ID
2024
Perbandingan Sistem Sambungan Baja dan Beton: Analisis Kinerja dan Optimasi Detail
Structures
ID
2023
Kegagalan Sambungan di Lapangan dan Strategi Mitigasinya
Structures
ID
2023
Strategic Talent Blueprint: Penyusunan Tenaga Ahli Bangunan Gedung Negara Studi Kasus >100 Miliar
Structures
ID
2023
Blueprint Guardians: Menjadikan Laporan Konsultansi BGN Sebagai Jejak Keputusan
Structures
ID
2023
Panduan Komprehensif Dokumen Kajian Dampak Lingkungan untuk Pembangunan Gedung (Edisi 2025)
Structures
ID
2023
Blueprint ANDALALIN: Strategi Mobilitas untuk Proyek Gedung dan Kawasan
Structures
ID
2023
Standar & Regulasi Teknis Bangunan Gedung (Edisi Mutakhir): Apa Saja yang Wajib Diacu Perencana?
Structures
ID
2023
Before Sketching, Understand the Site and the Data
Structures
ID
2023
Blueprints Before Groundbreakers: The DED Planning Playbook
Structures
ID
2022
Design First: Building Integrity Through Detail Engineering Design
Structures
ID
2022
Pelat Lantai Bondek untuk Gedung di Palu: Alasan Pemilihan, Kesesuaian Sistem Struktur, dan Desain Komposit yang Aman
Structures
ID
2022
Translasi sebagai Kompas Analisis Dinamik dalam Kerangka SNI 1726
Structures
ID
2022
Perancangan Elastomer Bearing Pad Jembatan: Praktik SNI dan Studi Kasus
Structures
ID
2022
Memahami Perbedaan JavaScript dan Node.js
Software
ID
2022
The Philosophy of 'Hello World' in Software Engineering
Essay
EN
2022
Penggantung Regel: Strategi Desain Efisien untuk Struktur Baja Modern
Structures
ID
2022
From Bootcamp to Coffee Shop App: My Unusual Coding Journey
Software
EN
2021
Stress Ratio pada Baja dan Beton: Evaluasi Berbasis SNI
Structures
ID
2021
Perencanaan Beban Pelat Lantai: Interpretasi SNI 1727 & 2847
Structures
ID
2021
Kategori Risiko dan Beban Gempa: Panduan Praktisi SNI 1726
Structures
ID
2021
Support Reaction Gedung: Penilaian Nyata Berdasarkan SNI
Structures
ID
2021
Kelangsingan Batang Baja: Strategi Desain Sesuai SNI 1729
Structures
ID
2021
Analisis Beban Angin Gedung: Parameter Kunci dalam SNI 1727
Structures
ID
2021
Strategi Sambungan Balok-Komposit untuk Memaksimalkan Kekakuan dan Stabilitas Sistem
Structures
ID
2020
Mengawal Kapasitas Abutment Jembatan dengan Analisis Struktural-Geoteknik
Structures
ID
2020
Mengendalikan Lendutan Vertikal Jembatan Sesuai SNI 1725 & 1729
Structures
ID
2020
From Desktop to Cloud: AutoCAD''s Next Evolution
Structures
EN
2020
The Future of Work: What I''ve Learned as a New Developer
Essay
EN
2020
The Art of Digital Storytelling: Building Narratives Through Code
Software
EN
2020
Building Modern Web Applications: A Developer's Journey
Software
EN
2020
+⋮⋮

All 77 articles open right here. Click any row.

Change cover

Mini Games

+⋮⋮

Nine small games. Most are built around something I actually do for a living, and the three arcade ones come with a walkthrough of how they are built. They take about five minutes each, and every one of them explains its answers, the point is to be mildly educational, not just a score.

+⋮⋮
Set your name once and it carries across every leaderboard. Scores stay in your browser, nothing is sent anywhere, and clearing your site data clears them.
+⋮⋮

Your best runs

+⋮⋮

Scores live in your browser only. Nothing is sent anywhere, and clearing your site data clears them.

Change cover

Cold Case Files

+⋮⋮
0 / 10Filed 0Solved
Case 01

Evidence

    +⋮⋮

    Leaderboard

    +⋮⋮

    Answer options are shuffled each time you play, so a remembered position will not help you.

    Change cover

    Ship or Hold

    +⋮⋮
    Twelve releases, one call each. You are the release manager. Read what is in the build and what the signals say, then ship it or hold it. The scary-looking signal is often irrelevant and the calm release is often the dangerous one, which is the whole job.
    0Correct 0 / 12Decided

    Signals

      +⋮⋮

      Leaderboard

      +⋮⋮

      Nothing here is a trick question. Every call can be made from the signals given, and the explanation says why the other call is tempting.

      Change cover

      Big-O Sprint

      +⋮⋮
      Fourteen snippets, one complexity each. Python, JavaScript, Dart, Rust and SQL. Some ask about time, some about space. The traps are the ordinary ones: a membership test inside a loop, a sort hidden in a helper, a function wrapped around an indexed column.
      0Correct 0 / 14Answered ·Language

      +⋮⋮

      Leaderboard

      +⋮⋮

      Every snippet is real code for the language named above it, syntax-checked before it went in.

      Change cover

      Starfire

      +⋮⋮
      My own game, ported onto this page. Starfire Impact is a ten sector arcade shooter I built as a standalone PWA, sprites and all. This is the same game, wrapped so it can share a page with eight others.

      Arrow keys to fly, space to fire. On a phone, hold and drag anywhere on the field. The fullscreen button gives you the same full viewport the standalone build ran in.

      +⋮⋮

      Leaderboard

      +⋮⋮

      How it works

      This is not a demo written for the site. Starfire Impact is a game I built as a standalone progressive web app: ten sectors, ten bosses, hand made sprites, a full run of about thirteen minutes if you get to the end. The repo is the original. What runs above is that same code, and the port only had to solve two problems.

      Everything was global

      game.js declared Game, Player, Entity, Boss, Enemy and a dozen more at the top level, which is fine on a page it owns and not fine here, where eight other games share one scope and this site already has its own Game. The whole file now sits inside one IIFE and exports exactly three functions: sfInit() builds the markup and binds input, sfStart() opens the page for play, and sfStop() cancels the animation frame, releases every listener and silences the audio. Navigation calls the last one, so the loop is not running while you read the contact page.

      Six megabytes of sprites

      The thirty six PNGs behind the ships, rocks and bosses come to 6 MB. Every page of this site lives in the DOM at once, so if the game loaded its art at parse time, every visitor would pay for it whether or not they came here. Nothing is fetched until the first sfStart(), which is the moment you open this page, and a loading bar covers the wait. A sprite that fails to load leaves its slot empty and the entity falls back to the vector art the game was originally drawn with, so a missing file costs you a nice sprite and not the run.

      Two things I did change

      The standalone sized its canvas to the window, so a laptop gave it about 1500 by 800 units of room. In a column that same field would be four times more crowded for the same spawn rates, which is a harder game, not a smaller one. The field is now a fixed 1280 by 720 that scales into whatever box it is given, so the column and the fullscreen button play identically and fullscreen is bigger rather than easier.

      And I rebalanced it. Almost nobody was reaching the final boss, so I flattened the difficulty slope over sectors 6 to 10, cut boss health growth, capped how many things can be on screen at once, and gave the ship a longer moment of invulnerability after a hit. Sectors 1 to 4 are unchanged. To check it rather than guess, I wrote a bot that plays the real game loop with a hundred millisecond reaction time and ran it sixty times against each version: median sector reached went from 4.5 to 10, and runs that beat the final boss went from none to about three in five.

      Change cover

      Flyer

      +⋮⋮
      One button, thread the gaps. Gravity pulls, a tap lifts. The gap positions are derived from the physics constants rather than guessed, so a reachable gap is always reachable, and the simulation runs on a fixed step so a 144Hz monitor does not make it easier.
      0Score 0Personal best Space or ↑ to flap · P to pause · tap anywhere on the field

      Thread the gaps

      Tap the field or press Space to flap. Gravity does the rest. One point per gap cleared.

      You start with a moment of grace before the first obstacle.
      Run over 0

      Gaps cleared.

      Tap or press Space to fly again

      Paused

      The loop is stopped, not just hidden. Nothing is running while this panel is up.

      Tap or press P to resume
      +⋮⋮

      Leaderboard

      +⋮⋮

      How it works

      The whole game is about 336 lines of vanilla JavaScript drawing into one canvas. Most of those lines are ordinary. The four decisions below are the ones that decide whether it feels like a game or like a bug, so they are the ones worth writing down.

      The physics does not run on the frame rate

      The obvious way to write this loop is to take the delta between two requestAnimationFrame callbacks and integrate with it directly: vy += g * dt; y += vy * dt. That is semi-implicit Euler, and it is stable, but it is not the same simulation at every frame rate. Run the algebra and the closed form for a fall from rest with a fixed frame time h is y(t) = ½·g·t·(t + h). The h term is the frame rate leaking into the physics.

      With this game's gravity of 1400 units per second squared, one second of falling covers 711.7 units at 60Hz and 704.9 units at 144Hz. That is a difference of 6.8 units in the first second alone, on a play field only 360 units tall, and it compounds: every flap arc is slightly flatter and every fall slightly shorter on the faster monitor. A gap that is tight on a laptop is comfortable on a 144Hz display, and the leaderboard stops comparing like with like. The same bug in the other direction is what made a generation of DOS games unplayable on faster hardware.

      So the physics gets its own clock. Time from the frame is poured into an accumulator, and the accumulator is drained in fixed slices of 1/120 s. Every machine integrates exactly the same sequence of steps, and rendering only decides how many of them happen before the next paint. The delta is clamped twice, before and after it enters the accumulator, because a backgrounded tab or a long garbage collection hands back a delta measured in seconds: without the clamp the while loop would queue several hundred steps, take longer than a frame to run, arrive even later, and queue more. That is the spiral of death, and one line prevents it.

      function flLoop(ts){
        flRaf = 0
        if (!flLast) flLast = ts
        let dt = (ts - flLast) / 1000
        flLast = ts
        if (!(dt > 0)) dt = 0
        // Clamp the frame delta before it ever reaches the accumulator. A backgrounded tab or a
        // long GC pause hands back a delta of seconds, and without this the while loop below
        // would queue hundreds of steps, take longer than a frame, and fall further behind.
        if (dt > FL_MAXACC) dt = FL_MAXACC
        flAcc += dt
        if (flAcc > FL_MAXACC) flAcc = FL_MAXACC
        while (flAcc >= FL_STEP){ flStep(FL_STEP); flAcc -= FL_STEP }
        flRender(flAcc / FL_STEP)
        // Idle out instead of spinning: a finished or paused run has nothing left to animate.
        if (flRunning && !((flG.mode === 'over' || flG.mode === 'pause') && flG.shake <= 0))
          flRaf = requestAnimationFrame(flLoop)
      }

      The leftover fraction of a step is handed to the renderer as an interpolation factor, so the avatar and the obstacles are drawn between their last two physics positions rather than snapped to the most recent one. Without that, a 1/120 s simulation on a 60Hz screen judders, because every other paint shows a state the display never asked for.

      Collision is swept, not sampled

      Testing where the avatar is once per frame answers the wrong question. What matters is whether anything lies on the path between where it was and where it now is. If the step is long enough, a solid object thinner than that path sits entirely between two samples and the avatar passes straight through it. This is tunnelling, and it is the reason a fast bullet in a naive engine goes through a wall while a slow one does not.

      Honest accounting for this game: at the fixed 1/120 s step the avatar moves at most about 5.5 units per step, and the obstacles are 46 units wide, so tunnelling is not reachable with the shipped constants. The sweep is load bearing in two other places. The first is the accumulator clamp, where a stalled tab lets one rendered frame advance the world by up to 0.25 s, or 155 units of vertical travel and 57 units of horizontal, more than an obstacle's own width. The second is the future: raise the speed ceiling or widen the step and a point test starts lying long before anyone thinks to re-check the collision code.

      The sweep runs in the obstacle's frame of reference. The avatar holds a fixed x while the world slides left, so relative to an obstacle it moves right and vertically at the same time. Grow the obstacle rectangle by the avatar's half extents (a Minkowski sum, which turns a box-versus-box problem into a segment-versus-box one), then clip the segment against each pair of slabs and see whether any interval survives.

      function flSweep(p0x, p0y, p1x, p1y, hw, hh){
        const d = [p1x - p0x, p1y - p0y], p = [p0x, p0y], h = [hw, hh]
        let t0 = 0, t1 = 1
        for (let a = 0; a < 2; a++){
          if (Math.abs(d[a]) < 1e-9){ if (p[a] < -h[a] || p[a] > h[a]) return false; continue }
          let e0 = (-h[a] - p[a]) / d[a], e1 = (h[a] - p[a]) / d[a]
          if (e0 > e1){ const t = e0; e0 = e1; e1 = t }
          if (e0 > t0) t0 = e0
          if (e1 < t1) t1 = e1
          if (t0 > t1) return false
        }
        return true
      }

      The avatar's box is also inset by 3 units on every side before the sum. Players read a collision as unfair well before the pixels actually touch, so the forgiving box is a design choice, not a rounding error.

      The gap band comes out of the constants

      Randomising the next gap's height is easy and wrong. Sooner or later the generator produces two consecutive gaps further apart than the avatar can physically travel in the time between them, the run ends through no fault of the player, and the game feels arbitrary. So the band is derived rather than chosen.

      A flap sets vertical velocity to -420 rather than adding to it, which makes the arithmetic clean. One flap gains 420² / (2 × 1400) = 63 units before gravity wins. Flapping again the moment velocity returns to zero makes the cycle 420 / 1400 = 0.3 s long, so the sustained climb rate is 63 / 0.3 = 210 units per second, which is exactly half the flap impulse. Falling is bounded instead by the terminal velocity of 620 units per second, which over the same interval covers more than twice the distance, so climbing is the binding direction and the band is sized on it.

      Gap centres are 210 units apart, so the player has 210 / speed seconds between them: 1.4 s at the speed floor of 150, and 0.91 s at the ceiling of 230. The reachable climb is therefore 294 units at the floor and 192 at the ceiling. Sampling inside 55 per cent of that leaves room for an imperfect cadence, and it means the band tightens on its own as the game speeds up, without a second difficulty curve to tune.

      function flBand(speed){
        const T = FL_SPACING / speed
        const up = (Math.abs(FL_FLAP) / 2) * T * 0.55
        const tv = FL_VMAX / FL_GRAV                                  // seconds to terminal velocity
        const fall = T <= tv ? 0.5 * FL_GRAV * T * T
                             : 0.5 * FL_VMAX * tv + FL_VMAX * (T - tv)
        return { up: up, down: Math.min(fall * 0.55, up * 1.5) }
      }

      Difficulty otherwise ramps in two clamped lines: the gap narrows by 2.5 units per point down to a floor of 88, and the scroll speed rises by 3 units per point up to a ceiling of 230. Both floors exist so that a long run gets harder and then stays hard, rather than becoming impossible.

      Input is state, not an event

      A keydown handler that calls the flap directly puts the impulse wherever in the frame the browser happened to deliver the event, which is somewhere between two physics steps. Worse, a press that arrives a few milliseconds before a step is easy to lose entirely if the handler writes to a variable the step has already read. Players notice: it reads as the game dropping inputs, and it is unfalsifiable from the outside, which makes it a miserable bug to be sent.

      So the handler does not flap. It records that a flap was asked for, with a timestamp, and the next physics step consumes it. A press up to 120 ms early still lands on the step that follows. Anything older than that is dropped rather than fired late, which matters when the loop has been idle: the tab was hidden, the run was paused, and a press from before the pause should not launch the avatar on resume.

      The same buffer is what makes the first flap start the run, so pressing early at the ready screen is never wasted. The ready state is also invulnerable for 0.8 s and the first obstacle is placed 430 units ahead of the avatar, which is a little under three seconds of run-in at the starting speed.

      The parts that are not interesting but are still load bearing

      • Pooling. Twelve obstacles are allocated once at init and recycled by flipping a live flag when they leave the left edge. Nothing is allocated during a run, so there is nothing for the garbage collector to collect mid-flight, and no collection pause to show up as a stutter.
      • Device pixel ratio. The canvas backing store is sized to cssPixels × devicePixelRatio, capped at 3, and the context transform folds the ratio together with the world scale. Everything else in the game is written in world units, where the play field is always 360 units tall, so the physics never notices a resize and the same run plays identically on a phone and a desktop. A wider viewport simply sees further ahead.
      • Stopping properly. Every page of this site is in the DOM at once, so a loop left running would burn battery on the contact page. flapStop() cancels the one outstanding frame handle and unbinds the input listeners. There are no timers in the game at all, so there is nothing else to cancel. The loop also idles itself out when a run is over or paused, and visibilitychange pauses rather than letting a hidden tab kill the player.
      • Reduced motion. With prefers-reduced-motion set, the death shake and the idle bob are skipped. The game itself is unchanged, because making it unplayable would be a worse answer than making it still.
      Change cover

      Type Triangle Duel

      +⋮⋮
      You always start in the losing matchup. Grass beats water, water beats fire, fire beats grass. Whichever starter you pick, the opponent is the type that beats it. Your same-type attack is halved, theirs is doubled, and the fight is still winnable: the off-type move is never resisted, the status move drags their attack down, and the guard turn is how you pay for both.
      0Turn Choosing starterPhase

      Pick a starter. The card tells you who you will be fighting before you commit.

      +⋮⋮

      Leaderboard

      +⋮⋮

      How it works

      The game is the starter-triangle format made famous by monster-battling RPGs, with one rule changed: the opponent is never random. It is always the type that beats the one you picked. That turns the whole thing into a puzzle about finding a route out of a losing matchup, and it puts a fair amount of weight on four small pieces of code.

      The type chart is data, not branching

      Effectiveness lives in a nested object keyed by attacking type and then defending type. There is exactly one function that reads it, and no part of the game asks if (type === 'fire').

      const BTL_CHART = {
        grass:   {grass:0.5, fire:0.5, water:2,   neutral:1},
        fire:    {grass:2,   fire:0.5, water:0.5, neutral:1},
        water:   {grass:0.5, fire:2,   water:0.5, neutral:1},
        neutral: {grass:1,   fire:1,   water:1,   neutral:1}
      }
      
      function btlEff(moveType, defType){
        const r = BTL_CHART[moveType]
        return (r && r[defType] != null) ? r[defType] : 1
      }

      The payoff is what happens when a fourth type arrives. With a table you add one row, one column, and nothing else changes: damage, the AI's move scoring, the move tooltips and the chips all keep working because they all go through btlEff. With a chain of conditionals a fourth type means finding every branch that enumerates types and remembering to extend each one, and the branches you miss fail silently as a 1x multiplier rather than as an error. A table also lets you look at the balance as a grid and see, at a glance, that the triangle is symmetric. You cannot eyeball that in an if-chain.

      The neutral row is what makes the game winnable. Every creature carries one off-type move that reads 1x against all three types, so a player stuck at 0.5x with their own type still has a weapon that does not get halved.

      The turn is an explicit state machine

      A turn has more steps than it looks like: your move resolves, the game checks whether that ended the fight, the opponent's move resolves, it checks again, then upkeep ticks the damage-over-time and the stamina regeneration, and only then is input accepted again. Those are named states in a table, and one function moves between them.

      const BTL_FLOW = {
        select:      {pick:'choose'},
        choose:      {move:'resolveYou'},
        resolveYou:  {done:'checkYou'},
        checkYou:    {alive:'resolveFoe', over:'end'},
        resolveFoe:  {done:'checkFoe'},
        checkFoe:    {alive:'upkeep',     over:'end'},
        upkeep:      {alive:'choose',     over:'end'},
        end:         {again:'select'}
      }
      
      function btlSend(ev, payload){
        const next = (BTL_FLOW[BTL.phase] || {})[ev]
        if(!next) return false          /* wrong phase: the event is dropped, not queued */
        BTL.phase = next
        BTL_ENTER[next](payload)
        return true
      }

      Every move button sends the same event, move, and only the choose state has a transition for it. So the guard against double-resolving a turn is not a boolean flag someone has to remember to set and clear, and it is not the disabled attribute on the buttons either. The buttons are disabled as well, but that is presentation. If a click arrives during the animation pause between the two resolve steps, or from a keyboard repeat, or from a second tap on a touchscreen that fired before the re-render, the lookup returns undefined and the event is dropped.

      The bugs this design removes are the ones that turn up late. An implicit state machine, where the turn is a sequence of nested callbacks and timeouts, gives you two players acting twice in one turn because a second click landed inside a setTimeout; it gives you a knockout that is checked only after both sides have moved, so a creature at zero HP still gets its attack in; and it gives you input accepted during an animation, which reads as a dropped click to the player and as an off-by-one turn count to the scoreboard. Each of those is a different fix in the callback version. Here they are the same fix, and it is already made.

      The one thing the state machine does own is the timers. Transitions that pace the animation go through a helper that records the timeout id, so btlStop() can cancel every pending one when the page is left mid-turn.

      Damage is a pure function

      Damage takes the attacker, the defender, the move, the effectiveness multiplier and the random roll, and returns a number. It reads no global state and writes nothing.

      function btlDamage(attacker, defender, move, mult, roll){
        if(move.kind !== 'attack') return 0
        const atk = attacker.atk * btlStageMult(attacker.atkStage)
        const def = defender.def * btlStageMult(defender.defStage)
        const guard = defender.guarding ? BTL_K.guardCut : 1
        return Math.max(1, Math.round(move.power * (atk / def) * mult * roll * guard))
      }

      Pulling the roll out as a parameter rather than calling Math.random() inside is the part that matters. It means the function can be called with roll = 1 to get the expected damage of a move, which is exactly what the opponent AI needs in order to compare its options, and it means the balance can be tested by running whole matches with a scripted policy and no UI. Tuning the game was a loop of running two hundred matches per starter against a competent policy and against a policy that spams the strongest same-type attack, and checking that the first wins comfortably and the second does not. That is only cheap because the rules do not touch the DOM.

      The random band is deliberately narrow, plus or minus six percent. Wide enough that identical turns are not identical, narrow enough that a correct line of play does not lose to variance.

      The opponent is a scoring policy

      The AI does not pick at random and it does not run a search. It scores its four moves in damage-equivalent points and takes the highest.

      function btlAiScore(move, self, foe){
        if(move.cost > self.sp) return -Infinity
        const left = self.sp - move.cost
        if(move.kind === 'attack'){
          /* score against an unguarded foe: a guard lapses the moment its owner acts again */
          const open = Object.assign({}, foe, {guarding:false})
          const est = btlDamage(self, open, move, btlEff(move.mtype, open.type), 1)
          return est - (left < BTL_K.aiReserve ? BTL_K.aiStrain : 0)
        }
        if(move.kind === 'status'){
          return (foe.atkStage > -BTL_K.stageCap ? BTL_K.aiWantAtk : 0)
               + (self.defStage <  BTL_K.stageCap ? BTL_K.aiWantDef : 0)
               + (foe.wound > 0 ? 0 : BTL_K.aiWantWound)
        }
        /* guard: recover when starved, bank when the heavy move is one turn out of reach */
        const heavy = self.moves.filter(m => m.kind === 'attack')
          .reduce((a, b) => a.power >= b.power ? a : b)
        if(self.sp <= BTL_K.aiReserve) return BTL_K.aiBrace
        return self.sp < heavy.cost ? BTL_K.aiBank : 3
      }

      Because it is deterministic given the board, the opponent's next move can be computed at the end of upkeep and shown to the player before they choose, and it will be honest: nothing the player does between the telegraph and the resolution changes the opponent's stamina, so it always commits to what it announced. The player is reading a rule, not a coin flip.

      The behaviour that falls out is a pattern you can learn in three or four attempts. The opponent opens with its doubled same-type attack, which costs most of its stamina bar. It fills the next turns with the cheap off-type move while the bar refills, spends a turn on its status move once neither attack is worth much, and braces when it is nearly empty. Then it saves up and leads with the big attack again. Once you have seen the loop, you know which turn to spend on your guard and which turns are free for the off-type move. Beating it is solving it.

      A scoring policy is also the version you can tune. Every number in that function is a lever with a meaning: aiStrain is how much the opponent dislikes stranding itself without stamina, aiBrace is how urgently it recovers when starved, aiBank is how willing it is to spend a turn saving up for the heavy move. Moving one changes behaviour in a direction you can predict and re-measure with the same two hundred match harness. A tree of conditionals encodes the same decisions in a form where you can only change them by rewriting the tree.

      What is deliberately simple

      There is one status move rather than a menu of them, and it does three things at once: it lowers their attack, raises your defence and sets a wound. Stat stages are linear and capped at plus or minus two rather than the compounding fractions the genre normally uses, because linear stages are easier to read off the chips on the card and easier to reason about when tuning. There is no switching, no items and no accuracy roll. All three would add depth, and none of them would make the central question, which is how to win from behind, any sharper.

      Change cover

      Will It Hold?

      +⋮⋮
      Twelve steel beams, one question each. Look at the section, the span, and the load, then decide whether it passes. Real Indonesian IWF profiles, real yield strengths, and the same flexural check a design reviewer runs: Mu ≤ φMn. You get the full calculation either way.
      0Correct 0 / 12Answered

      +⋮⋮

      Leaderboard

      +⋮⋮
      How the check works

      Demand. For a simply supported beam, midspan moment is wL²/8 under a uniform load, or PL/4 under a single point load at midspan. Span is squared in the first case, which is why adding a metre costs more than it looks.

      Capacity. For a compact section reaching flexural yield, Mn = Zx · fy, reduced by φ = 0.90. Zx is the plastic section modulus of the profile; fy is 240 MPa for BJ 37 and 250 MPa for BJ 41.

      Verdict. It passes when Mu ≤ φMn. A ratio of 1.05 is not "close enough": φ is already the margin.

      Simplified for the game: no lateral-torsional buckling check, no deflection limit, no self-weight. In practice all three decide real sections, and deflection governs more often than strength on long spans.

      +⋮⋮

      This is the judgement I used across 82 construction projects. Prefer keyboards to beams? Try the Typing Test.

      Change cover

      Spot the Bug

      +⋮⋮
      Ten snippets, one bug each. Click the line that causes the problem described above it. Every bug here is one I have actually shipped, reviewed, or been paged for, the explanations are the same ones I would leave in a code review.
      0Found 0 / 10Answered ·Language

      +⋮⋮

      Leaderboard

      +⋮⋮

      Most of these have a case study behind them on the Writing page.

      Change cover

      Latency Estimator

      +⋮⋮
      How long does it take? Drag the slider to your estimate, the scale is logarithmic, from a nanosecond to a few seconds. You are scored on orders of magnitude, not precision: 3 points within half an order, 2 within one, 1 within two.
      0Points 0 / 12Answered

      ·
      1 ns1 µs1 ms1 s
      +⋮⋮

      Leaderboard

      +⋮⋮
      Why this matters more than it looks

      Knowing that a datacentre round trip is sub-millisecond while a Jakarta–US round trip is a couple of hundred tells you where to put the API, when a cache is worth it, and which loops will never be fast enough.

      The specific numbers change with hardware. The ratios do not, and those are what let you predict whether something will be slow before you build it.

      Change cover

      Typing Test

      +⋮⋮
      Real Rust code, 30 seconds. Click the code and start typing, the timer starts on your first keystroke. Press Enter at line ends; indentation is automatic. Finish a snippet and the next one loads.
      0WPM100%Accuracy30Seconds left
      +⋮⋮

      Leaderboard

      +⋮⋮

      Everyone who plays on this browser keeps their row. I also built Story Typer, a kids' version with a narrative instead of a code snippet, private repo, but happy to demo it.

      Change cover


      ← Back to Writing
      Change cover

      Contact

      +⋮⋮
      Setyo Aji Imam Maliki Setyo Aji Imam Maliki · Software engineer (fullstack, mobile-focused) · certified civil engineer
      Not looking for a role, but always glad to talk: interesting problems, collaborations, or just comparing notes. Response within 48 hours.
      +⋮⋮

      Off the record

      +⋮⋮
      Not everything I write has a code block in it

      Somewhere on Wattpad there is a story about two people, one city, and the rain that keeps deciding things for them. It runs in two directions at once, that is the whole trick of it.

      It is filed under the same handle I use everywhere else. I am not going to link it; a story you had to look for reads better than one that was handed to you.

      Hint: it starts after the rain.

      +⋮⋮

      Colophon. The interface is inspired by Notion. Everything under it is built from scratch: one static HTML file, no framework, no build step, zero external scripts or stylesheets.

      What should we call you?

      Your name goes on the leaderboard for every game here, it stays in this browser and is never sent anywhere.