[{"content":"For most of its life, GraphCompose could lay out text and structure very well, and draw very little. It produced invoices, reports, CVs, and proposals — documents that are mostly typography, spacing, and tables. That was the point. But real business documents are not only words. They have a revenue chart, a sparkline next to a KPI, a logo, a divider shape, a coloured panel with a soft gradient. Up to now, every one of those meant rasterizing an image somewhere else and pasting it in.\nThe 1.8 release — I called it illustrative — is about closing that gap. The engine can now draw, and it draws the same way it lays out text: declaratively, deterministically, and as native vector geometry rather than pasted pixels.\nThe banner at the top of this post is the honest version of that claim. It is not a design mockup. It is a GraphCompose page, rendered by the engine, then turned into a PNG. The bars carry real linear gradients, the little trend mark after \u0026ldquo;Native vector charts\u0026rdquo; is an inline sparkline, and the whole thing is the same code path any document uses.\nCharts should belong to the document The easy way to add charts to a PDF library is to depend on a charting toolkit, render a PNG, and drop the image on the page. It works, and it is wrong for this engine. A rasterized chart does not scale, does not match the document\u0026rsquo;s fonts and colours, and does not survive being measured and paginated like everything else.\nSo charts in 1.8 are part of the document model, not guests in it. You describe the data and the shape you want — a grouped bar chart, a line, a pie or donut — and the engine compiles that description, at layout time, into the primitives it already knows: shapes, lines, paragraphs. There is no chart-specific rendering code in the backend. A chart is measured, split, and placed by the same machinery as a paragraph, which means it is deterministic and testable by the same snapshot tests as the rest of the page.\nThat decision paid off in a way I did not fully expect. Because a chart is just primitives, the semantic export backend — which has no layout pass at all — can fall back to the chart\u0026rsquo;s underlying data table instead of failing. The chart degrades to its data, not to a broken page.\nSmooth, but honest about the data The part I am most quietly proud of is the smallest. A line chart can be drawn straight, or smoothed into a curve. The usual smoothing — a Catmull-Rom spline — looks lovely and lies a little: on a sharp swing it overshoots, bulging past the highest point in the data to a value that was never there. For a decorative chart, nobody cares. For a financial chart, that is a misrepresentation.\nSo 1.8 adds a monotone interpolation mode that stays just as smooth but is mathematically constrained never to leave the range of the points it connects. The curve cannot claim a number the data never had. It is one enum on the line spec, and it is the kind of detail that only matters to the small group of people it matters to a great deal.\nInline sparklines came along the same way: a mini trend silhouette that sits on a text baseline, next to a KPI or inside a CV line, smoothed with the same curve the charts use.\nImporting the design world The other half of illustrative is letting real artwork in. GraphCompose can now parse the practical subset of an SVG file — paths, basic shapes, grouped transforms, stroke and fill styling — and lower it into native PDF curves. An icon\u0026rsquo;s path data renders as actual Bézier geometry, smooth at any zoom, not a tessellated approximation. And gradients defined in that SVG — linear and radial, on fills and strokes — render as native PDF shadings with the exact endpoints, rather than collapsing to a flat colour.\nUnderneath all of it is one new idea: a vector path primitive, the open, curve-capable sibling of the polygon the charts already used. Smooth chart lines, decorative shapes you author by hand, and imported SVG icons all ride that single primitive. There is one source of truth for \u0026ldquo;a native curve on the page,\u0026rdquo; and everything that draws a curve goes through it. A new path-shaped clip outline lets a container mask its children to any silhouette — turn a logo into a content mask, fill and stroke along an arbitrary curve.\nI want to be precise about the status, because it is easy to oversell an SVG importer. The path importer is solid; the whole-file reader is marked beta while it hardens against the strange things real exporters emit. And some things are deliberately out of scope — SVG text, embedded images, filters, masks, clip paths. The reader does not try to render those badly; it drops them with a single warning that names exactly what it skipped and why. I would rather it fail loudly and tell you than produce a document that is subtly wrong. That instinct — that a document you cannot trust is worse than one that refuses — runs through the whole engine, and I wrote about why in Documents Are Backend Infrastructure.\nKeeping things together Not every feature in 1.8 is about drawing. The one I reach for most is keepTogether() — an opt-in flag that says \u0026ldquo;if this block does not fit in the space left on the page, move the whole thing to the next page instead of splitting it.\u0026rdquo; A chart card, a signature block, a small table with its heading: things that look broken when a page break lands in the middle of them.\nThis is the unglamorous heart of a document engine. Pagination is where templates that looked perfect with demo data fall apart on real data, and giving authors one clear, declarative way to say \u0026ldquo;do not break this here\u0026rdquo; removes a whole category of those failures. It is the same lesson I keep relearning: layout is product behaviour, not decoration. Lessons from Building a Java PDF Engine is the longer version of that story.\nA lighter download One change in 1.8 you will feel before you write a line of code: the bundled fonts moved out of the engine jar into their own independently-versioned artifact. The engine no longer ships several megabytes of typefaces you may not use. If you want the curated font set, you add one dependency; if you bring your own, you do not pay for theirs. The core document APIs stay source- and binary-compatible with 1.7, so the upgrade is the two consumption changes — the fonts split and a removed config loader — and nothing in your templates.\nThe principle underneath If there is a thread through all of this, it is restraint about the hot path. Charts, gradients, sparklines, imported icons, path clips — none of them added a new rendering handler to the engine. Every one compiles down to primitives that already existed, so the layout and render code that runs on every page did not grow. Documents that do not use a gradient produce byte-for-byte the same output they did before.\nThat is the trade-off I keep choosing: do the hard, clever work at composition time, where it happens once and can be tested, and keep the part that runs on every page boring. New things to draw, the same engine drawing them.\nThe release is on JitPack, and the changelog has the exhaustive list. But the short version is the banner: the documents can draw now, and they draw in vectors.\n","permalink":"https://demchaav.github.io/blog/posts/graphcompose-1-8-illustrative/","summary":"\u003cp\u003eFor most of its life, GraphCompose could lay out text and structure very well, and draw very little. It produced invoices, reports, CVs, and proposals — documents that are mostly typography, spacing, and tables. That was the point. But real business documents are not only words. They have a revenue chart, a sparkline next to a KPI, a logo, a divider shape, a coloured panel with a soft gradient. Up to now, every one of those meant rasterizing an image somewhere else and pasting it in.\u003c/p\u003e","title":"GraphCompose 1.8: Documents That Can Draw"},{"content":"Four names sit at the top right now: Google, xAI, OpenAI, and Anthropic. The list of companies shipping something is endless — Meta, DeepSeek, Qwen, and so on. But at the top, where the real competition happens, it\u0026rsquo;s these four. And they\u0026rsquo;re playing completely different games.\nFour players, four foundations Each of the four has its own strength — and that strength isn\u0026rsquo;t only the model.\nGoogle went its own way. They have Search behind them and the whole stack of services half the world already uses. They don\u0026rsquo;t need to convince you to come to their model — they bake it into the places you already live. Mail, search, docs, your phone. It\u0026rsquo;s a very strong play: the model doesn\u0026rsquo;t even have to be the best, because it\u0026rsquo;s everywhere.\nxAI is Musk. Grok is wired into Twitter, and that\u0026rsquo;s its strength: a live stream of data, an audience, reach. And behind Musk sits Tesla, SpaceX, a whole empire. He doesn\u0026rsquo;t want to give up, he\u0026rsquo;s getting his network in order, and in some ways it\u0026rsquo;s genuinely decent. Grok won\u0026rsquo;t disappear, because it\u0026rsquo;s part of something bigger.\nThen come the other two. OpenAI and Anthropic. And here\u0026rsquo;s the fundamental difference: they have no outside ecosystem to fall back on. They exist purely because they own their models. Everything is on the line. If Google\u0026rsquo;s or xAI\u0026rsquo;s model falls behind, they compensate with services, connections, other businesses — the company isn\u0026rsquo;t going anywhere. These two have nothing to hide behind. Everything they have is the model.\nSo this is a conversation about those two.\nHow it started I\u0026rsquo;ve been watching this since the first ChatGPT release.\nSam Altman did a public launch, I tried it — and I understood: this is a new chapter, this changes everything. The model was dumb, the answers wrong almost every time. But how it synthesized things was stunning. I was hooked. That\u0026rsquo;s the moment my close watching of all of this began — how it unfolds, who\u0026rsquo;s moving where.\nAt first nobody cared. Nobody understood why this mattered. Everyone thought: toy. Even my girlfriend said — okay, use it if you want. She wasn\u0026rsquo;t interested. But the start had been made. A year later people were talking about it. Then they started thinking about how to integrate it. And right around then, Anthropic showed up with its own model.\nMeanwhile ChatGPT was already being recognized, already being used, and word of mouth did the work. They made a splash and forced everyone to start building their own models — Google, Meta, xAI, DeepSeek, Qwen, an endless list.\nTwo teachers I used these models as a teacher. I could always ask until I got it, break things down piece by piece until they made sense, and get explanations back. That gave me a lot.\nAnd I had two teachers — very different ones.\nChatGPT was a talker. Ready to chat and explain a simple answer across two volumes — which wasn\u0026rsquo;t always what I needed, but plenty of people loved it for exactly that. I was coding, asking for advice. The answers were often wrong, but the syntax wasn\u0026rsquo;t bad, it gave you a foundation to understand from. The problem was that it was a kilometer-long roll of toilet paper. Sometimes it even ran 😅\nAnthropic was different from day one. I noticed it immediately — this wasn\u0026rsquo;t the talker. Ask how to do something, how to solve a task, and you get a structured answer. Everything cut into classes, separate methods, readable. And not working at all 😅\nAnd here\u0026rsquo;s the important part. It gave me a sense of how to write properly. Like an engineer — not like an author of giant slabs that work but that you can never touch again afterward. I peeked at how to structure things. The logic was sometimes broken, the information wrong — but the concept itself, the way of thinking, was valuable. I wasn\u0026rsquo;t learning the answer. I was learning to think.\nMeanwhile ChatGPT could hand me a correct answer — but as a slab, and built wrong from an engineering standpoint. But hey, it ran somehow 😅😅\n2026: who\u0026rsquo;s ahead, and why And now, in 2026, the picture has developed.\nOn coding, Anthropic holds the top. Their models sit at the top of SWE-bench, and the new flagship sets a new ceiling. Programmers choose Claude. Office workers choose Claude. Professionals don\u0026rsquo;t need a talker — they need an organized assistant. And Claude was that from the very first day.\nBut to be fair: this doesn\u0026rsquo;t mean OpenAI \u0026ldquo;lost.\u0026rdquo; Saying that would be untrue. On reasoning tasks, they\u0026rsquo;re ahead. Gemini wins on price and runs neck-and-neck on a number of benchmarks. What\u0026rsquo;s happening is specialization, not anyone\u0026rsquo;s knockout. One leads on code, another on logic, a third on cost. And smart developers in 2026 don\u0026rsquo;t pick one — they run several in parallel.\nAnd still, on my turf — engineering — Anthropic is ahead, and OpenAI can\u0026rsquo;t catch up yet. The benchmarks look fine, the model looks good, but it\u0026rsquo;s still the same talker underneath.\nMy bet: it\u0026rsquo;s about the data We know models get retrained — new layers, new techniques that improve results. But why does Anthropic pull this off more consistently? Here\u0026rsquo;s where my hypothesis begins.\nI think it\u0026rsquo;s because it was set up differently from the start. And that paid off. And the lion\u0026rsquo;s share of that \u0026ldquo;differently\u0026rdquo; is the data. How you train it, and what you want back. This was collected over years.\nAnd here\u0026rsquo;s the catch. OpenAI gathered its data for its approach to training. Anthropic for its own. Whatever new model comes out, the data will be the same — just topped up. A huge slab of it is already done. You\u0026rsquo;ll keep refining the architecture — but the model still learns on the old character. And you can\u0026rsquo;t dump all your datasets in the trash: that\u0026rsquo;s years and billions in cost. So you keep using them and wait for a miracle.\nAnthropic, meanwhile, will keep improving the architecture — and training on that same quality dataset, sharpened for engineering rigor from the start.\nI\u0026rsquo;ll be honest about where this can be challenged: technically, you can change a model\u0026rsquo;s behavior without throwing out the corpus — through RLHF, filtering, synthetic data. So \u0026ldquo;data decides everything\u0026rdquo; is too strong. But the inertia of a data culture doesn\u0026rsquo;t go anywhere. What you fed a model for years is what sets its character. And I don\u0026rsquo;t see what OpenAI needs to do to break that character. I think it could end badly for them.\nYes, these are my guesses. My thoughts. But still.\n","permalink":"https://demchaav.github.io/blog/posts/the-race-neural-nets/","summary":"\u003cp\u003eFour names sit at the top right now: Google, xAI, OpenAI, and Anthropic. The list of companies shipping \u003cem\u003esomething\u003c/em\u003e is endless — Meta, DeepSeek, Qwen, and so on. But at the top, where the real competition happens, it\u0026rsquo;s these four. And they\u0026rsquo;re playing completely different games.\u003c/p\u003e\n\u003ch2 id=\"four-players-four-foundations\"\u003eFour players, four foundations\u003c/h2\u003e\n\u003cp\u003eEach of the four has its own strength — and that strength isn\u0026rsquo;t only the model.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGoogle\u003c/strong\u003e went its own way. They have Search behind them and the whole stack of services half the world already uses. They don\u0026rsquo;t need to convince you to come to their model — they bake it into the places you already live. Mail, search, docs, your phone. It\u0026rsquo;s a very strong play: the model doesn\u0026rsquo;t even have to be the best, because it\u0026rsquo;s everywhere.\u003c/p\u003e","title":"The Race Where Two Players Have Nowhere to Retreat"},{"content":"Most backend systems eventually need to produce documents: invoices, reports, offers, letters, CVs, certificates, export packs. The business treats those documents as serious output. They are sent to customers, attached to applications, used by operations teams, and archived for compliance.\nThe code that produces them often does not get the same respect.\nThis is the companion to What Drove Me to Build GraphCompose — that post was the personal story of how GraphCompose started. This one is about a claim I now believe after living inside that code: document generation is backend infrastructure, and it pays off when you build it like infrastructure instead of like a one-off script.\nDocuments are not decoration A generated PDF is often the actual product of a flow, not a cosmetic detail. If it is wrong, the customer sees it, the application is rejected, or the compliance archive is incorrect.\nThat changes how the code should be treated. A document engine needs clear APIs, predictable output, versionable templates, and tests. It needs to be boring in the best way: understandable, repeatable, and safe to evolve. The moment a document is business-critical, the code that draws it is infrastructure, whether you planned it that way or not.\nThe usual failure mode PDF generation in Java can become a long sequence of coordinates, drawing calls, conditionals, and layout patches. A small content change breaks spacing. A new section disturbs pagination. A template looks fine in one data case and fails in another.\nTreated as a throwaway script, document code rots like any other untested path — except the breakage ships straight to a customer. The cost is hidden until the data stops being polite.\nWhen you actually need a document engine You do not always need one, and pretending otherwise is how libraries get overused. Be honest about the small cases:\nOne fixed PDF that rarely changes, with simple data: a direct PDFBox or iText script is fine. A single label, a receipt line, a one-off export: do not pull in an engine for it. You start needing a real engine when the problem stops being a single document and becomes a system of documents:\nthe same visual language repeats across several document types (CV, cover letter, invoice, proposal) the data is variable in size — one row or one hundred rows, a short name or a very long one templates change often and must stay reviewable by another developer the output is business-critical and must be testable, not just \u0026ldquo;looked right last time\u0026rdquo; you may need another output format later (PDF now, maybe DOCX or slides) without rewriting every template That is the line where ad-hoc drawing code stops scaling and infrastructure starts paying for itself.\nWhy declarative Backend developers already understand declarative ideas from SQL, Spring configuration, validation rules, and build files. You describe what should exist, and the engine handles the mechanics.\nGraphCompose applies that style to documents. Instead of making the template responsible for every drawing step, the template defines the document model and layout rules: sections, blocks, spacing, typography, hierarchy, and reusable components. The engine handles measurement, pagination, rendering, and repeatable behavior.\nThat separation matters because document templates change constantly. A declarative template is easier to review, easier to refactor, and easier to explain than a wall of coordinates. Rendering should still be precise, but precision should not require every template author to think in raw pixels.\nInfrastructure means testable A document engine only earns the word \u0026ldquo;infrastructure\u0026rdquo; if you can trust it under change.\nThat takes more than one shape of test: small checks for layout calculations, regression tests for document structure, rendered-output checks for visual behavior, and real templates that act as integration examples. The goal is not to test pixels for their own sake — it is to catch the kind of change that would make a business document look broken or untrustworthy. I wrote more about that engineering side in Lessons from Building a Java PDF Engine.\nThe trade-off I wanted Building a document engine is a good reminder that \u0026ldquo;simple API\u0026rdquo; does not mean \u0026ldquo;simple implementation.\u0026rdquo; Layout, pagination, typography, and rendering all contain edge cases, and the engine is where they have to be solved.\nThe work is worth it because every hard decision inside the engine removes complexity from application code. That is the trade-off I was after: keep the hard parts in one focused library, so product code can describe documents clearly and the rest of the backend can stop fighting coordinates.\nDocuments are infrastructure. It is easier to admit that early than to discover it the day a template breaks in production.\n","permalink":"https://demchaav.github.io/blog/posts/documents-are-backend-infrastructure/","summary":"\u003cp\u003eMost backend systems eventually need to produce documents: invoices, reports, offers, letters, CVs, certificates, export packs. The business treats those documents as serious output. They are sent to customers, attached to applications, used by operations teams, and archived for compliance.\u003c/p\u003e\n\u003cp\u003eThe code that produces them often does not get the same respect.\u003c/p\u003e\n\u003cp\u003eThis is the companion to \u003ca href=\"/blog/posts/what-drove-me-to-build-graphcompose/\"\u003eWhat Drove Me to Build GraphCompose\u003c/a\u003e — that post was the personal story of how GraphCompose started. This one is about a claim I now believe after living inside that code: document generation is backend infrastructure, and it pays off when you build it like infrastructure instead of like a one-off script.\u003c/p\u003e","title":"Document Generation Is Backend Infrastructure"},{"content":"I decided to create a personal blog because I often have thoughts that are too large for a quick note and too useful to leave only in my head.\nMy name is Artem Demchyshyn. I am a Ukrainian Java Backend Developer based in London. My work is mostly around backend systems, Java, Spring Boot, APIs, databases, product logic, and the practical engineering decisions that make software reliable.\nBut this blog is not only about code.\nOne of the things that has always fascinated me is how strong human beings are as creators.\nIn a relatively small period of history, people moved from primitive tools to machines, software, global networks, space technology, artificial intelligence, and systems that can reshape how we think and work. That difference is almost impossible not to admire.\nWhat amazes me even more is that people rarely stop at \u0026ldquo;good enough\u0026rdquo;. If something already works, someone will still try to improve it. Make it faster. Make it safer. Make it smaller. Make it easier to use. Make it more powerful. Make it available to more people.\nSometimes it feels like there is nothing left to invent.\nAnd then someone invents something anyway.\nThat constant human need to move forward is one of the reasons technology interests me so much. It is not only about devices, models, frameworks, or code. It is about the human instinct to take what already exists and ask:\nCan this be better?\nThat is also why I care about technology beyond software.\nI like following how phones evolve from one generation to the next: what operating systems change, what manufacturers choose to improve, how cameras, batteries, thermal design, displays, chips, and sensors become part of a bigger engineering story.\nI am interested in the architecture behind progress too: how RAM becomes faster and more efficient, how processors are designed, how chip architecture changes, how hardware and software start shaping each other, and why some design decisions matter more than the marketing headline.\nFor me, technology is not only an app or a backend service. It is the whole chain: hardware, operating systems, developer tools, infrastructure, AI models, product decisions, and the people who connect all of it into something useful.\nI want to write about programming, technology, technical ideas, and the inventions that are changing how we build things. I am especially interested in the rapid growth of AI systems: how they work, how they interact with people, how people should interact with them, and how we can build systems around them instead of just treating them as magic boxes.\nI care about understanding AI in a practical way:\nhow models behave how to structure prompts and workflows how to direct AI systems toward useful outcomes how to combine AI with real engineering work how to use AI without losing responsibility for the result I follow new model releases and industry news closely. I try to analyse what is happening, why it matters, what is hype, and what might become part of normal software development.\nI also build my own projects and use AI systems inside my workflow. Not as a replacement for engineering judgement, but as leverage: a way to move faster, explore more ideas, and create better products when the developer still understands the system.\nSo this blog will be a place for practical notes, project stories, technical reflections, and longer essays about the things I keep thinking about.\nSome posts will be about Java and backend architecture.\nSome will be about GraphCompose and document generation.\nSome will be about AI tools and how they change the way developers work.\nSome will be about phones, hardware, processors, memory, operating systems, and the engineering decisions behind modern devices.\nSome will simply be my attempt to take a large idea and explain it clearly.\nThat is the point of the blog: to write what I think, make the thinking visible, and share the ideas that feel worth developing in public.\n","permalink":"https://demchaav.github.io/blog/posts/why-i-started-this-blog/","summary":"\u003cp\u003eI decided to create a personal blog because I often have thoughts that are too large for a quick note and too useful to leave only in my head.\u003c/p\u003e\n\u003cp\u003eMy name is Artem Demchyshyn. I am a Ukrainian Java Backend Developer based in London. My work is mostly around backend systems, Java, Spring Boot, APIs, databases, product logic, and the practical engineering decisions that make software reliable.\u003c/p\u003e\n\u003cp\u003eBut this blog is not only about code.\u003c/p\u003e","title":"Why I Started This Blog"},{"content":"It started with a simple idea: I wanted to create my own CV in pure Java.\nNo big framework. No designer tool. No attempt to overengineer everything before I even had one page. Just Java, PDFBox, and the confidence every developer has right before a supposedly small task becomes a real project.\nAt first I thought: how hard can it be?\nVery quickly I found myself inside the classic PDF generation loop:\nwrite coordinates render the PDF open it notice that something is slightly wrong change the coordinates render again repeat until the document looks acceptable One block was too low. One line was too close to another. One section did not fit. One font change broke the page. The funny part was that nothing was technically wrong. PDFBox was doing exactly what I asked.\nThe problem was that I was asking in the wrong language.\nI was talking to the PDF like a machine:\n\u0026ldquo;Draw this text at x = 42, y = 713.\u0026rdquo;\nBut in my head I was thinking like a human:\n\u0026ldquo;I want the title at the top, centered, with a strong font. Then a divider. Then a section. Then some text. And if the content grows, move things properly.\u0026rdquo;\nThat gap became the beginning of GraphCompose.\nCoordinates Are Not Intent When we imagine a document, we do not imagine coordinates. Nobody thinks, \u0026ldquo;I want my professional summary at x 58 and y 492.\u0026rdquo; We think in hierarchy, structure, spacing, sections, emphasis, and meaning.\nThat was the first real insight: low-level PDF libraries think in drawing commands, but humans think in layout intent.\nThe document I wanted was not a list of coordinates. It was a structured object:\na header a section a paragraph a table a block that may move to the next page a visual system that should survive changes in data So GraphCompose did not start as \u0026ldquo;make PDFBox easier.\u0026rdquo; That would be too small. The deeper idea was this:\nWhat if Java developers could describe a document the way they actually see it?\nNot coordinates first. Structure first. Intent first. Then the engine can calculate the boring and fragile part.\nFrom PDF to Layout At the beginning, GraphCompose was close to the PDF world. That made sense because the first target was PDF output. But the more I worked on it, the more obvious it became that coordinates are not only a PDF problem.\nPDF has coordinates. Images have coordinates. SVG has coordinates. Slides have coordinates. Even UI rendering becomes coordinates at some point.\nSo the better question was not:\n\u0026ldquo;How do I draw this with PDFBox?\u0026rdquo;\nIt was:\n\u0026ldquo;How do I describe the document once, resolve its layout, and let a backend draw it?\u0026rdquo;\nThat changed the direction of the project. The engine should understand documents. The backend should understand drawing. PDFBox can draw PDF. Apache POI can write DOCX. A future backend could create slides, SVG, or images.\nDifferent output. Same resolved layout idea.\nThat separation is what made GraphCompose more interesting than \u0026ldquo;my CV generator.\u0026rdquo;\nThe ECS Phase Before the semantic DSL became the main public surface, I experimented with an ECS-style architecture. I still think that was a strong step for the engine internals.\nECS gives you a flexible way to model objects. You have entities as identities, and then you attach components: size, padding, margin, content, placement, render markers, parent relations, and children order. Systems process those components. One system measures, one lays out, one paginates, and one renders.\nThat structure is powerful because each part has a job. If you want a new property, you add a component. If you want new behavior, you teach a system how to work with that component. If you want a new primitive, you model it as an entity with the right set of components.\nFor example, if the engine already knows how to handle an atomic rectangle, adding a circle is not a completely new universe. The shape payload is different, but from the layout engine\u0026rsquo;s point of view both objects take space, can move to another page, and can be rendered by a handler.\nECS gave the project flexibility.\nBut it also exposed a problem: ECS is a good engine brain, not always a good public API.\nPart of the complexity was hidden from me because I already had the engine model in my head. I knew how containers worked, how components could be layered, how entities could be connected, and how the systems would process the tree. For me, that mental model was available before I wrote the API.\nFor another developer, that is not true. If someone has not been living inside the engine, they first need to understand the entity/component model, the container structure, the parent-child relationships, and the rendering pipeline before they can feel productive. That is a lot of preparation before writing one useful document.\nThere was also a lifecycle question. In the ECS version, the entity tree still had to be assembled for each generation run. The benchmarks showed that this was fast, so it was not a practical bottleneck at that stage. But it still meant repeated construction of the same kind of object graph.\nA more semantic approach can make more of the template structure stable: describe the document shape once, bind data for a specific render, resolve layout, and then draw the output. That does not automatically make everything faster, but it gives the engine a better path toward reuse, less repeated setup, and clearer optimization boundaries.\nMost developers do not want to build a CV by manually creating entities and attaching component sets. They want something closer to this:\ndocument.pageFlow(page -\u0026gt; page .module(\u0026#34;Professional Summary\u0026#34;, module -\u0026gt; module .paragraph(\u0026#34;Backend developer with Java and Spring Boot experience.\u0026#34;))); That difference matters. Engine internals can be technical. The public API should feel calm.\nThe Semantic DSL Shift The next step was moving GraphCompose toward a semantic document model.\nNot because ECS was wrong. ECS did its job. But I needed a higher-level layer because writing documents should feel like writing documents.\nA CV should have modules. A proposal should have sections. An invoice should have tables. A report should have paragraphs, images, dividers, and page breaks. Application code should describe semantic nodes, and the engine should compile them into layout fragments.\nThat became the shape of the architecture:\napplication code describes document intent the engine resolves layout and pagination the backend renders the final output Before that shift, the engine was closer to \u0026ldquo;objects on a page.\u0026rdquo; After the shift, it became closer to \u0026ldquo;document meaning that becomes objects on a page.\u0026rdquo;\nThat opened the door to stronger testing, reusable templates, theme-driven design, custom node definitions, multiple output backends, and safer internal refactoring.\nThe public side became simpler. The inside became more structured. That is usually a good sign.\nTemplates Made It Feel Like a Product Templates were another important step.\nAt first, templates can look like examples. But they are more than that. Templates are a stress test for the architecture. If every template turns into a long file full of duplicated header logic, spacing hacks, hardcoded colors, and one-off rendering decisions, then the engine is not helping enough.\nThat is exactly what I started to see in GraphCompose. In the beginning, I treated templates mostly as written code: build the template, show how the engine works, and let people reuse parts if they wanted to. That was useful for proving the idea, but it was not enough for a real user experience.\nThe classes became large. It was easy to imagine writing templates forever in the same style: repeat a header here, repeat a block there, copy some spacing logic, duplicate visual decisions, and slowly create a set of templates that all looked different on the surface but shared the same hidden mess underneath.\nFor a user who comes to the library with a specific task, that is not what they need. They do not want to read all the internal template code before they can create a CV or a business document. They usually need data, visual options, small configuration points, and maybe a controlled way to adjust existing components.\nThey should not have to touch the internal template implementation just to get a useful result.\nThat changed how I started thinking about templates. A template is not just an example. A template is closer to a product surface. If someone opens the library, chooses a CV template, and wants to create their own document, the ideal path should be simple: fill the data, choose the available options, and generate the output.\nThe user should not be forced into the code path where they can accidentally break layout internals while trying to change content.\nThe newer direction is cleaner:\ntheme tokens layout slots reusable components structured spec data That matters because a CV is not just \u0026ldquo;draw some text.\u0026rdquo; A CV becomes data + layout + theme + components. A cover letter can share the same visual language. An invoice or proposal can reuse the same design tokens.\nThat is when GraphCompose started to look less like a rendering experiment and more like a document generation platform.\nIt is still young. It is still not perfect. Some parts are still being cleaned. But the direction is much clearer.\nOpen Source Changed the View One of the useful moments came from the outside.\nA user found the library, got interested, and asked a simple question: why is there no Java 17 support?\nHe was right.\nI had been focused on layout, rendering, pagination, performance, tests, templates, and internal architecture. Those are important things. But from a user\u0026rsquo;s point of view, Java 17 support also matters because many real production Java stacks are still on Java 17.\nThat is where open source became valuable. A fresh view revealed an adoption problem I had not prioritized enough. Then @jottinger helped move the project toward Java 17 compatibility, refreshed dependencies, and improved the project\u0026rsquo;s practical usability.\nThat kind of contribution is not noise. It is exactly why open source is useful. Someone looking from the user side can see something obvious that the builder misses from inside the engine.\nThe Real Idea For me, the real idea of GraphCompose is simple:\nDocuments should be described like documents, not like manual drawing scripts.\nA developer should be able to say:\nI want a section I want a paragraph I want this table to repeat headers I want this block to move to the next page if needed I want this shape to contain content I want this output as PDF now, and maybe another backend later Coordinates are necessary, but they should be the engine\u0026rsquo;s problem. They should not be the developer\u0026rsquo;s problem every time a font size, paragraph length, or section order changes.\nThat is why I kept building GraphCompose.\nIt started because I wanted to make a CV. Then PDFBox made me fight coordinates. Then that frustration became architecture.\nNow the direction is clearer:\nDescribe intent. Resolve layout. Render anywhere.\nThat is the part I find exciting.\n","permalink":"https://demchaav.github.io/blog/posts/what-drove-me-to-build-graphcompose/","summary":"\u003cp\u003eIt started with a simple idea: I wanted to create my own CV in pure Java.\u003c/p\u003e\n\u003cp\u003eNo big framework. No designer tool. No attempt to overengineer everything before I even had one page. Just Java, PDFBox, and the confidence every developer has right before a supposedly small task becomes a real project.\u003c/p\u003e\n\u003cp\u003eAt first I thought: how hard can it be?\u003c/p\u003e\n\u003cp\u003eVery quickly I found myself inside the classic PDF generation loop:\u003c/p\u003e","title":"What Drove Me to Build GraphCompose"},{"content":"Building a PDF engine in Java is a useful way to meet a lot of hidden complexity at once. Text measurement, pagination, styling, rendering order, reusable components, API design, testing, and performance all become visible very quickly.\nThis is not a tutorial about drawing text into a PDF. It is a reflection on what I learned while building the layout engine behind GraphCompose: the hard part is rarely one isolated algorithm. The hard part is making many small rules work together until the final document feels reliable.\nLayout is product behavior It is tempting to treat layout as a visual detail. In document generation, layout is part of the product contract.\nIf a section moves to the wrong page, a heading separates from its content, or a table breaks in a confusing way, the output may still be a valid PDF, but it is not a good document.\nThat changed how I think about layout code. It needs explicit rules, good defaults, and tests around the cases users will actually hit. The engine is not only responsible for drawing. It is responsible for producing a document that a person can trust.\nLayered layout is where assumptions fail A template usually looks simple with perfect demo data. Real data is less polite.\nNames are longer than expected. Tables have one row or one hundred rows. Optional sections appear together. A paragraph that usually fits suddenly needs another page.\nPlain pagination is not the hardest version of the problem. If a document is basically flat, with one layer of blocks flowing from top to bottom, pagination is still work, but the model is understandable: measure, split, move overflow to the next page.\nThe harder case starts when the document has layers and dependencies. One layer may depend on another. A container may need to stretch because of its content. Another block may need to align with it. A visual background, border, sidebar, or overlay may need to resize together with the content. At that point, layout is not only \u0026ldquo;does this fit on the page?\u0026rdquo; It becomes \u0026ldquo;how do all these pieces change together and still land in the right pixels?\u0026rdquo;\nThat kind of layered layout forces the engine to answer questions that are easy to ignore:\nCan this block split? Should this heading stay with the next block? What happens when a section is larger than a page? How much spacing is preserved across a page break? Which layer owns the final size? What depends on what? When one element stretches, which other elements must be recomputed? Those decisions need to be designed, not patched after the fact. Otherwise every new template becomes another special case.\nSome problems are thinking problems I remember one specific moment when the engine already worked with containers. Blocks could flow, containers could relate to each other, and the basic layout model felt alive. The problem was not that pagination was impossible. If the document had been flat, I could have implemented page flow in a more direct way.\nThe difficult part appeared when positioning had to work across layered structures. One layer could depend on another layer. A container might stretch because of its children, while another visual element had to follow that new size. Several pieces had to resize, move, and still match each other precisely.\nThat is where I got stuck.\nThe code was not completely broken. The idea was not completely wrong. But I could not clearly see how the positioning model should work when size, position, layer order, and dependency rules all had to converge. I added logs, read the logs, changed the logs, and tried to analyze the flow. I also used AI tools to think through the problem, but they could not replace the missing mental model.\nFor a week, maybe a little more, I almost did not write code. I would sit at the computer, try to write something, and realize I did not know what the next correct line should be. Then I would step away, lie on the sofa, think about the problem, come back, stare at the code again, and repeat the same loop.\nThat is a strange part of building an engine: sometimes the work is happening, but it does not look like work. No commits. No new classes. No visible progress. Just the mental model slowly turning until it finally clicks.\nAt some point the shape of the solution became clear. I could see how the positioning should work, where the responsibility belonged, and how to simplify the problem instead of fighting every edge case separately.\nThen the work changed completely. Once the idea was clear, the code started to move. Line by line, the implementation began to take shape. The first run did not work everywhere, but it worked in the way I wanted. That first partial success mattered because it proved the pattern.\nAfter that, the task was no longer \u0026ldquo;what should this be?\u0026rdquo; It became \u0026ldquo;how do I shape this code until the pattern is reliable?\u0026rdquo;\nAPIs should express intent After spending enough time inside the engine, the API problem became clearer too. A user should not need to think in the same low-level mechanics that the engine uses internally.\nGood APIs do not hide every detail. They hide accidental complexity and expose meaningful choices.\nFor a document engine, that means template authors should not need to know every rendering primitive. But they should be able to express layout intent clearly: spacing, grouping, alignment, theme, and behavior around page breaks.\nWhen an API preserves intent, the generated document becomes easier to reason about. The code starts to say what the document is, not only how the PDF backend should draw it.\nTests need more than one shape Unit tests are useful, but they are not enough on their own. A layout engine can pass small calculations and still produce a document that looks wrong.\nFor a PDF engine, I want several kinds of confidence:\nSmall tests for layout calculations Regression tests for document structure Rendered output checks for visual behavior Real templates that act as integration examples The goal is not to test pixels for their own sake. The goal is to catch the kind of changes that would make a business document look broken or untrustworthy.\nPerformance work should stay boring When I was writing the engine, performance was not the first goal. The first goal was simpler and more urgent: make it work. Make it render the document. Make the layout rules actually produce the result they were supposed to produce.\nI wrote some parts as quickly as I could because I was trying to keep the whole model in my head. Sometimes I could see that a class or a method repeated something from an earlier version. Sometimes I knew that a calculation would probably be done more than once. But stopping too early to make everything elegant would have broken the thread. In that phase, momentum mattered.\nThat does not mean performance was ignored. It means the work had phases. First, get the engine to do the job. Then come back to the places where the cost is visible and the behavior is already understood.\nBy the end of that phase, I had a much clearer idea of where the waste was. I knew which parts had repeated calculations, where layout data could be reused, and which areas would need optimization later.\nMost useful performance work then starts with simple questions:\nAre we measuring the same text repeatedly? Are we allocating too much inside hot paths? Can layout data be reused safely? Is the algorithm doing work proportional to the document size? In Java, boring performance work is often the right performance work: measure first, remove obvious repetition, cache only when the rules are clear, and keep the data structures understandable.\nThe main lesson A PDF engine looks like a rendering problem from the outside. From the inside, it is an API design problem, a layout problem, a testing problem, a performance problem, and a product reliability problem.\nThat is why it is interesting. The output is only one PDF file, but behind that file there is a chain of decisions about structure, intent, constraints, and trust.\n","permalink":"https://demchaav.github.io/blog/posts/lessons-from-building-a-java-pdf-engine/","summary":"\u003cp\u003eBuilding a PDF engine in Java is a useful way to meet a lot of hidden complexity at once. Text measurement, pagination, styling, rendering order, reusable components, API design, testing, and performance all become visible very quickly.\u003c/p\u003e\n\u003cp\u003eThis is not a tutorial about drawing text into a PDF. It is a reflection on what I learned while building the layout engine behind GraphCompose: the hard part is rarely one isolated algorithm. The hard part is making many small rules work together until the final document feels reliable.\u003c/p\u003e","title":"Lessons from Building a Java PDF Engine"},{"content":"AI tools make some developers uncomfortable because they blur a familiar line. If a tool can suggest code, explain an API, draft a test, or refactor a function, does using it mean the developer is cheating?\nI do not think so.\nBut I also do not think AI removes responsibility from the developer.\nTools have always changed the work Modern development is already tool-assisted. We use IDE completion, static analysis, linters, formatters, frameworks, dependency managers, documentation search, and generated code.\nAI is different in shape, but not in the basic idea: a tool helps us move faster through part of the work.\nThe important question is not \u0026ldquo;did a tool help?\u0026rdquo; The important question is \u0026ldquo;do you understand, own, and verify the result?\u0026rdquo;\nWhere AI helps AI is useful when it reduces friction:\nExploring an unfamiliar codebase Drafting a first version of documentation Turning a rough idea into a concrete checklist Explaining an error message Generating test cases to review Comparing implementation options Finding edge cases I may have missed In those cases, AI acts like a fast thinking partner. It does not replace judgment, but it can make the path to judgment shorter.\nWhere AI is risky AI becomes dangerous when it creates confidence without understanding.\nThat can happen when a developer accepts code without reading it, trusts invented facts, skips tests, or lets the tool choose architecture without checking the trade-offs.\nThe risk is not that AI writes code. The risk is that the developer stops being the engineer responsible for the system.\nMy rule If I use AI, I still need to be able to explain the change.\nI need to know what files changed, why the approach fits the codebase, what assumptions were made, and how I verified the result. If I cannot explain it, I have more work to do.\nThat rule keeps AI in the right place: useful, fast, and secondary to engineering responsibility.\nThe career angle For backend developers, AI is not a shortcut around fundamentals. It makes fundamentals more important.\nIf I understand Java, Spring Boot, SQL, security, APIs, and system design, AI can help me move faster. If I do not understand those things, AI can help me produce code that looks convincing but fails under real review.\nThe value is still in engineering judgment.\nAI is not cheating. Pretending to understand what you shipped is.\n","permalink":"https://demchaav.github.io/blog/posts/ai-as-a-developer-tool-not-cheating/","summary":"\u003cp\u003eAI tools make some developers uncomfortable because they blur a familiar line. If a tool can suggest code, explain an API, draft a test, or refactor a function, does using it mean the developer is cheating?\u003c/p\u003e\n\u003cp\u003eI do not think so.\u003c/p\u003e\n\u003cp\u003eBut I also do not think AI removes responsibility from the developer.\u003c/p\u003e\n\u003ch2 id=\"tools-have-always-changed-the-work\"\u003eTools have always changed the work\u003c/h2\u003e\n\u003cp\u003eModern development is already tool-assisted. We use IDE completion, static analysis, linters, formatters, frameworks, dependency managers, documentation search, and generated code.\u003c/p\u003e","title":"AI as a Developer Tool, Not Cheating"},{"content":"On June 9, 2026, Anthropic announced Claude Fable 5, a Mythos-class model made available for broader use with stricter safety layers around it. On June 12, Anthropic added an update saying that access to Claude Fable 5 and Claude Mythos 5 was temporarily unavailable while they worked to restore it.\nThat timeline is already interesting.\nFrontier AI releases are starting to look less like simple product launches and more like controlled deployment systems: a powerful model, safety routing, monitoring, fallback behavior, access policy, pricing, and operational risk all wrapped together.\nI only tested Fable 5 briefly, so this is not a deep review. But my first impression was strong. The model felt thoughtful, capable, and very good at holding context. In some complex tasks, it felt stronger than Opus.\nWhat interested me most, though, was not only the raw intelligence.\nSafety as part of the architecture Some responses felt like they were passing through an extra safety process: deeper thinking, a pause, and then a final answer that sometimes appeared in chunks rather than as one smooth token stream.\nThat is only an observation from usage, not proof of how the system works internally. But it made me think about the shape of the product.\nFable 5 does not feel like a model with a simple input/output filter on top. It feels more like a layered system:\ndetection safety gates possible rewriting or routing fallback behavior for sensitive requests logging and retention policies pricing as another form of access control That is important because it changes how developers should think about AI systems.\nThe model is not just a model. It is a model inside a deployment architecture.\nThe pricing question The pricing is also worth watching.\nFor everyday prompts, a more expensive frontier model may not be worth it. If the task is simple, the best model is not always the most powerful one. It may be the model that gives a good enough answer quickly, cheaply, and predictably.\nFor complex reasoning, coding, long-context work, or difficult analysis, the calculation changes. The question is not only:\nIs it smarter?\nThe better question is:\nDoes it solve hard tasks in fewer iterations?\nIf a model costs more per token but reduces the number of failed attempts, rewrites, retries, and human correction loops, it can still be useful. But that needs to be measured in real workflows, not only felt in a few impressive prompts.\nMore power, more control Fable 5 feels like a glimpse of where frontier AI access may be going.\nMore powerful models will not simply be released as unrestricted APIs. They will likely come with stronger safety layers, stricter access policies, more monitoring, higher prices, and sometimes behavior that is intentionally less transparent to the user.\nThat is both exciting and uncomfortable.\nExciting, because these systems are becoming genuinely useful for hard work.\nUncomfortable, because developers building on top of them need to understand that the model may not behave like a stable deterministic service. It may route, refuse, rewrite, downgrade, slow down, or become unavailable because the deployment layer decides that the request crosses a boundary.\nFor AI products, that means we need better thinking around:\nfallback models observability evaluation cost control user communication trust when the model\u0026rsquo;s behavior changes The real signal The most interesting part of Fable 5 is not only that the model appears stronger.\nThe real signal is that frontier AI is becoming a full system around the model. Capability is only one layer. Safety, access, policy, infrastructure, and economics are becoming part of the product itself.\nThat is probably where the next phase of AI will be decided.\nThis note started as a short LinkedIn post after my first tests with Fable 5. The broader context is Anthropic\u0026rsquo;s announcement and the later access update.\nSources: my LinkedIn note and Anthropic\u0026rsquo;s Claude Fable 5 / Mythos 5 announcement.\n","permalink":"https://demchaav.github.io/blog/posts/claude-fable-5-and-the-shape-of-frontier-ai-access/","summary":"\u003cp\u003eOn June 9, 2026, Anthropic announced Claude Fable 5, a Mythos-class model made available for broader use with stricter safety layers around it. On June 12, Anthropic added an update saying that access to Claude Fable 5 and Claude Mythos 5 was temporarily unavailable while they worked to restore it.\u003c/p\u003e\n\u003cp\u003eThat timeline is already interesting.\u003c/p\u003e\n\u003cp\u003eFrontier AI releases are starting to look less like simple product launches and more like controlled deployment systems: a powerful model, safety routing, monitoring, fallback behavior, access policy, pricing, and operational risk all wrapped together.\u003c/p\u003e","title":"Claude Fable 5 and the Shape of Frontier AI Access"},{"content":"I am Artem Demchyshyn, a Ukrainian Java Backend Developer based in London.\nI work with Java, Spring Boot, REST APIs, SQL, JPA/Hibernate, Spring Security, Docker, and Flyway. I care about backend systems that are secure, practical, easy to reason about, and useful beyond the demo.\nMy main open-source project is GraphCompose, a declarative PDF and document layout engine for Java and Kotlin. It grew out of a simple frustration: document generation should be treated like real product code, not as a pile of fragile drawing instructions.\nI also built CVRewriter, an AI-powered resume tailoring platform with a Spring Boot backend, JWT authentication, PDF generation, AI orchestration, profile-based CV management, and application tracking. It is a product-shaped backend project, not just an AI wrapper.\nMost of my attention now goes to AI systems: how they work, how to structure them, and how to build useful workflows around them without losing engineering responsibility for the result. I follow new model releases and industry shifts closely — not for the hype, but to understand what actually changes in real development work. I also pay attention to the hardware side of progress: phones, processors, memory, and the design choices behind each generation of devices.\nThis blog is where I write about:\nJava and Spring Boot backend engineering PDF and document generation with GraphCompose AI systems, developer tools, and human-AI workflows Hardware progress: phones, processors, memory, and operating systems Open-source design decisions and my own projects Career notes from building toward stronger backend/product work in the UK Some posts are practical engineering notes; others are longer thoughts on technology, AI, or architecture. The goal is simple: write honestly, make the trade-offs visible, and publish the ideas that are too large to leave only in my notes.\nYou can find my work on GitHub and LinkedIn.\n","permalink":"https://demchaav.github.io/blog/about/","summary":"\u003cp\u003eI am Artem Demchyshyn, a Ukrainian Java Backend Developer based in London.\u003c/p\u003e\n\u003cp\u003eI work with Java, Spring Boot, REST APIs, SQL, JPA/Hibernate, Spring Security, Docker, and Flyway. I care about backend systems that are secure, practical, easy to reason about, and useful beyond the demo.\u003c/p\u003e\n\u003cp\u003eMy main open-source project is \u003ca href=\"https://github.com/DemchaAV/GraphCompose\"\u003e\u003cstrong\u003eGraphCompose\u003c/strong\u003e\u003c/a\u003e, a declarative PDF and document layout engine for Java and Kotlin. It grew out of a simple frustration: document generation should be treated like real product code, not as a pile of fragile drawing instructions.\u003c/p\u003e","title":"About"}]