[{"data":1,"prerenderedAt":232},["ShallowReactive",2],{"api:\u002Fapi\u002Fconfig:en":3,"api:\u002Fapi\u002Fprofile:":8,"api:\u002Fapi\u002Fcategories:en":20,"api:\u002Fapi\u002Fprojects\u002Fdocs-engine:en":164,"api:\u002Fapi\u002Fnotes:en":211},{"email":4,"lang":5,"name":6,"role":7},"hello@ewsirdev.example","en","Ewsirdev","Web developer: websites, landing pages and Go services",{"name":6,"handle":6,"contacts":9,"note":19},{"email":10,"github":13,"telegram":16},{"url":11,"label":4,"placeholder":12},"mailto:hello@ewsirdev.example",true,{"url":14,"label":15},"https:\u002F\u002Fgithub.com\u002Fewsir247","github.com\u002Fewsir247",{"url":17,"label":18},"https:\u002F\u002Ft.me\u002FEwsirdev","@Ewsirdev","email is a placeholder on a reserved domain: mail is not delivered. Telegram is the real channel. This file is the single source of contacts for the site, the contact block, JSON-LD sameAs, security.txt and llms.txt.",[21,50,78,100,136],{"slug":22,"title":23,"blurb":24,"variant":25,"palette":26,"layout":27,"count":28,"preview":29,"stack":45},"landings","Landing pages","One page, one job. Hand-written markup where possible, plus one WebGL experiment.","drop","cold","shots",6,[30,35,40],{"slug":31,"title":32,"shot":33,"hue":34},"landing-studio","Halftone: lighting studio","\u002Fshots\u002Flanding-studio-desktop-sm.webp",212,{"slug":36,"title":37,"shot":38,"hue":39},"landing-saas","Kill Switch: subscription tracker","\u002Fshots\u002Flanding-saas-desktop-sm.webp",182,{"slug":41,"title":42,"shot":43,"hue":44},"landing-event","Small Scale: conference","\u002Fshots\u002Flanding-event-desktop-sm.webp",124,[46,47,48,49],"CSS","HTML","GitHub Actions","JS",{"slug":51,"title":52,"blurb":53,"variant":54,"palette":55,"layout":56,"count":57,"preview":58,"stack":74},"sites","Multi-page sites","Sites with their own structure, routing and forms: from a client project to a set of niche pages.","lens","mono","frames",3,[59,64,69],{"slug":60,"title":61,"shot":62,"hue":63},"legal-multipage-site","Multi-page legal services website","\u002Fshots\u002Flegal-multipage-site-desktop-sm.webp",250,{"slug":65,"title":66,"shot":67,"hue":68},"niche-landings","Catalog of 10 niche demo landing pages","\u002Fshots\u002Fniche-landings-desktop-sm.webp",32,{"slug":70,"title":71,"shot":72,"hue":73},"docs-engine","Sverlo: a documentation generator in Node.js","\u002Fshots\u002Fdocs-engine-desktop-sm.webp",25,[48,75,76,77],"Vue 3","Bootstrap 5","Cloudflare Pages",{"slug":79,"title":80,"blurb":81,"variant":82,"palette":83,"layout":84,"count":85,"preview":86,"stack":97},"apps","Web apps","Interface plus server: auth, data, e-mail. Apps you sign in to.","merge","warm","phone",2,[87,92],{"slug":88,"title":89,"shot":90,"hue":91},"bad-club-booking-app","Bad Club: seat booking for a gaming coworking space","\u002Fshots\u002Fbad-club-booking-app-desktop-sm.webp",150,{"slug":93,"title":94,"shot":95,"hue":96},"typing-lab","typing-lab: a touch-typing trainer","\u002Fshots\u002Ftyping-lab-desktop-sm.webp",45,[75,77,98,99],"Express","GSAP",{"slug":101,"title":102,"blurb":103,"variant":104,"palette":105,"layout":106,"count":107,"langs":108,"preview":117,"stack":133},"backend","Backends","Services with an API, a database and tests: mostly Go, with some in Python and TypeScript. A language filter sits inside the section.","torus","acid","list",14,[109,112,115],{"lang":110,"count":111},"Go",12,{"lang":113,"count":114},"Python",1,{"lang":116,"count":114},"TypeScript",[118,123,128],{"slug":119,"title":120,"shot":121,"hue":122},"kanban-tasks","Amber: kanban board","\u002Fshots\u002Fkanban-tasks-desktop-sm.webp",344,{"slug":124,"title":125,"shot":126,"hue":127},"link-shortener","Short: link shortener","\u002Fshots\u002Flink-shortener-desktop-sm.webp",111,{"slug":129,"title":130,"shot":131,"hue":132},"booking-slots","Appointment booking","\u002Fshots\u002Fbooking-slots-desktop-sm.webp",65,[134,110,135,48],"Docker","SQLite",{"slug":137,"title":138,"blurb":139,"variant":140,"palette":55,"layout":141,"count":57,"langs":142,"preview":145,"stack":161},"cli","CLI tools","Terminal programs: one binary, clear flags, an exit code you can check in a script.","film","terminal",[143,144],{"lang":110,"count":85},{"lang":113,"count":114},[146,151,156],{"slug":147,"title":148,"shot":149,"hue":150},"gitpulse","GitPulse: git repository analytics","\u002Fshots\u002Fgitpulse-desktop-sm.webp",7,{"slug":152,"title":153,"shot":154,"hue":155},"logslice","logslice: log analysis with no dependencies","\u002Fshots\u002Flogslice-desktop-sm.webp",160,{"slug":157,"title":158,"shot":159,"hue":160},"envguard","envguard: a linter and a safe for .env files","\u002Fshots\u002Fenvguard-desktop-sm.webp",35,[162,134,48,163],"CLI","stdlib only",{"slug":70,"title":71,"type":165,"category":51,"live_url":166,"stack":167,"description":172,"highlights":173,"run":178,"hue":73,"og":179,"shots":180,"case":187,"case_lang":5,"prev":210},"site","https:\u002F\u002Fewsirdev-docs.pages.dev",[168,169,170,171,77,48],"Node.js","JavaScript (ESM)","zero dependencies","Markdown","A static documentation site generator written from scratch in Node.js with no dependencies: its own Markdown parser, code highlighting and offline search. The demo site about a fictional library, Sverlo, is built from 43 pages in two languages (RU and EN) and two versions (v1 and v2). A side project.",[174,175,176,177],"Own Markdown parser, code highlighting and client-side search with no libraries","43 pages, RU and EN, versions v1 and v2, hreflang, sitemap and RSS","131 tests; broken links and anchors are checked in CI","The site reads without JavaScript, the search works offline","npm test && npm run build","\u002Fog\u002Fen\u002Fdocs-engine.jpg",{"desktop":181,"desktop_sm":72,"mobile":182,"dw":183,"dh":184,"mw":185,"mh":186},"\u002Fshots\u002Fdocs-engine-desktop.webp","\u002Fshots\u002Fdocs-engine-mobile.webp",1280,800,390,844,{"about":188,"features":191,"run":200,"notes":205},[189,190],"Sverlo (docs-engine) is a static documentation site generator in Node.js (ESM) with no dependencies, and the demo site it builds: documentation of a fictional log-analysis library. The library does not exist and the site is honestly marked as a demo; the generator is the real thing here. A side project.","Markdown is parsed by its own parser, code is highlighted by its own tokenizer, and the search index is built at build time and searched in the browser by the same file. The site reads fully without JavaScript: the script adds only search, the theme and copy buttons.",[192,193,194,195,196,197,198,199],"Markdown: headings with {#id}, nested lists and tasks, tables with alignment, code blocks, footnotes, ::: note callouts; front matter and include directives only from the site\u002Fincludes directory","Highlighting for js\u002Fts, json, bash, yaml, log, diff and http: tokens always join back into the source text","Documentation versions (v1, v2) and two languages (ru, en) with hreflang; the switchers keep the page when it has a pair","Client-side search with no libraries: an index built at build time, Russian and English stemming, prefixes, ranking, highlighting, works offline through a service worker","Navigation from the file tree, breadcrumbs, a table of contents, previous\u002Fnext; dark and light themes, RSS from the changelog","sitemap.xml with xhtml:link, robots.txt, llms.txt, security.txt, JSON-LD TechArticle and BreadcrumbList, canonical addresses","131 tests: the parser, highlighting (no lost characters), navigation, search, sanitizing (XSS payloads), golden page structure; CI checks broken links and anchors, hreflang and CSP safety","The live version is built with npm run build and deployed to Cloudflare Pages (direct upload of dist)",[201,202,203,204],"git clone \u003Crepository on request> docs-engine","cd docs-engine","npm test","npm run build   # dist\u002F with the static site",[206,207,208,209],"The content about Sverlo is fictional, the performance numbers in it are marked as targets.","Markdown has no indented code blocks, reference links or raw HTML. Highlighting is a regular-expression tokenizer without a grammar: nested template strings and regex literals can be inexact.","Stemming is heuristic, with no morphology or typo correction. The two languages and versions are set by directories, translation is manual and there is no automatic completeness check.","Node.js 22+ is required (checked on 24). The browser check (search, theme, language, axe) was done by hand over CDP and is not part of CI.",{"slug":65,"title":66},[212,217,222,227],{"slug":213,"lang":5,"title":214,"date":215,"summary":216,"project":129,"minutes":114},"double-booking","Double booking: a transaction plus a partial UNIQUE index","2026-10-20","How booking-slots protects against two clients booking the same time at once, and how that protection is tested.",{"slug":218,"lang":5,"title":219,"date":215,"summary":220,"project":221,"minutes":85},"lease-and-fencing","Lease and fencing: how a queue neither loses a job nor lets a zombie finish it twice","A worker can crash, stall, or wake up after its job was taken by someone else. How the lease and the lease token in job-queue deal with that on SQLite.","job-queue",{"slug":223,"lang":5,"title":224,"date":215,"summary":225,"project":226,"minutes":85},"p95-nearest-rank","p95 in an uptime monitor: the nearest-rank method and what it does not hide","How uptime-monitor computes p50\u002Fp95 latency and uptime, why the nearest-rank method was chosen, and where those numbers can mislead.","uptime-monitor",{"slug":228,"lang":5,"title":229,"date":215,"summary":230,"project":231,"minutes":85},"websocket-from-scratch","WebSocket on the standard library: what really happens under new WebSocket()","Why realtime-rooms has its own RFC 6455 layer, which protocol violations it checks, and why a library is still the better choice for production.","realtime-rooms",1792819120095]