[{"data":1,"prerenderedAt":855},["ShallowReactive",2],{"writing-id":3},[4,544,825],{"id":5,"title":6,"body":7,"cover":93,"date":528,"description":529,"draft":530,"extension":531,"meta":532,"navigation":533,"original":534,"path":535,"seo":536,"stem":537,"tags":538,"__hash__":543},"writing_id\u002Fwriting\u002Fclaude-code-content-plan.md","Mengubah rencana konten 30 hari menjadi draft artikel dengan Claude Code",{"type":8,"value":9,"toc":516},"minimark",[10,21,24,29,32,56,63,67,75,87,94,99,111,184,187,208,212,226,308,311,315,322,330,337,340,346,350,353,356,384,388,391,394,405,416,436,439,442,468,472,492,496,499,505,512],[11,12,13,20],"p",{},[14,15,19],"a",{"href":16,"rel":17},"https:\u002F\u002Fkatili.dev",[18],"nofollow","katili.dev"," — studio hosting dan web development milik saya — punya blog bilingual. Tiap bulan saya merencanakan sekitar 30 artikel di spreadsheet (judul, deskripsi, kategori, bahasa, link referensi, dan prompt siap pakai), meng-import-nya ke admin panel Laravel, lalu mengerjakannya satu per satu, hari demi hari.",[11,22,23],{},"Bagian yang paling makan waktu adalah menghasilkan artikelnya — dan penyebabnya justru bukan proses menulis itu sendiri.",[25,26,28],"h2",{"id":27},"rutinitas-copy-paste","Rutinitas copy-paste",[11,30,31],{},"Untuk setiap artikel, alurnya kurang lebih begini:",[33,34,35,39,47,50,53],"ol",{},[36,37,38],"li",{},"Buka project Claude yang instruksinya berisi panduan menulis saya (struktur, gaya bahasa, field SEO, dan format JSON persis yang dibutuhkan importer saya).",[36,40,41,42,46],{},"Kembali ke admin panel, cari hari yang dimaksud, klik ",[43,44,45],"strong",{},"Copy Prompt",".",[36,48,49],{},"Pindah tab, buka chat baru di project tadi, paste, lalu tunggu.",[36,51,52],{},"Copy response JSON-nya, buka halaman import, paste, import.",[36,54,55],{},"Kembali ke content plan, tandai hari itu selesai, lalu link ke post yang baru.",[11,57,58,59,62],{},"Lima kali context switch untuk satu artikel, tiga puluh artikel sebulan. Tidak ada yang sulit; semuanya cuma bikin repot. Saya ingin cukup mengetik satu perintah lalu kembali dan mendapati draft-nya sudah jadi — ",[43,60,61],{},"tanpa"," memasang API key AI di server dan membayar per token, padahal saya sudah berlangganan dan memakainya setiap hari.",[25,64,66],{"id":65},"idenya-claude-code-yang-mengemudi-server-cukup-jadi-pelayan","Idenya: Claude Code yang mengemudi, server cukup jadi \"pelayan\"",[11,68,69,70,74],{},"Claude Code sudah berjalan di terminal saya, di dalam repository. Ia bisa menjalankan shell command, fetch halaman web, menulis file, dan menjalankan subagent dengan model pilihan. Jadi server tidak perlu ",[71,72,73],"em",{},"menghasilkan"," apa-apa. Server cukup:",[76,77,78,81,84],"ul",{},[36,79,80],{},"memberi tahu Claude isi content plan-nya,",[36,82,83],{},"memberikan prompt untuk satu item,",[36,85,86],{},"menerima JSON yang sudah jadi lalu meng-import-nya.",[11,88,89],{},[90,91],"img",{"alt":92,"src":93},"Alurnya: Claude Code memanggil API kecil melalui script bash; satu subagent per artikel","\u002Fimages\u002Fwriting\u002Fclaude-code-content-plan\u002Fflow.svg",[95,96,98],"h3",{"id":97},"_1-api-kecil-yang-sengaja-dibuat-sederhana","1. API kecil yang sengaja dibuat sederhana",[11,100,101,102,106,107,110],{},"Lima route di ",[103,104,105],"code",{},"routes\u002Fapi.php",", di balik satu middleware yang mencocokkan Bearer token dengan environment variable memakai ",[103,108,109],{},"hash_equals",". Tanpa Sanctum, tanpa tabel user — ini tool untuk single user.",[112,113,114,127],"table",{},[115,116,117],"thead",{},[118,119,120,124],"tr",{},[121,122,123],"th",{},"Endpoint",[121,125,126],{},"Kegunaan",[128,129,130,141,154,164,174],"tbody",{},[118,131,132,138],{},[133,134,135],"td",{},[103,136,137],{},"GET \u002Fapi\u002Fcontent-plans",[133,139,140],{},"daftar content plan beserta jumlah item selesai \u002F sedang dikerjakan \u002F belum",[118,142,143,148],{},[133,144,145],{},[103,146,147],{},"GET \u002Fapi\u002Fcontent-plans\u002F{plan}\u002Fitems",[133,149,150,151,153],{},"daftar item ",[43,152,61],{}," prompt",[118,155,156,161],{},[133,157,158],{},[103,159,160],{},"GET \u002Fapi\u002Fcontent-plan-items\u002F{item}",[133,162,163],{},"satu item lengkap dengan prompt dan referensinya",[118,165,166,171],{},[133,167,168],{},[103,169,170],{},"PATCH \u002Fapi\u002Fcontent-plan-items\u002F{item}",[133,172,173],{},"mengubah status",[118,175,176,181],{},[133,177,178],{},[103,179,180],{},"POST \u002Fapi\u002Fcontent-plan-items\u002F{item}\u002Fimport",[133,182,183],{},"meng-import artikel yang sudah di-generate",[11,185,186],{},"Ada dua keputusan yang lebih penting daripada route-nya sendiri:",[76,188,189,195],{},[36,190,191,194],{},[43,192,193],{},"Kalau token kosong, API mati"," (403), bukan malah terbuka. Lupa mengisi env var jangan sampai membuat endpoint import bisa diakses siapa saja.",[36,196,197,204,205,46],{},[43,198,199,200,203],{},"Import memakai ulang command ",[103,201,202],{},"blog:import-json"," yang sudah ada"," — code path yang sama dengan yang dipakai halaman admin. Endpoint menyimpan JSON di disk yang sama, menjalankan command itu, lalu membaca kembali ID post yang dibuatnya. Jadi tetap hanya ada satu pintu masuk artikel ke database, dan setiap post baru selalu masuk sebagai ",[43,206,207],{},"draft",[95,209,211],{"id":210},"_2-client-bash-bukan-client-yang-canggih","2. Client bash, bukan client yang canggih",[11,213,214,217,218,221,222,225],{},[103,215,216],{},"bin\u002Fcontent-plan"," hanyalah bash dan ",[103,219,220],{},"curl"," — tanpa ",[103,223,224],{},"jq",", tidak perlu install apa pun:",[227,228,233],"pre",{"className":229,"code":230,"language":231,"meta":232,"style":232},"language-bash shiki shiki-themes github-light github-dark","bin\u002Fcontent-plan plans\nbin\u002Fcontent-plan items 1          # apa yang masih harus dikerjakan\nbin\u002Fcontent-plan show 42          # prompt lengkapnya\nbin\u002Fcontent-plan check 42 a.json  # hanya validasi (dry run)\nbin\u002Fcontent-plan import 42 a.json # post draft, item ditandai selesai\n","bash","",[103,234,235,247,263,277,293],{"__ignoreMap":232},[236,237,240,243],"span",{"class":238,"line":239},"line",1,[236,241,216],{"class":242},"sScJk",[236,244,246],{"class":245},"sZZnC"," plans\n",[236,248,250,252,255,259],{"class":238,"line":249},2,[236,251,216],{"class":242},[236,253,254],{"class":245}," items",[236,256,258],{"class":257},"sj4cs"," 1",[236,260,262],{"class":261},"sJ8bj","          # apa yang masih harus dikerjakan\n",[236,264,266,268,271,274],{"class":238,"line":265},3,[236,267,216],{"class":242},[236,269,270],{"class":245}," show",[236,272,273],{"class":257}," 42",[236,275,276],{"class":261},"          # prompt lengkapnya\n",[236,278,280,282,285,287,290],{"class":238,"line":279},4,[236,281,216],{"class":242},[236,283,284],{"class":245}," check",[236,286,273],{"class":257},[236,288,289],{"class":245}," a.json",[236,291,292],{"class":261},"  # hanya validasi (dry run)\n",[236,294,296,298,301,303,305],{"class":238,"line":295},5,[236,297,216],{"class":242},[236,299,300],{"class":245}," import",[236,302,273],{"class":257},[236,304,289],{"class":245},[236,306,307],{"class":261}," # post draft, item ditandai selesai\n",[11,309,310],{},"Script ini sama enaknya dipakai manual maupun oleh Claude — tanda bahwa interface-nya sudah pas.",[95,312,314],{"id":313},"_3-satu-skill-satu-subagent-per-artikel","3. Satu skill, satu subagent per artikel",[11,316,317,318,321],{},"Sebuah project skill (",[103,319,320],{},".claude\u002Fskills\u002Fgenerate-blog\u002FSKILL.md",") meringkas seluruh rutinitas tadi menjadi:",[227,323,328],{"className":324,"code":326,"language":327,"meta":232},[325],"language-text","\u002Fgenerate-blog 1 3,5,7-9 sonnet\n","text",[103,329,326],{"__ignoreMap":232},[11,331,332,333,336],{},"Artinya: content plan 1, item 3, 5, 7, 8, dan 9, ditulis oleh Sonnet (default-nya Opus). Untuk setiap item, main session menjalankan ",[43,334,335],{},"satu subagent"," dengan model yang dipilih. Subagent itu membaca panduan menulis langsung dari repository, meminta prompt item tersebut ke API, fetch link referensi, menulis JSON bilingual, memvalidasinya lewat dry run, membereskan apa pun yang ditolak server, lalu meng-import-nya.",[11,338,339],{},"Setelah selesai, ia cukup membalas dengan satu baris:",[227,341,344],{"className":342,"code":343,"language":327,"meta":232},[325],"OK 42 | Apa Itu Harness dalam AI Agent? | #101 (id), #102 (en) · draft\n",[103,345,343],{"__ignoreMap":232},[25,347,349],{"id":348},"mendesain-demi-hemat-token-bukan-sekadar-fitur","Mendesain demi hemat token, bukan sekadar fitur",[11,351,352],{},"Tantangan yang menarik di sini bukan soal fungsionalitas, melainkan ukuran context. Versi yang naif akan menjejalkan panduan 7,6 KB, tiga puluh prompt, belasan halaman web, dan semua artikel yang sudah jadi ke dalam satu percakapan. Di artikel kelima session-nya sudah lambat dan mahal; di artikel kesepuluh ia mulai lupa isi panduannya.",[11,354,355],{},"Ada tiga pilihan yang membuatnya tetap ramping:",[76,357,358,372,378],{},[36,359,360,363,364,367,368,371],{},[43,361,362],{},"Teks, bukan JSON, untuk apa pun yang dibaca model."," Setiap ",[103,365,366],{},"GET"," menerima ",[103,369,370],{},"?format=text"," dan mengembalikan tabel ringkas yang pipe-delimited. JSON mengulang setiap key di setiap baris, dan model harus \"membayar\" setiap pengulangan itu.",[36,373,374,377],{},[43,375,376],{},"Prompt hanya diambil saat dibutuhkan."," Daftar item tidak pernah menyertakan prompt. Hanya item yang sedang ditulis yang mengambil prompt-nya.",[36,379,380,383],{},[43,381,382],{},"Subagent sebagai context firewall."," Panduan, referensi, dan artikelnya hanya ada di dalam context subagent, lalu hilang begitu ia selesai. Main session hanya melihat satu tabel di awal dan satu baris hasil per artikel — jadi biaya artikel kesepuluh kurang lebih sama dengan artikel pertama.",[25,385,387],{"id":386},"supaya-bisa-jalan-dari-browser-juga","Supaya bisa jalan dari browser juga",[11,389,390],{},"Saya ingin perintah yang sama bisa dijalankan dari Claude Code versi web, supaya bisa memulai satu batch langsung dari ponsel. Cloud session punya tiga perbedaan dengan laptop saya: repository-nya hasil fresh clone (file config lokal saya tidak ikut), outbound traffic-nya melewati network policy, dan tidak ada orang yang meng-approve setiap command.",[11,392,393],{},"Urusan config gampang — script sekarang membaca environment variable lebih dulu, baru file lokal, jadi token bisa disimpan di environment settings cloud.",[11,395,396,397,400,401,404],{},"Urusan network-nya yang lebih menarik. Waktu saya coba, proxy session menolak koneksi ke domain saya dengan ",[43,398,399],{},"403",". Padahal API saya ",[71,402,403],{},"juga"," menjawab 403 saat dimatikan, dan 401 untuk token yang salah. Dari sisi script, \"token kamu salah\" dan \"kamu tidak boleh keluar dari sandbox ini\" kelihatan sama persis, padahal cara memperbaikinya jauh berbeda.",[11,406,407,408,411,412,415],{},"Solusinya cukup satu response header. Middleware menyisipkan ",[103,409,410],{},"X-Content-Plan-Api: 1"," di ",[43,413,414],{},"setiap"," response, termasuk 401 dan 403 miliknya sendiri. Script lalu memeriksanya:",[76,417,418,425],{},[36,419,420,421,424],{},"ada header → yang menjawab adalah API; exit code ",[43,422,423],{},"1"," beserta pesan dari API itu sendiri;",[36,426,427,428,431,432,435],{},"tidak ada header → yang menjawab pihak lain (proxy, host yang salah, atau server yang belum men-deploy route-nya); exit code ",[43,429,430],{},"2"," dengan awalan ",[103,433,434],{},"NETWORK:"," dan petunjuk untuk mengizinkan domain tersebut.",[11,437,438],{},"Skill membaca exit code itu dan memberi tahu saya setting mana persisnya yang perlu diubah — tanpa pernah meminta saya paste token ke chat.",[11,440,441],{},"Dua safeguard kecil lainnya muncul dari pertanyaan yang sama: \"bagaimana kalau ada dua 'saya' yang menjalankan ini bersamaan?\"",[76,443,444,458],{},[36,445,446,449,450,453,454,457],{},[43,447,448],{},"Lock per item saat import."," Session di laptop dan session di web (atau dua subagent yang jalan paralel) bisa sama-sama lolos pengecekan \"apakah item ini sudah punya post?\" sebelum salah satunya selesai. Sekarang import memasang cache lock per item, membaca ulang item di dalam lock itu, dan membalas ",[43,451,452],{},"423"," ke pihak yang kalah. Item yang sudah punya post mendapat ",[43,455,456],{},"409",", kecuali saya sengaja memaksa re-import.",[36,459,460,463,464,467],{},[43,461,462],{},"Non-interactive mode."," ",[103,465,466],{},"\u002Fgenerate-blog next 2"," mengambil dua item berikutnya yang belum selesai tanpa bertanya apa-apa, jadi bisa dijalankan sebagai scheduled task. Hasilnya tetap draft; keputusan untuk publish tetap di tangan manusia.",[25,469,471],{"id":470},"yang-sengaja-tidak-saya-buat","Yang sengaja tidak saya buat",[76,473,474,480,486],{},[36,475,476,479],{},[43,477,478],{},"Tidak ada AI call di server."," Server hanya menyimpan dan meng-import; penulisannya terjadi di tool yang memang sudah saya bayar.",[36,481,482,485],{},[43,483,484],{},"Tidak ada auto-publish."," Artikel yang di-generate berstatus draft. Saya tetap membaca, mengedit, dan menjadwalkan setiap artikel sendiri.",[36,487,488,491],{},[43,489,490],{},"Tidak ada perubahan permission yang di-commit atas nama saya."," Allow-list yang memungkinkan cloud session berjalan tanpa diawasi hanya didokumentasikan, tidak di-commit — itu keputusan pemilik repository, bukan agent yang menulis fiturnya.",[25,493,495],{"id":494},"hasilnya","Hasilnya",[11,497,498],{},"Rutinitas yang tadinya lima kali pindah tab per artikel kini cukup satu baris untuk satu batch penuh:",[227,500,503],{"className":501,"code":502,"language":327,"meta":232},[325],"\u002Fgenerate-blog next 3\n",[103,504,502],{"__ignoreMap":232},[11,506,507,508,511],{},"Beberapa menit kemudian, tiga draft bilingual sudah ada di admin panel, masing-masing ter-link ke harinya di kalender content plan, dengan source JSON-nya tersimpan bersama hasil import lainnya. Seluruh fitur ini kira-kira 550 baris PHP dan bash plus satu skill Markdown, dengan 14 feature test — dan sebagian besar pemikirannya justru tercurah pada apa yang ",[71,509,510],{},"tidak"," perlu dibaca model.",[513,514,515],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":232,"searchDepth":249,"depth":249,"links":517},[518,519,524,525,526,527],{"id":27,"depth":249,"text":28},{"id":65,"depth":249,"text":66,"children":520},[521,522,523],{"id":97,"depth":265,"text":98},{"id":210,"depth":265,"text":211},{"id":313,"depth":265,"text":314},{"id":348,"depth":249,"text":349},{"id":386,"depth":249,"text":387},{"id":470,"depth":249,"text":471},{"id":494,"depth":249,"text":495},"2026-10-03","Cara saya mengganti rutinitas copy-paste antartab browser dengan satu slash command — API kecil yang diproteksi token, client bash, dan satu subagent per artikel supaya context-nya tetap kecil.",false,"md",{},true,"en","\u002Fwriting\u002Fclaude-code-content-plan",{"title":6,"description":529},"writing\u002Fclaude-code-content-plan",[539,540,541,542],"Engineering","AI","Laravel","Claude Code","TgfrggMql3eQq69Zn05Z9DlghKGQis5lR2JFF3_untE",{"id":545,"title":546,"body":547,"cover":814,"date":815,"description":816,"draft":530,"extension":531,"meta":817,"navigation":533,"original":534,"path":818,"seo":819,"stem":820,"tags":821,"__hash__":824},"writing_id\u002Fwriting\u002Fbuilding-this-portfolio.md","Membangun ulang portofolio saya dengan Nuxt 4 dan Nuxt Content",{"type":8,"value":548,"toc":808},[549,556,563,567,570,739,750,754,757,787,791,798,802,805],[11,550,551,552,555],{},"Situs lama saya memakai tema Hugo berbasis Bootstrap, ditambah beberapa inline script dan segudang ",[103,553,554],{},"!important"," demi dark mode. Situsnya jalan, tapi setiap kali menambah project saya harus meng-copy tabel gambar di Markdown sambil berharap layout-nya tidak berantakan.",[11,557,558,559,562],{},"Target rebuild ini: ",[43,560,561],{},"content terpisah dari presentation",", dan situsnya sendiri bisa jadi salah satu karya di portofolio.",[25,564,566],{"id":565},"content-sebagai-source-of-truth","Content sebagai source of truth",[11,568,569],{},"Setiap project cukup satu file Markdown. Front-matter-nya divalidasi dengan schema, jadi kalau ada field yang lupa diisi, build-nya yang gagal — bukan halamannya yang rusak.",[227,571,575],{"className":572,"code":573,"language":574,"meta":232,"style":232},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F content.config.ts\nprojects: defineCollection({\n  type: 'page',\n  source: 'projects\u002F*.md',\n  schema: z.object({\n    category: z.string(),\n    year: z.number(),\n    role: z.string(),\n    featured: z.boolean().default(false),\n    metrics: z.array(z.object({ value: z.string(), label: z.string() })).default([]),\n    cover: z.string(),\n  }),\n}),\n","ts",[103,576,577,582,597,608,618,628,640,651,661,685,717,727,733],{"__ignoreMap":232},[236,578,579],{"class":238,"line":239},[236,580,581],{"class":261},"\u002F\u002F content.config.ts\n",[236,583,584,587,591,594],{"class":238,"line":249},[236,585,586],{"class":242},"projects",[236,588,590],{"class":589},"sVt8B",": ",[236,592,593],{"class":242},"defineCollection",[236,595,596],{"class":589},"({\n",[236,598,599,602,605],{"class":238,"line":265},[236,600,601],{"class":589},"  type: ",[236,603,604],{"class":245},"'page'",[236,606,607],{"class":589},",\n",[236,609,610,613,616],{"class":238,"line":279},[236,611,612],{"class":589},"  source: ",[236,614,615],{"class":245},"'projects\u002F*.md'",[236,617,607],{"class":589},[236,619,620,623,626],{"class":238,"line":295},[236,621,622],{"class":589},"  schema: z.",[236,624,625],{"class":242},"object",[236,627,596],{"class":589},[236,629,631,634,637],{"class":238,"line":630},6,[236,632,633],{"class":589},"    category: z.",[236,635,636],{"class":242},"string",[236,638,639],{"class":589},"(),\n",[236,641,643,646,649],{"class":238,"line":642},7,[236,644,645],{"class":589},"    year: z.",[236,647,648],{"class":242},"number",[236,650,639],{"class":589},[236,652,654,657,659],{"class":238,"line":653},8,[236,655,656],{"class":589},"    role: z.",[236,658,636],{"class":242},[236,660,639],{"class":589},[236,662,664,667,670,673,676,679,682],{"class":238,"line":663},9,[236,665,666],{"class":589},"    featured: z.",[236,668,669],{"class":242},"boolean",[236,671,672],{"class":589},"().",[236,674,675],{"class":242},"default",[236,677,678],{"class":589},"(",[236,680,681],{"class":257},"false",[236,683,684],{"class":589},"),\n",[236,686,688,691,694,697,699,702,704,707,709,712,714],{"class":238,"line":687},10,[236,689,690],{"class":589},"    metrics: z.",[236,692,693],{"class":242},"array",[236,695,696],{"class":589},"(z.",[236,698,625],{"class":242},[236,700,701],{"class":589},"({ value: z.",[236,703,636],{"class":242},[236,705,706],{"class":589},"(), label: z.",[236,708,636],{"class":242},[236,710,711],{"class":589},"() })).",[236,713,675],{"class":242},[236,715,716],{"class":589},"([]),\n",[236,718,720,723,725],{"class":238,"line":719},11,[236,721,722],{"class":589},"    cover: z.",[236,724,636],{"class":242},[236,726,639],{"class":589},[236,728,730],{"class":238,"line":729},12,[236,731,732],{"class":589},"  }),\n",[236,734,736],{"class":238,"line":735},13,[236,737,738],{"class":589},"}),\n",[11,740,741,742,745,746,749],{},"Cukup tambahkan ",[103,743,744],{},"content\u002Fprojects\u002Fmy-project.md",", halaman ",[103,747,748],{},"\u002Fwork\u002Fmy-project"," langsung tersedia — tanpa menyentuh satu component pun.",[25,751,753],{"id":752},"component-langsung-di-markdown","Component langsung di Markdown",[11,755,756],{},"Case study bisa memanggil component langsung dari Markdown, misalnya architecture explorer dan animated metrics:",[227,758,761],{"className":759,"code":760,"language":531,"meta":232,"style":232},"language-md shiki shiki-themes github-light github-dark","::architecture-explorer{:nodes=\"architecture\"}\n::\n\n::metric-grid{:metrics=\"metrics\"}\n::\n",[103,762,763,768,773,778,783],{"__ignoreMap":232},[236,764,765],{"class":238,"line":239},[236,766,767],{},"::architecture-explorer{:nodes=\"architecture\"}\n",[236,769,770],{"class":238,"line":249},[236,771,772],{},"::\n",[236,774,775],{"class":238,"line":265},[236,776,777],{"emptyLinePlaceholder":533},"\n",[236,779,780],{"class":238,"line":279},[236,781,782],{},"::metric-grid{:metrics=\"metrics\"}\n",[236,784,785],{"class":238,"line":295},[236,786,772],{},[25,788,790],{"id":789},"animasi-secukupnya-hanya-kalau-membantu","Animasi secukupnya, hanya kalau membantu",[11,792,793,794,797],{},"Cukup satu animation library (GSAP), dan hanya di-load di client-side. Scroll animation dan counter mengikuti setting ",[103,795,796],{},"prefers-reduced-motion","; kalau setting itu aktif, semua konten langsung tampil tanpa animasi.",[25,799,801],{"id":800},"static-by-default","Static by default",[11,803,804],{},"Semua halaman di-prerender, image dioptimasi saat build, lalu seluruh situs di-deploy ke GitHub Pages sebagai static file.",[513,806,807],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":232,"searchDepth":249,"depth":249,"links":809},[810,811,812,813],{"id":565,"depth":249,"text":566},{"id":752,"depth":249,"text":753},{"id":789,"depth":249,"text":790},{"id":800,"depth":249,"text":801},null,"2026-09-29","Kenapa saya pindah dari tema Hugo ke Nuxt, dan bagaimana content, image, serta animasinya saya susun supaya menambah project cukup dengan satu file Markdown.",{},"\u002Fwriting\u002Fbuilding-this-portfolio",{"title":546,"description":816},"writing\u002Fbuilding-this-portfolio",[539,822,823],"Nuxt","Desain","bOaecCcBQ71mSz0VrhzKOVIy2O_Q28yyMvPeWnq9J6k",{"id":826,"title":827,"body":828,"cover":835,"date":844,"description":845,"draft":530,"extension":531,"meta":846,"navigation":533,"original":847,"path":848,"seo":849,"stem":850,"tags":851,"__hash__":854},"writing_id\u002Fwriting\u002Fanak-anak-masjid.md","Anak-anak di Masjid Umar Bin Khattab Bypass",{"type":8,"value":829,"toc":842},[830,836,839],[11,831,832],{},[90,833],{"alt":834,"src":835},"Anak-anak di masjid","\u002Fimages\u002Fwriting\u002Fanak-anak-masjid\u002Fcover.png",[11,837,838],{},"Kami baru saja selesai salat Jumat di Masjid Umar Bin Khattab, Bypass. Kami duduk sejenak sambil bersantai, menunggu awan lewat di langit untuk melindungi kami dari terik matahari Gorontalo — saking panasnya, konon katanya di sini mataharinya ada dua, wkwk.",[11,840,841],{},"Lalu kami dikagetkan oleh kesibukan anak-anak kecil di sekeliling kami. Awalnya saya kira mereka sedang bermain, ternyata mereka sedang membantu merapikan karpet masjid yang baru selesai dipakai jemaah. Wajah-wajah kecil itu langsung berseri-seri ketika bapak takmir memberi mereka uang 2.000 rupiah. Senyum polos mereka menebar kebahagiaan. Pemandangan seperti ini jarang terlihat, jadi saya memutuskan untuk mengabadikan momen itu.",{"title":232,"searchDepth":249,"depth":249,"links":843},[],"2022-05-24","Catatan kecil selepas salat Jumat — tentang senyum anak-anak yang merapikan karpet masjid.",{},"id","\u002Fwriting\u002Fanak-anak-masjid",{"title":827,"description":845},"writing\u002Fanak-anak-masjid",[852,853],"Personal","Cerita","k2CHGAsuA7JftwgEnkr5FsbyGeQJ7csb0TaJrgsb06E",1791117946699]